Infrastructure as code
The order service's database and Redis were made by hand in a cloud console, and nobody can say exactly how. This lesson puts them in Terraform or OpenTofu files, so every change is planned, reviewed in a pull request and applied by the pipeline, and so staging can be rebuilt from Git.
By the end you can
- Explain how a declarative tool turns code, state and the real cloud into a plan
- Keep state in a remote backend with locking, and keep secrets out of it where you can
- Read a plan line by line and spot the lines that destroy data
- Run plan in the pull request and apply the saved plan on merge, with no stored cloud keys
- Find drift, adopt hand-made resources with import blocks, and refactor safely with moved blocks
The everyday picture
When Mangrove Market opens a new store, the fit-out team works from a planogram: a drawing of every shelf and what goes on it. They do not build the store from memory. They walk the floor, compare it with the drawing, and make a list: two shelves to add, one fridge to move, an old stand to remove. A manager signs the list before anyone lifts a box.
The store also keeps an equipment register: fridge number 4 is serial ABC-123, bought in March. Without the register, the team could not tell "our fridge" from a supplier's fridge that happens to stand in the same spot.
Infrastructure as code works the same way. Your code is the drawing. The state file is the register. The plan is the signed list of changes. And when someone rearranges a shelf without changing the drawing, the next walk-through finds it.
Why describe infrastructure in files
Infrastructure as code (IaC) means the database, the cache, the network rules and the DNS records are written in files, kept in Git, and applied by a tool. Today the order service's staging database was created by clicking in the cloud console two years ago. Production was clicked separately, later, by someone else. Nobody knows every setting, and the two differ in ways that only show up during a release. IaC gives you three things the console cannot:
- Review. A change to the database size is a pull request, read and approved like any code change (Pull requests and code review).
- Repeat. Staging and production come from the same files with different numbers, so they stop drifting apart.
- Recover. If staging is deleted, one command rebuilds it. The code rebuilds the empty database server; your data still comes from backups (Backups).
Terraform and OpenTofu are declarative. You write what should exist, not the steps to create it. A script that says "create a database" fails or makes a second copy when you run it twice. A Terraform file that says "a database called orders-staging should exist, with 50 GB" does nothing the second time, because it already matches. Change 50 to 100 and the tool works out that only the storage needs to change.
The files are written in HCL and built from a few pieces:
- A provider talks to one platform's API. We use AWS as the example; others work the same way.
- A resource block is one thing that should exist, with an address like
aws_db_instance.orders. - Variables are inputs, outputs are values other code can read (the database host name), and a module is a folder of resources you can use several times with different inputs.
# one resource: the tool compares this with what exists and plans the difference
resource "aws_elasticache_cluster" "cache" {
cluster_id = "orders-staging-redis" # the name in the cloud
engine = "redis"
node_type = var.cache_node_type # an input: small in staging, larger in production
num_cache_nodes = 1
}
output "redis_host" {
value = aws_elasticache_cluster.cache.cache_nodes[0].address # read by the app's config
}A word on names. In 2023 HashiCorp moved Terraform from the open-source MPL 2.0 licence to the Business Source License, and the last open version was forked as OpenTofu, now a Linux Foundation project under MPL 2.0. For everything in this lesson they work the same way; the OpenTofu command is tofu instead of terraform. Features arrive at different times in each, so check versions.
Quick check
A test bucket is managed by Terraform. You delete its resource block from the code and run apply. What happens to the bucket?
The code is the full description of what should exist. A resource that the state knows about but the code no longer mentions is planned for destruction. To stop managing something without deleting it, you need a removed block, covered later. Option 1 is how a script thinks, and the declarative model is the opposite.