🪐 terraforming cloud run with a placeholder image

why terraform needs a placeholder image before ci runs

tl;dr

google_cloud_run_v2_service needs a real, pullable image to create its first revision, but on a brand new environment nothing has ever been pushed to Artifact Registry yet. I point it at Google's own placeholder and let CI take over after the fact.

the problem

Same chicken-and-egg problem as bootstrapping a GCP backend, but on a different resource. Cloud Run's API validates that the image you're deploying actually exists, and it cannot create a Cloud Runrevision against nothing.

The issue is that that image only exists once Cloud Build has run at least once, and Cloud Build only runs on a git push (or a manual trigger). terraform apply doesn't push our app code for us, and neither should it. Creating a google_cloudbuild_trigger resource just registers a webhook, it doesn't execute a build. So on a from-scratch environment where Registry, Build, and Run are all brand new, the Artifact Registry repo Terraform creates is empty, and there's nothing valid to reference.

the solution

Point at a container that always exists: Google's own placeholder

containers {
  image = "gcr.io/cloudrun/placeholder"
}

lifecycle {
  ignore_changes = [template[0].containers[0].image]
}

From here, CI does the rest.

flowchart LR
  A["push to main"] --> B["Developer Connect trigger fires"]
  B --> C["Cloud Build builds and pushes<br/>image tagged $COMMIT_SHA"]
  C --> D["cloudbuild.yml invokes Run to create a new revision"]

Terraform's state will always think the image is the placeholder, but ignore_changes means it never checks that field again, so it never fights CI for control of it. Think of it as permanent, deliberate drift on one field.