<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Ansible on IT Comparison</title><link>https://comparison.metacog.co.kr/tags/ansible/</link><description>Recent content in Ansible on IT Comparison</description><generator>Hugo</generator><language>en-us</language><lastBuildDate>Sun, 02 Aug 2026 11:25:27 +0900</lastBuildDate><atom:link href="https://comparison.metacog.co.kr/tags/ansible/index.xml" rel="self" type="application/rss+xml"/><item><title>Terraform vs Ansible: Provisioning vs Configuration Management</title><link>https://comparison.metacog.co.kr/posts/2026-08-02-terraform-vs-ansible-provisioning-vs-configuration-managemen/</link><pubDate>Sun, 02 Aug 2026 11:25:27 +0900</pubDate><guid>https://comparison.metacog.co.kr/posts/2026-08-02-terraform-vs-ansible-provisioning-vs-configuration-managemen/</guid><description>&lt;h2 id="overview"&gt;Overview&lt;/h2&gt;
&lt;p&gt;Terraform and Ansible are both infrastructure-as-code tools but solve different problems: Terraform declaratively provisions and tracks cloud infrastructure using a state file, while Ansible procedurally configures and manages software on existing hosts with no persistent state. Many teams use them together — Terraform to stand up infrastructure, Ansible to configure it.&lt;/p&gt;
&lt;h2 id="comparison-diagram"&gt;Comparison Diagram&lt;/h2&gt;
&lt;div class="compare-diagram"&gt;
&lt;svg viewBox="0 0 640 360" xmlns="http://www.w3.org/2000/svg"&gt;&lt;line x1="320" y1="20" x2="320" y2="335" style="stroke:var(--border)" stroke-width="1.5" stroke-dasharray="4 4"/&gt;&lt;text x="170" y="28" text-anchor="middle" style="fill:var(--primary)" font-size="16" font-weight="bold"&gt;Terraform&lt;/text&gt;&lt;text x="170" y="44" text-anchor="middle" style="fill:var(--secondary)" font-size="11"&gt;declarative&lt;/text&gt;&lt;rect x="70" y="52" width="200" height="32" rx="4" style="fill:var(--compare-a-soft);stroke:var(--compare-a)" stroke-width="1.5"/&gt;&lt;text x="170" y="72" text-anchor="middle" style="fill:var(--content)" font-size="11"&gt;main.tf (desired state)&lt;/text&gt;&lt;line x1="170" y1="84" x2="170" y2="98" style="stroke:var(--compare-a)" stroke-width="1.5"/&gt;&lt;rect x="70" y="98" width="200" height="32" rx="4" style="fill:var(--compare-a-soft);stroke:var(--compare-a)" stroke-width="1.5"/&gt;&lt;text x="170" y="118" text-anchor="middle" style="fill:var(--content)" font-size="11"&gt;state file (source of truth)&lt;/text&gt;&lt;line x1="170" y1="130" x2="170" y2="152" style="stroke:var(--compare-a)" stroke-width="1.5"/&gt;&lt;rect x="110" y="152" width="120" height="30" rx="4" style="fill:var(--compare-a-soft);stroke:var(--compare-a)" stroke-width="1.5"/&gt;&lt;text x="170" y="171" text-anchor="middle" style="fill:var(--content)" font-size="10"&gt;dependency graph&lt;/text&gt;&lt;line x1="150" y1="182" x2="65" y2="244" style="stroke:var(--compare-a)" stroke-width="1.2"/&gt;&lt;line x1="170" y1="182" x2="155" y2="244" style="stroke:var(--compare-a)" stroke-width="1.2"/&gt;&lt;line x1="190" y1="182" x2="245" y2="244" style="stroke:var(--compare-a)" stroke-width="1.2"/&gt;&lt;rect x="25" y="244" width="80" height="32" rx="4" style="fill:var(--compare-a-soft);stroke:var(--compare-a)" stroke-width="1.5"/&gt;&lt;text x="65" y="264" text-anchor="middle" style="fill:var(--content)" font-size="10"&gt;VM&lt;/text&gt;&lt;rect x="115" y="244" width="80" height="32" rx="4" style="fill:var(--compare-a-soft);stroke:var(--compare-a)" stroke-width="1.5"/&gt;&lt;text x="155" y="264" text-anchor="middle" style="fill:var(--content)" font-size="10"&gt;Network&lt;/text&gt;&lt;rect x="205" y="244" width="80" height="32" rx="4" style="fill:var(--compare-a-soft);stroke:var(--compare-a)" stroke-width="1.5"/&gt;&lt;text x="245" y="264" text-anchor="middle" style="fill:var(--content)" font-size="10"&gt;DB&lt;/text&gt;&lt;text x="170" y="300" text-anchor="middle" style="fill:var(--secondary)" font-size="9.5"&gt;converges infra to match state&lt;/text&gt;&lt;text x="480" y="28" text-anchor="middle" style="fill:var(--primary)" font-size="16" font-weight="bold"&gt;Ansible&lt;/text&gt;&lt;text x="480" y="44" text-anchor="middle" style="fill:var(--secondary)" font-size="11"&gt;procedural&lt;/text&gt;&lt;rect x="380" y="52" width="200" height="32" rx="4" style="fill:var(--compare-b-soft);stroke:var(--compare-b)" stroke-width="1.5"/&gt;&lt;text x="480" y="72" text-anchor="middle" style="fill:var(--content)" font-size="11"&gt;playbook.yml&lt;/text&gt;&lt;line x1="480" y1="84" x2="480" y2="96" style="stroke:var(--compare-b)" stroke-width="1.5"/&gt;&lt;rect x="400" y="96" width="160" height="26" rx="4" style="fill:var(--compare-b-soft);stroke:var(--compare-b)" stroke-width="1.5"/&gt;&lt;text x="480" y="113" text-anchor="middle" style="fill:var(--content)" font-size="10"&gt;task 1: install pkg&lt;/text&gt;&lt;line x1="480" y1="122" x2="480" y2="132" style="stroke:var(--compare-b)" stroke-width="1.5"/&gt;&lt;rect x="400" y="132" width="160" height="26" rx="4" style="fill:var(--compare-b-soft);stroke:var(--compare-b)" stroke-width="1.5"/&gt;&lt;text x="480" y="149" text-anchor="middle" style="fill:var(--content)" font-size="10"&gt;task 2: configure&lt;/text&gt;&lt;line x1="480" y1="158" x2="480" y2="168" style="stroke:var(--compare-b)" stroke-width="1.5"/&gt;&lt;rect x="400" y="168" width="160" height="26" rx="4" style="fill:var(--compare-b-soft);stroke:var(--compare-b)" stroke-width="1.5"/&gt;&lt;text x="480" y="185" text-anchor="middle" style="fill:var(--content)" font-size="10"&gt;task 3: start service&lt;/text&gt;&lt;line x1="460" y1="194" x2="385" y2="244" style="stroke:var(--compare-b)" stroke-width="1.2" stroke-dasharray="3 3"/&gt;&lt;line x1="480" y1="194" x2="475" y2="244" style="stroke:var(--compare-b)" stroke-width="1.2" stroke-dasharray="3 3"/&gt;&lt;line x1="500" y1="194" x2="565" y2="244" style="stroke:var(--compare-b)" stroke-width="1.2" stroke-dasharray="3 3"/&gt;&lt;rect x="345" y="244" width="80" height="32" rx="4" style="fill:var(--compare-b-soft);stroke:var(--compare-b)" stroke-width="1.5"/&gt;&lt;text x="385" y="264" text-anchor="middle" style="fill:var(--content)" font-size="10"&gt;Server A&lt;/text&gt;&lt;rect x="435" y="244" width="80" height="32" rx="4" style="fill:var(--compare-b-soft);stroke:var(--compare-b)" stroke-width="1.5"/&gt;&lt;text x="475" y="264" text-anchor="middle" style="fill:var(--content)" font-size="10"&gt;Server B&lt;/text&gt;&lt;rect x="525" y="244" width="80" height="32" rx="4" style="fill:var(--compare-b-soft);stroke:var(--compare-b)" stroke-width="1.5"/&gt;&lt;text x="565" y="264" text-anchor="middle" style="fill:var(--content)" font-size="10"&gt;Server C&lt;/text&gt;&lt;text x="480" y="300" text-anchor="middle" style="fill:var(--secondary)" font-size="9.5"&gt;sequential push over SSH, no state file&lt;/text&gt;&lt;/svg&gt;
&lt;/div&gt;
&lt;h2 id="comparison-table"&gt;Comparison Table&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Aspect&lt;/th&gt;
&lt;th&gt;Terraform&lt;/th&gt;
&lt;th&gt;Ansible&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Primary purpose&lt;/td&gt;
&lt;td&gt;Provision and tear down cloud/infra resources (VMs, networks, DBs)&lt;/td&gt;
&lt;td&gt;Configure software and manage state on existing hosts&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Configuration language&lt;/td&gt;
&lt;td&gt;HCL (HashiCorp Configuration Language), declarative&lt;/td&gt;
&lt;td&gt;YAML playbooks, procedural task lists&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Execution model&lt;/td&gt;
&lt;td&gt;Builds a dependency graph and applies changes in parallel where possible&lt;/td&gt;
&lt;td&gt;Executes tasks sequentially, in order, per host&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;State management&lt;/td&gt;
&lt;td&gt;Maintains a state file mapping config to real resources&lt;/td&gt;
&lt;td&gt;Stateless — queries live system facts on each run&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Idempotency approach&lt;/td&gt;
&lt;td&gt;Diffs desired config against state file before acting&lt;/td&gt;
&lt;td&gt;Each module checks current condition before making a change&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Connectivity/agent requirement&lt;/td&gt;
&lt;td&gt;Agentless — calls cloud/provider APIs directly&lt;/td&gt;
&lt;td&gt;Agentless — connects over SSH or WinRM to target hosts&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Failure &amp;amp; recovery handling&lt;/td&gt;
&lt;td&gt;Partial applies are resolved by re-running against the state file&lt;/td&gt;
&lt;td&gt;Reruns the playbook from the start; tasks are re-checked, not resumed&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="key-differences"&gt;Key Differences&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Terraform tracks infrastructure in a persistent &lt;strong class="kw"&gt;state file&lt;/strong&gt;; Ansible has no state store and reads live system facts each run.&lt;/li&gt;
&lt;li&gt;Terraform resolves a &lt;strong class="kw"&gt;dependency graph&lt;/strong&gt; to apply changes in parallel; Ansible runs tasks &lt;strong class="kw"&gt;sequentially&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Terraform talks to infrastructure through provider &lt;strong class="kw"&gt;APIs&lt;/strong&gt;; Ansible connects to hosts via &lt;strong class="kw"&gt;SSH/WinRM&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Terraform is built for &lt;strong class="kw"&gt;provisioning&lt;/strong&gt; infra; Ansible is built for &lt;strong class="kw"&gt;configuration&lt;/strong&gt; of what already exists.&lt;/li&gt;
&lt;li&gt;They&amp;rsquo;re commonly paired: Terraform creates the servers, then Ansible &lt;strong class="kw"&gt;configures&lt;/strong&gt; them.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="when-to-use-each"&gt;When to Use Each&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Terraform&lt;/strong&gt;&lt;/p&gt;</description></item></channel></rss>