Skip to content
  • 10 cloud providers
  • 51 configurations
  • Competitive pricing
  • Developer friendly

Infrastructure as code: a starting point that does not overwhelm

You do not need to define your entire estate in code to get most of the benefit. Start with the parts that would be painful to recreate, and grow from there.

Abstract illustration accompanying this guide on infrastructure as code

Infrastructure as code is usually presented as an all-or-nothing transformation, which makes it easy to postpone indefinitely. The realistic version is incremental: define the pieces that would hurt most to lose, and expand only when there is a reason.

What it actually buys you

Reproducibility. The environment can be rebuilt from a definition rather than from someone’s memory. This is the benefit that matters most and the one that justifies the effort on its own.

A review point. Infrastructure changes go through the same discussion as code changes, which catches mistakes before they reach production rather than after.

A history. When something changed and why is answerable. “It has always been like that” stops being the answer.

Consistent environments. Staging genuinely resembles production because both come from the same definition with different variables, rather than having drifted apart over two years.

Documentation that cannot go stale, because it is the thing that creates the infrastructure.

Where to start

Not with everything. Start with what would be painful to recreate under pressure.

First: networking. Address ranges, subnets, firewall rules and routing. This is the layer that is most tedious to rebuild by hand, easiest to get subtly wrong, and least likely to change frequently. It is also the layer where a mistake has the widest consequences, so a review point is valuable.

Second: compute. Instances, their sizes, their images, their attached storage, their group memberships.

Third: the supporting services. Load balancers, managed databases, object storage buckets, DNS records.

Later, or never: things that change constantly or are genuinely one-off. Not everything benefits from being codified, and forcing it produces definitions nobody maintains.

Handling what already exists

Most people are not starting empty, and the existing infrastructure is the reason the project keeps getting postponed.

Three viable approaches.

Import it. Most tools can bring existing resources under management by importing their current state. Tedious for a large estate, and it gets you to a codified representation of what actually exists.

Codify new work only. Leave existing infrastructure alone and define everything new in code. The estate becomes gradually more codified without a migration project. This is the pragmatic default.

Rebuild in parallel. Define the environment in code, stand it up alongside, verify, cut over. Cleanest result, largest effort, and only sensible for something small or something you were going to rebuild anyway.

State, which is the thing that bites

Most tools keep a state file recording what they have created. It is the link between your definitions and reality, and mishandling it causes the worst problems in this area.

Three rules.

Store it remotely, in object storage or a managed backend, not on someone’s laptop. A state file that exists in one place, on one machine, is a single point of failure for your ability to manage the infrastructure.

Enable locking, so two people applying changes simultaneously cannot corrupt it.

Treat it as sensitive. State files frequently contain secrets in plain text: generated passwords, connection strings, keys. Encrypt the backend and restrict access to it as you would to production credentials.

Losing the state file does not destroy your infrastructure, but it does mean the tool no longer knows what it manages, and reconciling that by hand is genuinely unpleasant.

Keep it readable

The most common way these projects fail is not technical. The definitions become so abstracted that nobody can tell what they create, at which point people stop using them.

Prefer clarity to cleverness. A little repetition between two environments is better than an abstraction that requires study.

Separate environments properly, with their own state, so that applying a change to staging cannot touch production. This boundary is worth more than any amount of shared module design.

Modularise only after repeating yourself three times. Premature modules encode assumptions that turn out to be wrong.

Pin versions of the tool and its providers, so a change to your infrastructure is something you initiated rather than something that arrived.

Making it stick

A definition that people bypass is worse than none, because it is now misleading.

Make the codified path easier than the console. If applying a change through the pipeline takes twenty minutes and clicking takes two, people will click.

Detect drift. Run a plan on a schedule and alert when reality differs from the definition. Drift is inevitable; unnoticed drift is what makes the definitions untrustworthy.

Allow emergency console changes, and require them to be codified afterwards. A policy that forbids urgent manual fixes will be broken during the first incident and then ignored generally.

A realistic first week

Define the network for one non-production environment. Store the state remotely with locking. Destroy the environment and recreate it from the definition, which is the test that proves it works. Then define the compute for the same environment and do it again.

At that point you have a working pattern, a state backend, and the confidence to apply it to production. That is a week’s work, not a quarter’s, and it is the part that delivers most of the value.

Where you run this matters less than how, but if the provider is still open, the cloud account catalogue compares the options side by side.

For the vendor’s own reference on the services involved here, see the Kamatera support library.

Independent sizing is easier to understand once you have set it yourself. Our Kamatera accounts come in two configurations, and the cloud account catalogue compares the other nine providers.

Questions people ask

Do I need to codify my entire estate?

No, and attempting it is why these projects stall. Start with networking, which is the most tedious layer to rebuild and the least frequently changed, then compute, then supporting services. Codifying new work only is a perfectly good default.

What is the most dangerous part to get wrong?

State handling. Store state remotely rather than on a laptop, enable locking so simultaneous applies cannot corrupt it, and treat it as sensitive, because state files often contain generated passwords and keys in plain text.

How do I bring existing infrastructure under management?

Import it resource by resource, or leave it alone and define only new work in code. The second is pragmatic and gets the estate progressively codified without a migration project.

Why do infrastructure-as-code projects fail?

Usually because the definitions become too abstracted to read, or because using the console is easier than the pipeline. Prefer clarity to cleverness, modularise only after repeating yourself several times, and make the codified path the quicker one.

Telegram