Skip to content

Write infrastructure with Terraform

Describe a service's cloud resources in its infra/ folder so that Deploy can apply them into each deployment environment. Deploy runs Terraform with the platform's state backend and injects variables that identify the deployment environment, the product and the version being deployed.

Prerequisites

Set up the module

Create infra/main.tf with the Google provider and a placeholder backend. The bucket and prefix are supplied at deploy time; leave the placeholder strings as they are.

infra/main.tf
terraform {
  required_providers {
    google = {
      source  = "hashicorp/google"
      version = ">= 6.0.0"
    }
  }
  backend "gcs" {
    bucket = "provided_at_runtime_by_alis"
    prefix = "provided_at_runtime_by_alis"
  }
}

provider "google" {
  project = var.ALIS_OS_PROJECT
}

Declare the variables you use

Deploy injects a fixed set of ALIS_* variables. Declare the ones your module reads; you do not have to declare them all.

infra/variables.tf
variable "ALIS_OS_PROJECT" {}                   # the environment's Google Cloud project id
variable "ALIS_OS_PRODUCT_PROJECT" {}           # the product's project, which hosts the image registry
variable "ALIS_OS_NEURON" {}                    # the service id, e.g. orders-v1
variable "ALIS_OS_NEURON_VERSION_COMMIT_SHA" {} # the built commit, used as the image tag
variable "ALIS_REGION" {}                       # the environment's region
variable "ALIS_PRODUCT_REGION" {}               # the product's region

Environment variables you set on the deployment environment (see Manage environment variables) arrive as Terraform input variables of the same name. Declare those too:

HCL
variable "API_URL" {}

A variable stored in Secret Manager is left out of the deploy; read it from the secret named after it in the deployment environment's project, for example with data "google_secret_manager_secret_version".

Deploy a Cloud Run service

infra/cloudrun.tf
resource "google_project_service" "run" {
  service            = "run.googleapis.com"
  disable_on_destroy = false
}

resource "google_cloud_run_v2_service" "service" {
  name                = var.ALIS_OS_NEURON
  location            = var.ALIS_REGION
  deletion_protection = false

  template {
    scaling { max_instance_count = 10 }
    containers {
      image = "${var.ALIS_PRODUCT_REGION}-docker.pkg.dev/${var.ALIS_OS_PRODUCT_PROJECT}/neurons/${var.ALIS_OS_NEURON}:${var.ALIS_OS_NEURON_VERSION_COMMIT_SHA}"
      ports {
        name           = "h2c" # gRPC needs end-to-end HTTP/2; omit for plain HTTP
        container_port = 8080
      }
      env {
        name  = "ALIS_OS_PROJECT"
        value = var.ALIS_OS_PROJECT
      }
      env {
        name  = "ALIS_REGION"
        value = var.ALIS_REGION
      }
      resources {
        limits   = { cpu = "1000m", memory = "512Mi" }
        cpu_idle = true
      }
    }
    service_account = "alis-build@${var.ALIS_OS_PROJECT}.iam.gserviceaccount.com"
  }

  traffic {
    type    = "TRAFFIC_TARGET_ALLOCATION_TYPE_LATEST"
    percent = 100
  }
}

The image tag is the commit the version was built from, so each deploy pins exactly one build. Pass the values your code needs at run time as container env blocks; Terraform variables are not visible to the running container by themselves.

Preview before you apply

Whenever infra/*.tf changed, plan first:

alis deploy acme.sh.orders.v1 -e <env-id> --plan-only

A plan changes nothing and is never gated. When only infrastructure changed and the code did not, skip a rebuild with alis build acme.sh.orders.v1 --retag --deploy -e <env-id>.