DevOps · lesson 7 of 8
Intermediate
7- 2 Choosing a CI/CD Toolchain: The Same Weighted Framework as Choosing a Cloud
- 3 CI/CD Pipeline Patterns: Sequential, Parallel, and Staged
- 4 Deployment Strategies Compared: Rolling, Blue-Green, and Canary
- 5 GitOps in Practice: Git as the Source of Truth
- 6 Computing DORA Metrics From Your Own Git History
- 7 Terraform vs. Ansible: A Weighted Decision Framework
- 8 Observability Synthesis: Logs, Metrics, Traces, and Alerts as One Signal
Also part of DevOps
12- + PR Workflow: Rebasing, Squash Merge, and Merge Commits from Git & GitHub
- + GitHub Actions: Workflows, Jobs, and a Real Failing Step from GitHub Actions
- + Jenkins CI: Pipeline Basics from Jenkins
- + Bash DevOps Scripts from Bash
- + Introduction to Docker from Docker
- + Deployments and Rollouts from Kubernetes
- + Terraform Fundamentals (IaC) from Terraform
- + Terraform CI/CD with GitHub Actions (plan/apply) from Terraform
- + Ansible Idempotency, Verified: Run It Twice and Watch changed=0 from Ansible
- + Prometheus Scrapes You — It's Pull, Not Push from Monitoring & Observability
- + A Firing Alert Doesn't Mean Anyone Was Notified from Monitoring & Observability
- + A CI Security Gate: Gitleaks, Bandit and pip-audit in One Workflow from DevSecOps (AppSec in the pipeline)
Also part of: Terraform Ansible
Terraform vs. Ansible: A Weighted Decision Framework
Score Terraform, Ansible, and using both against the same four factors — provisioning, host configuration, state tracking, and operational simplicity — across three real scenarios.
By SkillByExample · Published
Same two tools, same four factors, three scenarios — and the recommendation changes each time, including once to “use both.”
The four factors
- Provisions new cloud resources — creating a VPC, VMs, load balancers, or managed databases that don’t exist yet.
- Configures existing hosts — installing packages, managing users, deploying app config onto machines that are already running.
- State and drift tracking — whether the tool keeps an explicit record of what it manages and can detect when reality has drifted from it.
- Operational simplicity — how much there is to learn, run, and keep in sync. Using two tools together is never free, even when each individually is simple.
# iac_config_mgmt.py
def recommend(name, weights, scores):
options = ("Terraform", "Ansible", "Both")
totals = {o: sum(w * scores[f][o] for f, w in weights.items()) for o in options}
ranked = sorted(totals.items(), key=lambda kv: -kv[1])
print(name)
for opt, total in ranked:
print(f" {opt:<10}{total:5.2f}")
print(f" -> recommend {ranked[0][0]}\n")
scores = {
"provisions_new_cloud_resources": {"Terraform": 10, "Ansible": 3, "Both": 10},
"configures_existing_hosts": {"Terraform": 2, "Ansible": 10, "Both": 10},
"state_and_drift_tracking": {"Terraform": 8, "Ansible": 4, "Both": 7},
"operational_simplicity": {"Terraform": 8, "Ansible": 8, "Both": 3},
}
Three real scenarios
# Scenario 1: new cloud footprint from zero, nothing existing to configure.
recommend(
"New cloud footprint from zero, no legacy servers",
{"provisions_new_cloud_resources": 0.50, "configures_existing_hosts": 0.05,
"state_and_drift_tracking": 0.25, "operational_simplicity": 0.20},
scores,
)
# Scenario 2: long-lived on-prem fleet, no new cloud resources being created.
recommend(
"Long-lived on-prem fleet, no new cloud resources",
{"provisions_new_cloud_resources": 0.05, "configures_existing_hosts": 0.55,
"state_and_drift_tracking": 0.15, "operational_simplicity": 0.25},
scores,
)
# Scenario 3: platform team provisioning new VMs and configuring app runtime on them equally.
recommend(
"New VMs that also need app-runtime configuration",
{"provisions_new_cloud_resources": 0.35, "configures_existing_hosts": 0.35,
"state_and_drift_tracking": 0.15, "operational_simplicity": 0.15},
scores,
)
$ py iac_config_mgmt.py
New cloud footprint from zero, no legacy servers
Terraform 8.70
Both 7.85
Ansible 4.60
-> recommend Terraform
Long-lived on-prem fleet, no new cloud resources
Ansible 8.25
Both 7.80
Terraform 4.80
-> recommend Ansible
New VMs that also need app-runtime configuration
Both 8.50
Terraform 6.60
Ansible 6.35
-> recommend Both
Terraform wins the pure-provisioning scenario despite scoring badly on host configuration, because that dimension barely matters when there’s nothing existing to configure. Ansible wins the pure-configuration scenario the same way in reverse. Only the third scenario — where both provisioning and configuration genuinely matter in similar measure — is where paying the operational-simplicity cost of running two tools together actually pays for itself.
Practice
1. Take scenario 3 and weight operational simplicity at 0.60. Does "Both" still win?
recommend(
"New VMs needing config, but operational simplicity weighted 0.60",
{"provisions_new_cloud_resources": 0.15, "configures_existing_hosts": 0.15,
"state_and_drift_tracking": 0.10, "operational_simplicity": 0.60},
scores,
)
New VMs needing config, but operational simplicity weighted 0.60
Terraform 7.40
Ansible 7.15
Both 5.50
-> recommend Terraform
Even in the exact scenario where both provisioning and configuration matter, weighting the overhead of running two tools heavily enough overturns “use both” — the framework doesn’t treat combining tools as a free win, because it isn’t one.
2. Weight all four factors equally. Which option wins on balance?
recommend(
"Equal weights on every factor",
{"provisions_new_cloud_resources": 0.25, "configures_existing_hosts": 0.25,
"state_and_drift_tracking": 0.25, "operational_simplicity": 0.25},
scores,
)
Equal weights on every factor
Both 7.50
Terraform 7.00
Ansible 6.25
-> recommend Both
“Both” wins on raw average because it’s the strongest or tied-strongest option on the two biggest-swing factors (provisioning and configuration) and only pays its penalty on one factor (simplicity) — a fact about this specific scoresheet, not a universal argument for always combining the two tools.
3. Re-score the on-prem scenario for a Windows Server fleet, where Ansible's SSH-based model needs WinRM instead and fits less cleanly. Does the recommendation change?
scores_windows_fleet = {**scores, "configures_existing_hosts": {"Terraform": 2, "Ansible": 5, "Both": 6}}
recommend(
"Long-lived on-prem fleet, but it is Windows Server (WinRM, not SSH)",
{"provisions_new_cloud_resources": 0.05, "configures_existing_hosts": 0.55,
"state_and_drift_tracking": 0.15, "operational_simplicity": 0.25},
scores_windows_fleet,
)
Long-lived on-prem fleet, but it is Windows Server (WinRM, not SSH)
Both 5.60
Ansible 5.50
Terraform 4.80
-> recommend Both
A small, realistic dent in Ansible’s host-configuration fit for Windows targets (versus its native strength on Linux over SSH) is enough to flip the recommendation from pure Ansible to “Both” — close, at 5.60 versus 5.50, which is itself worth noting: real recommendations aren’t always decisive, and a near-tie score is a signal to weigh in factors this framework doesn’t capture (existing team skill, for instance) rather than trust the number blindly.
4. Add a fifth factor, "multi_cloud_portability" — how well the setup transfers to a second cloud provider. Score Terraform 9, Ansible 6, Both 8, and re-run scenario 1 with it weighted 0.20 (rebalancing the other weights down proportionally).
scores["multi_cloud_portability"] = {"Terraform": 9, "Ansible": 6, "Both": 8}
recommend(
"New cloud footprint, portability to a second cloud now weighted 0.20",
{"provisions_new_cloud_resources": 0.40, "configures_existing_hosts": 0.04,
"state_and_drift_tracking": 0.20, "operational_simplicity": 0.16,
"multi_cloud_portability": 0.20},
scores,
)
Terraform’s provider-abstraction model was always its structural advantage for multi-cloud work; adding this factor explicitly and weighting it just makes that advantage visible in the score instead of leaving it implicit in the provisioning number alone.
5. This framework never lets "Both" lose the pure-provisioning scenario by much (7.85 vs. Terraform's 8.70). Why is that gap so small given Ansible barely provisions anything?
Because in the scores dict, Both’s provisions_new_cloud_resources score is set equal to Terraform’s (10), on the reasoning that a combined setup still uses Terraform for the provisioning half — that factor contributes zero to the gap. Breaking the full 0.85-point gap down factor by factor: configures_existing_hosts actually favors Both by 0.40 (it inherits Ansible’s strength there for free), state_and_drift_tracking favors Terraform by 0.25, and operational_simplicity favors Terraform by a full 1.00 — 0 - 0.40 + 0.25 + 1.00 = 0.85, exactly the observed gap. The single biggest driver is operational simplicity, but it isn’t the whole story — Both’s host-configuration strength is quietly clawing back nearly half a point that a simpler “it’s all about overhead” explanation would miss. Decomposing a score gap like this, factor by factor, is a useful sanity check before trusting any weighted-scoring result.