SSD Nodes Learn 🎉 VPS החל מ־$5.50/חודש
מדריכים Matt Connorמאת Matt Connor · עודכן 2026-08-07

ההבדל בין Ansible ל-Terraform: מה באמת צריך?

המדריך המלא להבנת ההבדלים בין Terraform ל-Ansible. גלו מדוע Terraform מתמחה בניהול תשתית ו-Ansible בקונפיגורציה, מתי להשתמש בכל כלי ואיך לבצע את ה-handoff ביניהם בצורה נכונה.

ההבדל בין Ansible לבין Terraform במשפט אחד

הבחירה בין Ansible לבין Terraform אינה בחירה בין שני כלים המבצעים את אותה עבודה. Terraform מצהיר על התשתית הקיימת: שרתים, כוננים, רשתות ורשומות DNS. Ansible מצהיר על המצב הרצוי בתוך מכונה קיימת: חבילות, משתמשים, קובצי תצורה ושירותים פעילים. Terraform יוצר את ה-VPS, ו-Ansible הופך את ה-VPS לשרת אינטרנט.

שניהם דקלרטיביים ושניהם מוגדרים כ-infrastructure as code (IaC). ההבדל המהותי הוא במידע שהם שומרים. Terraform כותב קובץ state הממפה כל משאב בקוד לאובייקט ממשי שנוצר דרך API, כך שהוא יודע שמחיקת חמש שורות משמעותה השמדת שרת. Ansible אינו זוכר דבר בין הרצות. הוא מתחבר באמצעות SSH, בוחן את המכונה ומשנה רק את מה שאינו תואם ל-playbook.

הבדל יחיד זה מסביר את המשך המדריך, כולל הסיבות לכך שערבוב בין שני התפקידים בכלי אחד מוביל לכשלים.

מה Terraform עושה בפועל

Terraform מתקשר עם API באמצעות תוסף ספק (provider plugin). דף ה-registry של הספק שלכם מגדיר את סוגי המשאבים שניתן לכתוב; לכן, שרת במארח אחד ושרת במארח אחר הם שמות משאבים שונים עם ארגומנטים שונים.

resource "cloud_server" "web" {
  name  = "web1"
  image = "ubuntu-24.04"
  type  = "small"
}

output "web_ip" {
  value = cloud_server.web.ipv4_address
}

החליפו את cloud_server בסוג המשאב כפי שמתועד אצל הספק שלכם. הבלוק output הוא החלק החשוב ביותר במדריך זה, שכן כך הכתובת יוצאת מ-Terraform.

terraform init
terraform fmt -check
terraform validate
terraform plan -out=tfplan
terraform apply tfplan

הפקודה terraform init מורידה את הספק וכותבת קובץ נעילה (lock file). הפקודה terraform plan מציגה את ההבדלים בין הקוד שלכם לבין קובץ ה-state, ומסתיימת בשורה כמו Plan: 1 to add, 0 to change, 0 to destroy.. קראו שורה זו בכל פעם. ישנם ארגומנטים שלא ניתן לשנות במקום (in-place), וה-plan מציין זאת באמצעות # forces replacement לצד המאפיין, ולאחריו 1 to add, 0 to change, 1 to destroy. החלת (apply) ה-plan הזה מוחקת את השרת ובונה שרת חדש וריק; כך אנשים מאבדים נתונים שהם חשבו שהם בטוחים.

שמירת ה-plan לקובץ והחלת הקובץ, במקום הרצה של terraform apply פשוט, מבטיחה שהדבר שסקרתם הוא הדבר שיוצא לפועל. בין שתי הפקודות, מישהו אחר עלול לשנות את התשתית.

הקובץ terraform.tfstate הוא הזיכרון של המערכת. אם תאבדו אותו, Terraform לא ידע עוד שהשרתים האלו שייכים לכם, וה-apply הבא ינסה ליצור כפילויות. שמרו אותו ב-backend מרוחק ברגע שיותר מאדם אחד מריץ את הפקודות, כיוון ששני אנשים שמריצים apply בו-זמנית מייצרים את זה:

Error: Error acquiring the state lock

OpenTofu הוא fork של Terraform עם אותן פקודות ואותו פורמט קבצים. נכון ליולי 2026, כל מה שמופיע במדריך זה עובד אם תקלידו tofu במקום terraform.

מה Ansible עושה בפועל

Ansible אינו דורש סוכן (agent) ואינו דורש API. הוא פותח חיבור SSH, מעתיק מודול Python קטן ליעד, מריץ אותו ומוחק אותו. כל מה שניתן להגיע אליו באמצעות SSH וסיסמת sudo, ניתן להגדרה באמצעות Ansible.

- 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: true
ansible -i inventory.ini web -m ansible.builtin.ping
ansible-playbook -i inventory.ini site.yml --check --diff
ansible-playbook -i inventory.ini site.yml

המודול ping מאמת את הגישה ב-SSH, את קיום Python ואת הרשאות ה-sudo לפני שמתחילים בניפוי שגיאות (debugging) של playbook. תוצאה תקינה היא web1 | SUCCESS => {"ping": "pong"}. הרצה עם --check --diff היא הדבר הקרוב ביותר לתוכנית עבודה ב-Ansible: היא מדווחת מה היה משתנה מבלי לבצע את השינוי בפועל. עם זאת, משימות התלויות במשימות קודמות עלולות לדווח דיווח שגוי במצב בדיקה, כיוון שהשינוי הקודם לא התרחש באמת.

כל הרצה מסתיימת בסיכום כגון ok=6 changed=2 unreachable=0 failed=0. הריצו את אותו ה-playbook פעמיים. ההרצה השנייה אמורה לדווח changed=0. משימה שמדווחת על שינוי (changed) בכל הרצה אינה אידמפוטנטית, ובדרך כלל מדובר במשימת command או shell שהייתה צריכה להתבצע באמצעות מודול ייעודי. אם מדובר בתחום חדש עבורכם, התחילו עם יצירת ה-playbook הראשון ב-Ansible על שרת VPS בודד והמשיכו משם.

היכן הכלים חופפים והיכן הם מתנגשים

Terraform יכול להריץ פקודות על שרת חדש באמצעות ה-provisioner מסוג remote-exec. התיעוד הרשמי של HashiCorp מגדיר provisioners כמוצא אחרון. יש לכך סיבות טובות.

ה-provisioner רץ רק בעת יצירת המשאב. אם תערוך את הסקריפט, דבר לא יקרה בשרת הקיים, כיוון שמבחינת Terraform המשאב כבר תואם לקוד. שלבי ה-provisioner לעולם אינם מופיעים ב-terraform plan, לכן סקירת השינויים לא תציג אותם. אם הסקריפט נכשל, Terraform מסמן את המשאב כ-tainted, והפעולה הבאה של apply תהרוס ותקים מחדש שרת שככל הנראה היה תקין.

הכשל מתרחש גם בתזמון בעייתי. ה-provider מדווח שהשרת נוצר ברגע שה-API מאשר זאת, בעוד מערכת ההפעלה עדיין עולה ו-sshd טרם מאזין.

Error: remote-exec provisioner error
timeout - last error: dial tcp 203.0.113.10:22: connect: connection refused

ל-Ansible יש פיתוי הפוך. מודולי ענן יכולים ליצור שרתים, ועבור מספר קטן של מכונות זה עובד. מה שאתה מאבד הוא גרף התלויות וקובץ ה-state. Ansible ייצור משאב בשמחה, אך אם תמחק את המשימה מה-playbook שלך, המשאב יישאר פעיל וימשיך לחייב אותך בתשלום, כיוון ששום דבר לא תיעד שהוא היה שייך לך.

הכלל הנובע מכך הוא: תן ל-Terraform לנהל אובייקטים ש-API יוצר ומשמיד, ותן ל-Ansible לנהל את כל מה שנמצא בתוך מערכת הפעלה פעילה.

העברת האחריות, עבודה תקינה

העברת האחריות היא גבול, לא אינטגרציה. Terraform מסיים את עבודתו, מפרסם כתובת, ועוצר. 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.yml

terraform output -raw מדפיס ערך אחד ללא גרשיים וללא מעטפת JSON, וזה בדיוק מה שנדרש בתוך החלפת פקודה (shell substitution). עבור כמה שרתים, השתמשו ב-terraform output -json ובנו את ה-inventory מתוכו, שכן -raw מטפל רק במחרוזת, מספר או ערך בוליאני בודד.

כדאי לשמור על שלב ה-ping בין שני הכלים. הוא מפריד בין המצב שבו "Terraform סיפק כתובת שגויה" לבין המצב שבו "ל-playbook שלי יש באג"; שתי הבעיות הללו נראות זהות כאשר ה-playbook הוא הדבר הראשון שנוגע בשרת החדש.

קריאת מצב Terraform כ־Ansible inventory

אם אינכם מעוניינים לכתוב קובץ inventory כלל, האוסף cloud.terraform קורא את המצב ישירות.

ansible-galaxy collection install cloud.terraform

כתבו את terraform.yml לצד ה־playbook שלכם:

plugin: cloud.terraform.terraform_provider
project_path: /home/deploy/infra
ansible-inventory -i terraform.yml --graph
ansible-playbook -i terraform.yml site.yml

ישנם שני דברים שחשוב לדעת לפני שמסתמכים על כך. התוסף מריץ terraform show כנגד project_path, לכן הספרייה חייבת להיות מאותחלת מראש, אחרת התוסף ייכשל. כמו כן, הוא אינו ממציא מארחים (hosts) מתוך משאבי השרת שלכם: הוא קורא משאבי ansible_host ו־ansible_group, אותם אתם מצהירים בקוד ה־Terraform שלכם באמצעות ה־provider של Ansible. דבר לא יופיע ב־ansible-inventory --graph עד שתוסיפו אותם.

קובץ inventory גנרי ופשוט קל יותר לניפוי שגיאות ועובד עם כל provider. התוסף הופך למשתלם ברגע שה־inventory גדל מעבר למספר קטן של מכונות ועריכה ידנית מתחילה לייצר שגיאות הקלדה; זהו בדיוק השלב שבו ניהול מספר שרתי Linux ממכונת שליטה אחת הופך לזרימת עבודה ממשית ולא רק להרגל.

האם אתם באמת זקוקים ל-Terraform?

רוב האנשים שקוראים זאת אינם זקוקים לו, לפחות לא בשלב זה. Terraform מצדיק את עלותו כאשר יצירה ומחיקה של תשתית הן משימות שחוזרות על עצמן. אם הזמנתם VPS אחד דרך לוח בקרה ואתם מתכוונים להחזיק בו במשך שנתיים, Terraform מתאר פעולה שמתרחשת פעם אחת, ומוסיף קובץ state שאסור לכם לאבד.

פנו ל-Terraform כאשר אתם בונים סביבות מחדש לעיתים קרובות, כאשר סביבת ה-staging חייבת להיות זהה לחלוטין לסביבת ה-production, כאשר כמה אנשים משנים את התשתית ואתם רוצים תוכנית שניתן לבחון לפני שמוחקים משהו, או כאשר מה שאתם מנהלים חורג מעבר לשרתים וכולל רשומות DNS, מאזני עומסים וחוקי firewall שחיים בתוך ה-API של הספק.

הישארו עם Ansible בלבד כאשר השרתים הם בעלי אורך חיים ארוך ומספרם קטן, וכאשר השאלה היומית היא "האם השרת הזה מוגדר נכון" ולא "האם השרת הזה קיים". playbook יחיד שמקשיח שרת חדש מכסה את אותו שטח כמו עשר הדקות הראשונות ב-VPS חדש, עם היתרון שהוא רץ באותה צורה בשרת הבא.

סדר הלמידה נגזר מכך. Ansible מחזיר את ההשקעה כבר בשרת הראשון שבבעלותכם. Terraform מחזיר את ההשקעה בסביבה השלישית שאתם בונים מחדש.

מה משתבש בתהליך ההעברה

השרת אינו מוכן. 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 החל להאזין. המתינו לפורט במקום להוסיף פקודת sleep קבועה. ל־Ansible יש את ansible.builtin.wait_for_connection בדיוק למטרה זו; הריצו אותו כמשימה הראשונה ב־play.

מפתח המארח (host key) השתנה. השמדתם את השרת ויצרתם אותו מחדש, והשרת החדש משיב באותה כתובת עם מפתח חדש.

Host key verification failed.

הסירו את הרשומה הישנה באמצעות ssh-keygen -R 203.0.113.10. זה קורה ללא הרף כאשר Terraform מבצע בנייה מחדש, וזו סיבה טובה להימנע מבנייה מחדש של מכונות המכילות נתונים.

פקודת sudo נכשלת. fatal: [web1]: FAILED! => {"msg": "Missing sudo password"} משמעו ש־become: true דורש סיסמה במארח זה. הגדירו sudo ללא סיסמה עבור משתמש ה־deploy, או העבירו את --ask-become-pass.

Terraform רוצה להשמיד משהו שלא נגעתם בו. ה־plan מציג שינויים שלא כתבתם, מה שאומר שהתשתית בפועל סטתה מהקוד, בדרך כלל משום שמישהו שינה הגדרה בלוח הבקרה של ספק הענן. הריצו את terraform plan -refresh-only כדי לראות את ההבדל בעצמכם, ואז החליטו אם הקוד או המשאב החי שגויים. לעולם אל תבצעו apply לתוכנית הרסנית שאינכם יכולים להסביר שורה אחר שורה.

Ansible מדווח על שינוי בכל הרצה. משימת shell ללא הגנת creates או when רצה ללא תנאי. זו אינה בעיה קוסמטית בלבד, כיוון שמשמעות הדבר היא שלא ניתן עוד להשתמש ב־changed=0 כסימן לכך שהשרת נמצא במצב שביקשתם.

FAQ

האם Terraform יכול להחליף את Ansible?

לא עבור הגדרות בתוך שרת. Terraform יכול להריץ סקריפטים באמצעות ה-provisioner מסוג remote-exec, אך אלו רצים רק בעת יצירת המשאב, אינם מופיעים ב-terraform plan, וגורמים לסימון המשאב כפגום (tainted) במקרה של כשל, מה שמוביל לתזמון מחיקה ובנייה מחדש בהרצה הבאה. ל-Terraform אין מקבילה למודול שבודק אם Nginx כבר מותקן ולא מבצע דבר אם כן. השתמשו ב-Terraform כדי ליצור את המכונה, ולאחר מכן העבירו את הטיפול ל-Ansible.

האם Ansible יכול להחליף את Terraform?

עבור מספר קטן של שרתים בעלי אורך חיים ארוך, כן. ל-Ansible יש מודולי ענן ליצירת שרתים, ואם אתם מזמינים שני שרתי VPS ומחזיקים אותם לאורך זמן, זה מספיק. מה שחסר הוא קובץ ה-state וגרף התלויות: אם תסירו משימה מה-playbook, המשאב ימשיך לרוץ ולחייב אתכם בתשלום, כיוון ש-Ansible לא תיעד שהוא יצר אותו. Terraform היה מתכנן מחיקה של המשאב.

מה כדאי ללמוד קודם?

את Ansible, אם כבר יש ברשותכם שרתים. הוא מחזיר את ההשקעה כבר מהמכונה הראשונה, אינו דורש דבר מלבד SSH, והמיומנות רלוונטית גם לשרת שהזמנתם ידנית. Terraform מחזיר את ההשקעה מאוחר יותר, כאשר בונים סביבות מחדש בתדירות גבוהה או מנהלים משאבי ספק מעבר לשרתים, כגון רשומות DNS וחוקי firewall.

איך מעבירים את ה-IP של השרת החדש מ-Terraform ל-Ansible?

הגדירו output בקוד ה-Terraform שלכם, וקראו אותו לאחר ה-apply. הפקודה terraform output -raw web_ip מדפיסה את הערך הגולמי עבור החלפת משתנה ב-shell, ו-terraform output -json מציגה את כל ה-outputs בבת אחת כאשר ישנם כמה מארחים. כתבו זאת לקובץ inventory, או התקינו את ה-collection מסוג cloud.terraform והפנו את ansible-inventory -i terraform.yml --graph לספריית הפרויקט.

מדוע ה-playbook שלי נכשל מיד לאחר ש-Terraform מסיים?

הספק מדווח שהשרת נוצר ברגע שה-API שלו מאשר זאת, בעוד מערכת ההפעלה עדיין עולה, ולכן חיבורי SSH נדחים בשניות הראשונות. השגיאה היא UNREACHABLE! עם Connection refused. הפכו את ansible.builtin.wait_for_connection למשימה הראשונה ב-play במקום לנחש את משך זמן ההמתנה, כיוון שזמן העלייה משתנה בהתאם ל-image ולתוכנית.