מדוע Terraform זקוק לקובץ state במקום לשאול את הענן בכל הרצה?
State ממפה כתובות תצורה (`aws_instance.web`) למזהי משאבים אמיתיים, עוקב אחר תלויות, ומטמון מטא-דאטה. בלעדיו, Terraform לא יכול לדעת אילו משאבי ענן הוא מנהל לעומת אילו נוצרו במקום אחר.
Terraform מקצה משאבי ענן (VMs, רשתות, IAM). Ansible/Chef/Puppet מגדירים תוכנה בתוך ה-VMs. הם משלימים, לא מתחרים.
חברה המשתמשת ב-AWS בלבד דנה בין CloudFormation ל-Terraform.
ל-CloudFormation אינטגרציה הדוקה יותר עם AWS, rollback מובנה ואפס ניהול קבצי state. Terraform מנצח במולטי-קלאוד, מערכת אקולוגית מודולים גדולה יותר וארגונומיית HCL. בחר CFN אם AWS בלבד ו-rollback חשוב ביותר; אחרת Terraform.
מוריד ספקים לפי `required_providers`, מאתחל את ה-backend, מוריד מקורות מודולים, וכותב `.terraform/` בתוספת `.terraform.lock.hcl`. נדרש לפני `plan` או `apply`.
ה-CI מריץ `terraform init` שוב ושוב על פני פרויקטים רבים, כשכל אחד מהם מוריד את אותם ספקים מאפס.
הגדר `TF_PLUGIN_CACHE_DIR` (או `plugin_cache_dir` בקובץ התצורה של ה-CLI). ספקים מורדים פעם אחת ומקושרים (symlinked) לתוך ספריות `.terraform/` ספציפיות לכל פרויקט.
`<hostname>/<namespace>/<type>` - לדוגמה `registry.terraform.io/hashicorp/aws`. שם המארח מושמט כברירת מחדל ל-Terraform Registry הציבורי. Namespace = ספק. Type = שם הספק.
למה: סודות סטטיים ארוכי טווח בתצורה הם הגורם העיקרי לאירועי דליפת אישורים.
היכן הגדרות ברמה העליונה ממוקמות?
בלוק `terraform { ... }` מכיל `required_version`, `required_providers`, `backend`, `cloud`, ו-experiments. מספר בלוקי `terraform` על פני קבצים מתמזגים.
שימוש ב-Terraform מחוץ לזרימת העבודה המרכזית
משאב קיים ב-state אך לא אמור להיות מנוהל על ידי Terraform יותר; משאב הענן חייב להמשיך לפעול.
`terraform state rm <addr>`. מסיר מה-state מבלי להרוס את משאב הענן.
צריך לייבא משאבים רבים באופן שניתן לשחזור דרך CI ולא באמצעות פקודות CLI אד-הוק.
השתמש בבלוק `import` (Terraform 1.5+): `import { to = aws_s3_bucket.legacy, id = "legacy-bucket-name" }`. הייבוא מתרחש במהלך `apply`, מנוהל גרסאות ועובד בפלט ה-plan.
`terraform state list` מציג את כל כתובות המשאבים. `terraform state show <addr>` מציג תכונות עבור משאב אחד. עבור משאבים עם אינדקס השתמש במרכאות: `terraform state show 'aws_instance.web[0]'`.
נתיב מקומי → `./modules/vpc`. רישום ציבורי → `terraform-aws-modules/vpc/aws`. Git → `git::https://github.com/org/repo.git//path?ref=v1.0`. S3/HTTP/Mercurial נתמכים גם.
שתי תבניות: (1) Workspaces עם תצורת שורש אחת + `*.tfvars` לכל workspace. (2) תצורות שורש לכל סביבה (`envs/dev/main.tf`, `envs/prod/main.tf`) שכל אחת מהן קוראת למודולים משותפים. תבנית 2 נפוצה יותר עבור בידוד מרובה צוותים.
שימוש בזרימת העבודה המרכזית של Terraform
ודא ש-CI מיישם בדיוק את מה שנבדק ב-plan, ללא סחף בין השלבים.
`terraform plan -out=tfplan` שומר את ה-plan. ואז `terraform apply tfplan` מיישם את ה-plan המדויק הזה. סירוב לתכנן מחדש מבטל סיכון של זמן בדיקה/זמן שימוש.
משאב A חייב להתקיים לפני משאב B, אך B אינו מפנה לתכונות של A.
הוסף `depends_on = [resource_a.name]` ל-B. השתמש רק כאשר הפניות תכונה מרומזות אינן יכולות לבטא את התלות (לדוגמה, מדיניות IAM חייבת להתפשט לפני ש-EC2 משתמש בה).
Workspaces - `terraform workspace new staging`, `terraform workspace select prod`. לכל אחד קובץ state משלו. התייחסות באמצעות `terraform.workspace` ב-HCL.
S3: אפשר SSE-KMS בדלי. Azure: הצפנת חשבון אחסון (מופעלת כברירת מחדל). GCS: מפתחות הצפנה מנוהלים על ידי לקוח. HCP Terraform: מוצפן באופן טבעי במנוחה.
מהנדס הפעיל בטעות `terraform destroy` נגד פרודקשן. ה-state כעת ריק.
שחזר את הגרסה הקודמת של קובץ ה-state מניהול גרסאות S3, ואז הפעל `terraform plan` כדי לראות מה Terraform חושב כעת שצריך ליצור/לייבא. שלב עם שחזור צד ענן (תמונות מצב, `aws backup`) עבור המשאבים שנהרסו.
קובץ ה-state נראה שגוי; מתפתה לערוך אותו ישירות.
אל תעשה זאת. השתמש בפקודות המשנה `terraform state` (`mv`, `rm`, `replace-provider`, `pull`, `push`). עריכות JSON ידניות מדלגות על בדיקות תקינות ומשחיתות את המקור.
בדוק JSON state מרוחק גולמי, או דחוף קובץ state ששוחזר.
`terraform state pull` כותב את ה-state המרוחק הנוכחי ל-stdout. `terraform state push <file>` דורס את המרוחק עם הקובץ הנתון. Push הוא הרסני - גבה תחילה.
העברת אסימון API זמני דרך Terraform מבלי שהוא ינחת ב-state.
סמן את המשתנה `ephemeral = true` (Terraform 1.10+). ערכים זמניים לעולם אינם נשמרים ב-state או בקבצי plan. כדי לייצא דרך פלט מודול, סמן גם את הפלט `ephemeral = true`.
למה: `sensitive` מוסתר ב-CLI אך מאוחסן ב-state בטקסט רגיל. `ephemeral` באמת לעולם אינו מאוחסן.
ההבדל בין ארגומנט `sensitive` לארגומנט write-only (לדוגמה, `password_wo`).
`sensitive` מאוחסן ב-state בטקסט רגיל, רק מוצפן ב-CLI. Write-only **לעולם** אינו מאוחסן ב-state. כדי לזהות שינויים בתכונות write-only, Terraform משתמש בשדה גרסה נלווה (לדוגמה, `password_wo_version`).
צטט את הכתובת: `terraform state show 'aws_instance.web[0]'`. ללא מרכאות, ה-shell עשוי לפרש את הסוגריים.
צוותים שונים צריכים לפעול באופן עצמאי מבלי לדרוס זה את ה-state של זה.
קובץ state אחד לכל צוות (או לכל סביבה לכל צוות). backends/buckets נפרדים. השתמש במקור נתונים `terraform_remote_state` כדי לקרוא state אחר בגישת קריאה בלבד.
תצורה שנכתבה מול Terraform 0.13; רוצה להשתמש ב-1.x.
קבצי State הם forward-compatible: 1.x קורא state של 0.13. HashiCorp ממליצה על שדרוגים מצטברים (0.13 ← 0.14 ← … ← 1.x) והרצת כל גרסה מול ה-state.
מישהו שינה קבוצת אבטחה דרך הקונסולה; רוצה ש-Terraform יאשר מחדש או יקבל את המצב החדש.
אישור מחדש: `terraform apply` - Terraform חוזר לתצורה. קבלה: עדכן את ה-HCL כדי להתאים למציאות, ואז בצע apply (אין diff). זיהוי ראשוני באמצעות `terraform plan -refresh-only`.
קריאה, יצירה ושינוי תצורה
הקלדה חזקה של משתנה.
פרימיטיבים: `string`, `number`, `bool`. אוספים: `list(<type>)`, `set(<type>)`, `map(<type>)`. מבניים: `object({...})`, `tuple([...])`. השתמש ב-`any` רק כאשר פולימורפי באמת.
הוצאת סיסמת מסד נתונים מבלי שהיא תופיע ב-`terraform output`.
`output "db_password" { value = ...; sensitive = true }`. ה-CLI מציג `(sensitive value)`. עדיין קריא באמצעות `terraform output db_password` או `-json` (בכוונה - עבור סקריפטים).
`for_each` (עם map או set) כאשר לפריטים יש זהות יציבה (שמות אזורים, מפתחות סביבה). `count` עבור "אני צריך N עותקים, הסדר לא משנה, הזהות היא רק אינדקס". הוספה/הסרה באמצע `count` גורמת להרס/יצירה מחדש; `for_each` שומרת על זהות.
`for_each = toset(["a", "b", "c"])`. `each.key` ו-`each.value` שניהם נותנים את המחרוזת. עבור מפות: `for_each = var.users` - `each.key` = מפתח מפה, `each.value` = ערך מפה.
`remote-exec` provisioner בתוך משאב. כלי מוצא אחרון - העדף cloud-init, user data, או configuration management. Provisioners אינם מתועדים ב-state ואינם רצים שוב בעת סחף.
מונע VCS (תכנון אוטומטי בדחיפת Git, הנפוץ ביותר). מונע CLI (מפתח מריץ `terraform plan/apply` מקומית, HCP מחזיק ב-state). מונע API (הרצות Terraform מופעלות על ידי API, משמשות מערכות אוטומציה/CD).
אכוף שכל דליי ה-S3 יהיו מוצפנים, חוסם apply אם מופר.
מדיניות Sentinel עם אכיפה קשיחה-חובה. בודקת את ה-plan; כישלון חוסם apply. מדיניות רכה-חובה מאפשרת עקיפה על ידי מנהל. מדיניות ייעוצית רק מתעדת אך לעולם אינה חוסמת.