Ansible vs Terraform: क्या चुनें और कब दोनों की जरूरत है?
Terraform इंफ्रास्ट्रक्चर प्रोविजनिंग के लिए है जबकि Ansible सर्वर कॉन्फ़िगरेशन के लिए। जानें कि कैसे Terraform स्टेट फाइल बनाता है और Ansible SSH के जरिए बदलाव लागू करता है।
Ansible और Terraform के बीच का अंतर एक वाक्य में
Ansible और Terraform एक ही काम करने वाले दो टूल्स के बीच का विकल्प नहीं हैं। Terraform यह घोषित करता है कि कौन सा इंफ्रास्ट्रक्चर मौजूद है: सर्वर्स, डिस्क, नेटवर्क्स, DNS रिकॉर्ड्स। Ansible यह घोषित करता है कि पहले से मौजूद मशीन के अंदर क्या स्थिति होनी चाहिए: पैकेजेस, यूजर्स, कॉन्फ़िगरेशन फाइल्स, रनिंग सर्विसेज। Terraform VPS बनाता है। Ansible उस VPS को वेब सर्वर में बदल देता है।
दोनों ही डिक्लेरेटिव (declarative) हैं और दोनों को इंफ्रास्ट्रक्चर एज़ कोड (IaC) कहा जाता है। वास्तविक अंतर यह है कि वे क्या याद रखते हैं। Terraform एक स्टेट फाइल लिखता है जो आपके कोड के हर रिसोर्स को API के माध्यम से बनाए गए वास्तविक ऑब्जेक्ट से मैप करती है, ताकि वह यह बता सके कि पाँच लाइनों को हटाने का मतलब एक सर्वर को नष्ट करना है। Ansible रन के बीच कुछ भी याद नहीं रखता। यह SSH के माध्यम से कनेक्ट होता है, मशीन का निरीक्षण करता है, और केवल उसी को बदलता है जो प्लेबुक से मेल नहीं खाता।
यह एक अंतर इस गाइड के बाकी हिस्सों की व्याख्या करता है, जिसमें यह भी शामिल है कि दोनों कार्यों को एक टूल में मिलाना गलत क्यों होता है।
Terraform वास्तव में क्या करता है
Terraform एक provider plugin के माध्यम से API से बात करता है। आपके provider का registry page उन resource types को परिभाषित करता है जिन्हें आप लिख सकते हैं, इसलिए एक host पर सर्वर और दूसरे host पर सर्वर अलग-अलग resource names और अलग-अलग arguments वाले होते हैं।
resource "cloud_server" "web" {
name = "web1"
image = "ubuntu-24.04"
type = "small"
}
output "web_ip" {
value = cloud_server.web.ipv4_address
}cloud_server को उस resource type से बदलें जिसे आपका provider document करता है। output ब्लॉक इस गाइड के लिए महत्वपूर्ण हिस्सा है, क्योंकि इसी तरह address Terraform से बाहर जाता है।
terraform init
terraform fmt -check
terraform validate
terraform plan -out=tfplan
terraform apply tfplanterraform init provider को डाउनलोड करता है और एक lock file लिखता है। terraform plan आपके कोड और state file के बीच का अंतर प्रिंट करता है, जो Plan: 1 to add, 0 to change, 0 to destroy. जैसी लाइन पर समाप्त होता है। उस लाइन को हर बार पढ़ें। कुछ arguments को सीधे (in-place) बदला नहीं जा सकता, और plan इसे attribute के बगल में # forces replacement के साथ बताता है, जिसके बाद 1 to add, 0 to change, 1 to destroy आता है। उस plan को apply करने से सर्वर डिलीट हो जाता है और एक नया खाली सर्वर बन जाता है, और इसी तरह लोग अपना वह डेटा खो देते हैं जिसे वे सुरक्षित समझते थे।
Plan को एक file में save करके उस file को apply करना, न कि सीधे terraform apply चलाना, यह सुनिश्चित करता है कि जो आपने review किया है वही run हो। इन दो commands के बीच, हो सकता है कि किसी और ने infrastructure बदल दिया हो।
terraform.tfstate आपकी memory है। इसे खोने का मतलब है कि Terraform को अब यह नहीं पता कि वे सर्वर आपके हैं, इसलिए अगला apply duplicates बनाने की कोशिश करेगा। जैसे ही एक से अधिक व्यक्ति commands run करने लगें, इसे remote backend में रखें, क्योंकि दो लोगों के एक साथ apply करने पर यह परिणाम मिलता है:
Error: Error acquiring the state lockOpenTofu, Terraform का ही एक fork है जिसमें समान commands और समान file format है। जुलाई 2026 तक, इस गाइड की हर चीज़ काम करेगी यदि आप terraform के बजाय tofu टाइप करते हैं।
Ansible वास्तव में क्या करता है
Ansible को किसी agent या API की आवश्यकता नहीं होती है। यह एक SSH connection खोलता है, एक छोटा Python module target पर copy करता है, उसे चलाता है और फिर हटा देता है। जिस भी चीज़ तक आप SSH और sudo password के साथ पहुँच सकते हैं, उसे Ansible configure कर सकता है।
- name: Base web server
hosts: web
become: true
tasks:
- name: Install nginx
ansible.builtin.apt:
name: nginx
state: present
update_cache: true
- name: Ensure nginx is running at boot
ansible.builtin.service:
name: nginx
state: started
enabled: trueansible -i inventory.ini web -m ansible.builtin.ping
ansible-playbook -i inventory.ini site.yml --check --diff
ansible-playbook -i inventory.ini site.ymlplaybook को debug करने से पहले ping module यह सुनिश्चित करता है कि SSH, Python और sudo सही ढंग से काम कर रहे हैं। एक सफल परिणाम web1 | SUCCESS => {"ping": "pong"} होता है। --check --diff run, Ansible की योजना के सबसे करीब है: यह बिना कुछ बदले यह बताता है कि क्या बदलाव किए जाएंगे। हालाँकि, जो tasks पहले के tasks पर निर्भर होते हैं, वे check mode में गलत रिपोर्ट दे सकते हैं, क्योंकि पिछला बदलाव वास्तव में कभी हुआ ही नहीं होता है।
हर run का अंत ok=6 changed=2 unreachable=0 failed=0 जैसे recap के साथ होता है। एक ही playbook को दो बार चलाएं। दूसरी बार चलाने पर परिणाम changed=0 आना चाहिए। जो task हर बार changed रिपोर्ट करता है, वह idempotent नहीं है, और यह आमतौर पर एक command या shell task होता है जिसे एक वास्तविक module होना चाहिए था। यदि आप इस क्षेत्र में नए हैं, तो एक single VPS पर पहली Ansible playbook से शुरुआत करें और धीरे-धीरे आगे बढ़ें।
जहाँ दोनों टूल्स का काम मेल खाता है, और जहाँ वे आपस में टकराते हैं
Terraform, remote-exec provisioner का उपयोग करके नए सर्वर पर commands चला सकता है। HashiCorp का अपना documentation provisioners को अंतिम विकल्प (last resort) मानता है। इसके पीछे ठोस कारण हैं।
एक provisioner केवल तभी चलता है जब resource बनाई जाती है। यदि आप script में बदलाव करते हैं, तो मौजूदा सर्वर पर कुछ नहीं होता, क्योंकि Terraform के दृष्टिकोण से resource पहले से ही code के अनुरूप है। Provisioner के steps कभी भी terraform plan में दिखाई नहीं देते, इसलिए आपके review में इनका कोई संकेत नहीं मिलता। यदि script विफल हो जाती है, तो Terraform resource को tainted के रूप में चिह्नित कर देता है, और अगली बार apply करने पर वह उस सर्वर को नष्ट करके फिर से बनाता है जो शायद पूरी तरह ठीक था।
यह विफलता गलत समय पर भी होती है। Provider सर्वर को उसी क्षण created रिपोर्ट कर देता है जैसे ही API ऐसा कहता है, जबकि operating system अभी भी boot हो रहा होता है और sshd अभी listening मोड में नहीं होता है।
Error: remote-exec provisioner error
timeout - last error: dial tcp 203.0.113.10:22: connect: connection refusedAnsible के साथ विपरीत प्रलोभन होता है। Cloud modules सर्वर बना सकते हैं, और कुछ मशीनों के लिए यह काम करता है। आप जो खो देते हैं वह है dependency graph और state file। Ansible खुशी-खुशी एक resource बना देगा, लेकिन यदि आप अपने playbook से उस task को हटा देते हैं, तो भी वह resource चलती रहेगी और उसका बिल आता रहेगा, क्योंकि कहीं भी यह दर्ज नहीं था कि वह आपकी थी।
इससे जो नियम निकलकर आता है वह यह है: Terraform को उन objects का स्वामित्व दें जिन्हें API बनाता और नष्ट करता है, और Ansible को booted operating system के अंदर की हर चीज़ का स्वामित्व दें।
हैंडऑफ, सफल रहा
हैंडऑफ एक सीमा है, न कि एकीकरण। Terraform अपना काम पूरा करता है, एक पता (address) प्रकाशित करता है और रुक जाता है। Ansible उस पते से शुरुआत करता है।
terraform apply -auto-approve
terraform output -raw web_ip
printf '[web]\n%s ansible_user=root\n' "$(terraform output -raw web_ip)" > inventory.ini
ansible -i inventory.ini web -m ansible.builtin.ping
ansible-playbook -i inventory.ini site.ymlterraform output -raw बिना कोट्स और बिना JSON रैपर के एक मान प्रिंट करता है, जो कि शेल सब्स्टीट्यूशन के भीतर आपको चाहिए होता है। कई सर्वर्स के लिए, terraform output -json का उपयोग करें और उससे इन्वेंट्री बनाएँ, क्योंकि -raw केवल एक स्ट्रिंग, नंबर या बूलियन को ही हैंडल करता है।
दोनों टूल्स के बीच ping स्टेप को बनाए रखना उपयोगी है। यह "Terraform ने मुझे गलत पता दिया" और "मेरे प्लेबुक में कोई बग है" के बीच अंतर स्पष्ट करता है, और जब प्लेबुक नई मशीन को छूने वाली पहली चीज़ होती है, तो ये दोनों समस्याएँ एक जैसी ही दिखाई देती हैं।
Terraform state को Ansible inventory के रूप में पढ़ना
यदि आप inventory file बिल्कुल नहीं लिखना चाहते हैं, तो cloud.terraform collection सीधे state को पढ़ लेती है।
ansible-galaxy collection install cloud.terraformअपने playbook के बगल में terraform.yml लिखें:
plugin: cloud.terraform.terraform_provider
project_path: /home/deploy/infraansible-inventory -i terraform.yml --graph
ansible-playbook -i terraform.yml site.ymlइस पर निर्भर होने से पहले दो बातें जान लें। यह plugin terraform show को project_path के विरुद्ध चलाता है, इसलिए वह directory पहले से initialized होनी चाहिए अन्यथा plugin विफल हो जाएगा। यह आपके server resources से hosts का निर्माण भी नहीं करता है: यह ansible_host और ansible_group resources को पढ़ता है, जिन्हें आप अपने Terraform code में Ansible provider का उपयोग करके घोषित करते हैं। जब तक आप उन्हें जोड़ते नहीं हैं, तब तक ansible-inventory --graph में कुछ भी दिखाई नहीं देता है।
एक साधारण generated inventory file को debug करना आसान होता है और यह किसी भी provider के साथ काम करती है। यह plugin तब उपयोगी साबित होता है जब inventory कुछ मशीनों से अधिक बढ़ जाती है और मैन्युअल संपादन (hand editing) से गलतियाँ होने लगती हैं; यही वह बिंदु है जहाँ एक control machine से कई Linux servers को manage करना एक आदत के बजाय एक वास्तविक कार्यप्रवाह (workflow) बन जाता है।
क्या आपको वास्तव में Terraform की आवश्यकता है?
इसे पढ़ने वाले अधिकांश लोगों को, कम से कम अभी के लिए, इसकी आवश्यकता नहीं है। Terraform का लाभ तब मिलता है जब infrastructure को बनाना और हटाना एक दोहराया जाने वाला कार्य हो। यदि आपने control panel के माध्यम से एक VPS लिया है और उसे दो वर्षों तक रखने का इरादा रखते हैं, तो Terraform केवल एक बार होने वाली प्रक्रिया का वर्णन करता है और एक state file जोड़ देता है जिसे खोना नहीं चाहिए।
Terraform का उपयोग तब करें जब आप अक्सर environments को फिर से बनाते हैं, जब staging को production से बिल्कुल मेल खाना होता है, जब कई लोग infrastructure में बदलाव करते हैं और आप चाहते हैं कि कुछ भी delete होने से पहले एक reviewable plan हो, या जब आप servers से आगे बढ़कर DNS records, load balancers और firewall rules जैसी चीजें manage करते हैं जो provider API में रहती हैं।
जब servers लंबे समय तक चलते हैं और संख्या में कम होते हैं, और जब दैनिक प्रश्न "क्या यह box सही ढंग से configured है" होता है, न कि "क्या यह box मौजूद है", तब केवल Ansible के साथ बने रहें। एक single playbook जो एक नए server को harden करती है, वह नए VPS पर पहले दस मिनट के समान ही काम करती है, जिसका लाभ यह है कि यह अगले server पर भी उसी तरह चलती है।
सीखने का क्रम इसी से तय होता है। Ansible आपके द्वारा लिए गए पहले server पर ही लाभ देना शुरू कर देता है। Terraform आपके द्वारा फिर से बनाए गए तीसरे environment पर लाभ देता है।
Handoff के दौरान क्या विफल होता है
सर्वर तैयार नहीं है। Terraform सफल हो जाता है, लेकिन Ansible तुरंत विफल हो जाता है।
fatal: [web1]: UNREACHABLE! => {"changed": false, "msg": "Failed to connect to the host via ssh: ssh: connect to host 203.0.113.10 port 22: Connection refused", "unreachable": true}API ने sshd के listening मोड में आने से पहले ही पता (address) लौटा दिया। एक निश्चित समय (fixed sleep) जोड़ने के बजाय port के तैयार होने की प्रतीक्षा करें। Ansible में इसके लिए ansible.builtin.wait_for_connection मौजूद है, जिसे play के पहले task के रूप में चलाएं। एक बार जब वही playbook एक नए बॉक्स के बजाय किसी group को target करती है, तो पहले से तय कर लें कि जब कोई host पहुंच से बाहर हो जाए तो क्या होना चाहिए, क्योंकि Ansible उस host को बाकी run से हटा देता है और recap लाइन ही एकमात्र ऐसी जगह है जहाँ यह आपको सूचित करता है।
Host key बदल गई है। आपने सर्वर को नष्ट करके फिर से बनाया है, और नया सर्वर उसी पते पर एक नई key के साथ जवाब दे रहा है।
Host key verification failed.ssh-keygen -R 203.0.113.10 का उपयोग करके पुरानी entry को हटा दें। जब Terraform rebuild कर रहा हो तो ऐसा अक्सर होता है, जो डेटा रखने वाली मशीनों पर rebuild को कम रखने का एक अच्छा कारण है।
Sudo विफल हो जाता है। fatal: [web1]: FAILED! => {"msg": "Missing sudo password"} का मतलब है कि उस host पर become: true को password की आवश्यकता है। या तो deploy user के लिए passwordless sudo कॉन्फ़िगर करें, या --ask-become-pass पास करें।
Terraform ऐसी चीज़ को नष्ट करना चाहता है जिसे आपने छुआ भी नहीं है। plan उन बदलावों को दिखाता है जिन्हें आपने कभी नहीं लिखा, जिसका अर्थ है कि वास्तविक infrastructure code से अलग हो गया है (drift), आमतौर पर इसलिए क्योंकि किसी ने provider के web panel में कोई सेटिंग बदल दी है। उस अंतर को स्वयं देखने के लिए terraform plan -refresh-only चलाएं, फिर तय करें कि code गलत है या live resource। कभी भी ऐसे destructive plan को apply न करें जिसे आप लाइन-दर-लाइन समझा न सकें।
Ansible हर run पर changed रिपोर्ट करता है। बिना creates या when guard वाला shell task बिना शर्त चलता है। यह केवल एक कॉस्मेटिक समस्या नहीं है, क्योंकि इसका मतलब है कि आप अब changed=0 का उपयोग इस संकेत के रूप में नहीं कर सकते कि सर्वर आपकी इच्छित स्थिति में है।
FAQ
क्या Terraform, Ansible की जगह ले सकता है?
सर्वर के अंदर कॉन्फ़िगरेशन के लिए नहीं। Terraform remote-exec provisioner के साथ स्क्रिप्ट चला सकता है, लेकिन वे केवल रिसोर्स निर्माण के समय चलती हैं, कभी भी terraform plan में दिखाई नहीं देतीं, और विफल होने पर रिसोर्स को 'taint' कर देती हैं, जिससे अगली बार 'apply' करने पर रिसोर्स नष्ट (destroy) होकर दोबारा बनता है। Terraform में ऐसा कोई मॉड्यूल नहीं है जो यह जांच सके कि nginx पहले से इंस्टॉल है या नहीं और यदि है, तो कुछ न करे। मशीन बनाने के लिए Terraform का उपयोग करें, फिर काम Ansible को सौंप दें।
क्या Ansible, Terraform की जगह ले सकता है?
लंबे समय तक चलने वाले कुछ सर्वरों के लिए, हाँ। Ansible में क्लाउड मॉड्यूल होते हैं जो सर्वर बनाते हैं, और यदि आप दो VPS इंस्टेंस लेते हैं और उन्हें बनाए रखते हैं, तो यह पर्याप्त है। आप जो खोते हैं वह है 'state file' और 'dependency graph': यदि आप प्लेबुक से कोई टास्क हटाते हैं, तो रिसोर्स चलता रहता है और उसका बिल आता रहता है, क्योंकि Ansible ने कभी रिकॉर्ड नहीं किया कि उसने उसे बनाया था। Terraform ऐसी स्थिति में उसे नष्ट (destroy) करने की योजना बनाता।
मुझे पहले क्या सीखना चाहिए?
Ansible, यदि आपके पास आज सर्वर हैं। यह पहली मशीन पर ही लाभ देना शुरू कर देता है, इसके लिए केवल SSH की आवश्यकता होती है, और यह कौशल उन सर्वरों पर भी लागू होता है जिन्हें आपने मैन्युअल रूप से ऑर्डर किया है। Terraform का लाभ बाद में मिलता है, जब आप बार-बार एनवायरनमेंट को फिर से बनाते हैं या सर्वर के अलावा अन्य प्रोवाइडर रिसोर्स, जैसे DNS रिकॉर्ड और फ़ायरवॉल नियमों को मैनेज करते हैं।
मैं Terraform से नए सर्वर का IP, Ansible में कैसे पास करूँ?
अपने Terraform कोड में एक output घोषित करें, फिर 'apply' के बाद उसे पढ़ें। terraform output -raw web_ip शेल सब्स्टीट्यूशन के लिए केवल वैल्यू प्रिंट करता है, और जब कई होस्ट हों तो terraform output -json आपको एक साथ सभी आउटपुट देता है। इसे एक इन्वेंट्री फ़ाइल में लिखें, या cloud.terraform कलेक्शन इंस्टॉल करें और ansible-inventory -i terraform.yml --graph को प्रोजेक्ट डायरेक्टरी की ओर पॉइंट करें।
Terraform के समाप्त होते ही मेरी प्लेबुक विफल क्यों हो जाती है?
प्रोवाइडर सर्वर को तभी 'created' रिपोर्ट कर देता है जैसे ही API ऐसा कहती है, जबकि ऑपरेटिंग सिस्टम अभी भी बूट हो रहा होता है, इसलिए शुरुआती कुछ सेकंड के लिए SSH कनेक्शन अस्वीकार कर दिया जाता है। यह त्रुटि UNREACHABLE! है जो Connection refused के साथ आती है। 'sleep' की अवधि का अनुमान लगाने के बजाय ansible.builtin.wait_for_connection को प्ले का पहला टास्क बनाएं, क्योंकि बूट का समय इमेज और प्लान के अनुसार अलग-अलग होता है।