Configuring Cloud-Native Applications for Deployment
The container contract
A deployable container must listen on the port the platform provides (Cloud Run injects PORT, defaulting to 8080), bind to 0.0.0.0 rather than localhost, write logs to stdout/stderr, keep the filesystem ephemeral, and handle SIGTERM by finishing in-flight requests before exit. Images must match the platform architecture, typically linux/amd64; build multi-arch or specify --platform if you develop on ARM. Distroless or slim base images reduce attack surface and cold-start time.
Deploying to Cloud Run
Each deployment creates an immutable revision you can route traffic to. Key flags: --service-account, --allow-unauthenticated versus default IAM invocation, --ingress (all, internal, internal-and-cloud-load-balancing), --min-instances, --max-instances, --concurrency, --cpu-boost for startup, and --no-cpu-throttling when CPU must stay allocated outside requests. Traffic splitting targets revisions by percentage and must total 100; tags give a revision a stable URL without production traffic, which is how you canary or smoke test.
Deploying to GKE
Manifests declare resource requests and limits, liveness, readiness, and startup probes, PodDisruptionBudgets, and topology spread across zones. Configure Workload Identity so pods get GCP credentials without key files, and mount secrets from Secret Manager or Kubernetes Secrets.
Traps
A service that hardcodes port 8080 works in one environment and fails where PORT differs. A background thread dies silently because Cloud Run throttles CPU outside requests - use an always-allocated CPU worker or Cloud Run jobs. --allow-unauthenticated makes a service world-invokable; questions about unexpected public access usually trace back to it.
Rule of thumb: read configuration from environment variables injected at deploy time, never baked into the image, and keep one image promoted across environments.