Terraform vs CI/CD for Serverless Deployments

I passed the Terraform certification some month ago. While learning terraform, I quickly found myself willing to provision all I can through terraform. Turned out a bad idea. Here is why.

Do you use Terraform for deploying helm charts ?

Terraform vs CI/CD for Serverless Deployments

1. The confusion between infra and app lifecycle

Infrastructure lifecycle and application lifecycle differ

Infrastructure change slowly whereas application releases can appear multiple times a day. For instance, while you are satisfied with your network configuration, you will not change it much at during next year. On the other hand, if your release of this morning for your application has broken some feature despite all the tests you have put in place, you want to rollback to the previous version quickly.

Therefore the changes you make to application have to be released much more frequently than pure infrastructure. You cannot handle both in the same place.

2. What Terraform is GREAT at

Terraform is an open source Infrastructure As Code open source tool created by Hashicorp. It allows to define your infrastructure, provision and manage it. It has seen a huge adoption in the industry though the years. It allows you to automated deployment for different providers, namely the cloud ones like AWS, Azure, GCP but also other PaaS like Heroku or even github or gitlab. Today many tools have their Terraform provider to allow you to declare your configuration in files and communicate with their apis.

The 1 M$ question really is what do I put in Terraform ?

Terraform shines at defining your desired state in terms of configuration for the following:

  • networking
  • IAM
  • buckets
  • SQL data base
  • secrets
  • DNS
  • load balancer

These infrastructure components define the core of your systems. Once they are setup, you rarely update them.

3. Why application deployment is different

Over the past few years, the tech industry has become significantly more competitive. And this shift has only accelerated with the arrival of AI-powered coding assistants.

Today, development velocity is no longer a nice-to-have — it is a core requirement. Feature teams can no longer afford to wait weeks or even a full month to deliver new functionality. In many organizations, it is now common to ship multiple features per week, and in some cases, even multiple times per day.

This level of speed requires a fundamental change in how software is delivered. Promoting application images across environments must be fast, reliable, and fully automated in order to support rapid testing and release cycles. Equally important is the ability to roll back just as quickly when something goes wrong.

In this model, deployment is no longer just about pushing changes to production — it is about enabling continuous, safe, and reversible delivery at high velocity.

4. The Cloud Run example

Let us take as a backbone example the serverless platform in Google Cloud named Cloud Run. This is a container as a service platform which can run at scale.

We are going to compare the workflows to deploy an application through Terraform vs through Continuous Deployment leveraging github actions.

💡All material found in this article can be found in my repository at https://github.com/Redcart/serverless-deployment.

🛠 Terraform example

In the following piece of Terraform configuration, we are defining our cloud run service. Once you are satisfied with this configuration, you just need to run terraform apply.

But now, if you need to promote a new version of your app ? You first need to build and push the new docker image of your code in Artifact Registry. Second you have to pick up the righ name and change it in the variable named below container_image. Eventually run terraform apply.

resource "google_cloud_run_v2_service" "cloud-run-service" {
name = var.cloud_run_service_name
location = var.region
ingress = "INGRESS_TRAFFIC_INTERNAL_LOAD_BALANCER"
deletion_protection = false
template {

service_account = var.sa_cloud_run

containers {
image = var.container_image

env {
name = "GCP_PROJECT_ID"
value = var.project_id
}

env {
name = "INPUT_DATASET"
value = var.input_dataset
}

env {
name = "OUTPUT_DATASET"
value = var.output_dataset
}

env {
name = "API_KEY"

value_source {
secret_key_ref {
secret = var.api_key_secret_name
version = var.api_key_secret_version
}
}
}
}
}
}

🛠 CI/CD in github actions example

In the following piece of configuration code, we are deploying through gcloud CLI in github actions a cloud run service.

If we want to deploy a new version of the app, we just have to commit and push the change in the github remote repository, Then the CI/CD will be triggered, the docker image built and pushed to Artifact Registry, the cloud run service automatically updated with this new docker image. All in one step, from one single repository.

IMAGE=${{ env.GCP_REGION }}-docker.pkg.dev/${{ env.GCP_PROJECT_ID }}/cloud-run/app:${{ github.sha }}
gcloud run deploy ${{ env.PROJECT }}
--image=$IMAGE
--region=${{ env.GCP_REGION }}
--platform=managed
--memory=1Gi
--no-allow-unauthenticated
--ingress=internal-and-cloud-load-balancing
--service-account=${{ env.SERVICE_ACCOUNT_RUNTIME }}
--set-env-vars GCP_PROJECT_ID=${{ env.GCP_PROJECT_ID }}
--set-env-vars INPUT_DATASET=${{ env.INPUT_DATASET }}
--set-env-vars OUTPUT_DATASET=${{ env.OUTPUT_DATASET }}
--set-secrets API_KEY=API_KEY:latest

5. Terraform pain points for deployments

While we have seen in the previous section that deploying a cloud run service through terraform can be easy, it has some limitations.

First, as discussed earlier, it mixes infra and app concerns. In some teams, people in charge of infra and app are not the same. You can encounter lack of velocity especially if you need to quickly rollback because of a pending apply (a colleague has done a plan but has not confirmed the apply yet). You can ran into state locking, drift is more likely to happen and interfer with the behavior of your app in production. The plan of such terraform workspaces can become very noisy and take a while.

📌 To overcome some of these limitations, one may tempted to say ok, I will have more terraform workspaces to not be bothered by other pending apply or long plan. But here again, do not underestimate the complexity and challenge to maintain a bunch of workspaces.

6. A pragmatic split

👨‍💻After a couple years of experience, I ran into the conclusion that infrastructure should be handled by an IaC tool like terraform and application releases by Continuous Deployment Pipeline like github actions.

This has several advantages. Different teams can handle infra vs application effortlessly as you put them in different repositories. It is easy to find which application version is currently deployed in production. You can release in the environment you want from the application repository in one single step. You can handle secrets without risking to put them in files (even if terraform state files are encrypted). Rollback is really straightforward.

In a nutshell,

Terraform is an infrastructure tool not a deployment tool.


Terraform vs CI/CD for Serverless Deployments was originally published in Towards AI on Medium, where people are continuing the conversation by highlighting and responding to this story.

Liked Liked