Importing a hand-built cloud into Terraform without breaking it
Every young cloud starts by hand. Someone clicks a cluster into existence at two in the morning, a service account gets created to unblock a demo, and a year later nobody knows which of the dozens of build triggers still matter. Picture inheriting that as the platform engineer on a product team: the product cannot afford downtime, and you cannot afford to keep operating by memory.
The rule: import, never recreate
The tempting move is to write clean Terraform and stand up a fresh environment next to the old one. It is also how you end up running two clouds for six months. The slower-looking path works: describe what already exists, import it, and only then change anything.
The tool that made this safe was a zero-diff gate. A resource is only considered “under code” when terraform plan shows no changes for it. Until then it is a draft. Import the estate in slices: networking first, then the clusters and node pools, then serverless services, load balancers, key rings, and finally the build triggers and service accounts that accumulated over the years.
What “zero downtime” actually required
Most of the time, nothing changed. That is the point. The dangerous cases were the ones where the provider’s defaults disagreed with what a human had clicked: a node pool with a surge setting nobody remembered, a service with a hidden revision annotation. Each of those is a place where a naive apply would replace the resource. Reading the plan for forces replacement became a reflex.
Where it landed
A few hundred resources across several environments, all in code. New environments are a variables file. GPU node pools scale to zero when idle, which is where a good part of the cost savings came from, and every change goes through a plan someone can read. The hand-built cloud is still there. It just has a description now.