Lesson: When to Use Which
What you'll learn
- A simple decision rule for picking Terraform, Ansible, cloud-init, or Pulumi.
- The boundary between provisioning, configuration management, and bootstrap.
- How these tools combine in one workflow rather than competing.
- A worked example: Terraform + cloud-init + Ansible building one server together.
- How the lab's current setup maps onto this picture.
Skill gained: given a real task, you can name the right IaC tool (or combination) and justify the choice — the practical payoff of the whole module.
The lesson
1. Start with the job, not the tool
Beginners ask "which tool is best?" The better question is "what job am I doing?" Each tool owns a job (Chapter 1). Match the job, and the tool picks itself.
Question to ask Tool
───────────────────────────────────── ──────────────────────
"Create a VM / network / DNS record?" -> Terraform (or Pulumi)
"Set up software inside a machine?" -> Ansible
"First-boot baseline on a new VM?" -> cloud-init
"Provisioning, but in Python/TS/Go?" -> Pulumi
2. The three jobs, sharpened
- Provisioning = bring infrastructure into existence. The unit is a resource: a VM, a disk, a network, a load balancer, a DNS entry. Lives in the cloud/hypervisor API. → Terraform or Pulumi.
- Bootstrap = the one-time, first-boot setup that makes a freshly created machine usable. → cloud-init.
- Configuration management = the ongoing setup inside machines: packages, files, services, users, kept correct over the machine's whole life. → Ansible.
Pulumi isn't a fourth job — it's an alternative way to do provisioning. Choose Terraform vs Pulumi by how you want to write it: HCL (purpose-built config) vs a real programming language. Everything else about them is similar.
3. A quick decision checklist
Ask, in order:
- Does the thing exist yet? No → you need provisioning (Terraform/Pulumi).
- Is it a one-time first-boot setup? Yes → cloud-init.
- Is it ongoing software/config inside an existing box? Yes → Ansible.
- Provisioning, and the team prefers a real language? → Pulumi instead of Terraform.
Most real situations need more than one of these. That's normal and correct — they're teammates, not rivals.
4. They combine: the classic pipeline
The most common professional pattern uses three tools, each for its job:
┌─────────────┐ creates VM, ┌──────────────┐ first boot ┌──────────────┐
│ TERRAFORM │ passes it ───> │ cloud-init │ ───────────> │ the new VM │
│ (provision) │ user-data │ (bootstrap) │ baseline │ exists + │
└─────────────┘ └──────────────┘ ready │ reachable │
└──────┬───────┘
│ SSH
▼
┌──────────────┐
│ ANSIBLE │
│ (configure, │
│ ongoing) │
└──────────────┘
- Terraform creates the VM, network, and firewall rules — and hands the VM a cloud-init user-data blob.
- cloud-init runs at first boot: sets hostname, creates the login user, installs your SSH key, does minimal baseline setup so the machine is reachable.
- Ansible then SSHes in to do the detailed, repeatable configuration — and you re-run it anytime over the machine's life to correct drift.
Each tool does what it's best at; none is stretched into a job it's poor at.
5. A worked example
Goal: stand up a web server.
- Provision (Terraform): declare one VM (
t3.micro), a security group allowing ports 22 and 443, and a DNS recordweb.example.compointing at the new public IP203.0.113.10. - Bootstrap (cloud-init, passed in by Terraform):
#cloud-config hostname: web01 users: - name: omniops groups: [sudo] ssh_authorized_keys: - ssh-ed25519 AAAA...your-key package_update: true packages: [python3] # Ansible needs Python on the target - Configure (Ansible): a playbook that installs nginx, deploys the site config, and ensures the service is running — re-runnable forever.
Notice cloud-init did just enough to make Ansible's job possible (a user to SSH as, Python present), then got out of the way. Clean division of labor.
6. Anti-patterns to avoid
- Using Ansible to create cloud VMs from scratch when Terraform would track their lifecycle far more cleanly. (Ansible can, but it's not its strength.)
- Trying to re-run cloud-init for ongoing changes. It's a first-boot tool; for day-2 changes use Ansible or rebuild from an updated snippet.
- Putting secrets in any of these files. Use a secrets manager or injected variables; in shared examples write
<REDACTED>. - Skipping
plan/--check. Both Terraform (plan) and Ansible (--check) can preview changes. Preview before you change production. - Not version-controlling the files. All of these are text — they belong in Git (Module 4), reviewed via pull requests.
7. How the lab maps onto this
Right now the lab uses exactly one of these tools in production, and that's deliberate for learning:
- cloud-init is live: every lab VM is built from a golden template and bootstrapped by a per-VM cloud-init snippet on first boot. That's your hands-on IaC today — open a snippet and read it.
- Terraform, Ansible, and Pulumi are not deployed yet in the lab. You learned them here conceptually with small standalone examples. When the lab adds them, the natural fit is: Terraform (or Pulumi) to provision VMs on the hypervisor behind pfSense, cloud-init for first boot (already in place), and Ansible — run from the Jumpbox as its control node — for configuration.
If you can look at any task and say "that's provisioning / that's bootstrap / that's config management, so I'd reach for this tool," you've got the core skill of this module.
Dig deeper
- Terraform: provision (run cloud-init/scripts on new resources)
- Ansible: how it works / use cases
- cloud-init: what it is
- Red Hat: IaC tools compared
- Pulumi vs Terraform
Search terms
terraform vs ansible vs cloud-init when to useprovisioning vs configuration management differenceterraform cloud-init ansible together workflowday 1 vs day 2 operations devopsinfrastructure as code best practices beginners
Check yourself
- What single question should you ask first when picking an IaC tool?
- Which tool owns provisioning, which owns bootstrap, and which owns configuration management?
- In the classic combined pipeline, what does each of Terraform, cloud-init, and Ansible contribute?
- Why is "re-run cloud-init to make a day-2 change" an anti-pattern, and what should you do instead?
- Which of these tools is actually live in the lab today, and how is it used?
No comments to display
No comments to display