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¶
- A built image, or at least a Dockerfile in the service folder. See Write a Dockerfile for your service.
- Terraform familiarity: providers, variables, resources.
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.
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.
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:
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¶
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:
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>.