הגדרת Terraform Plan/Apply אוטומטי ב-CI/CD Pipeline
Terraform מורץ ידנית מהלפטופ של מהנדס — מצב קלאסי בצוותים שבהם קוד תשתית קיים אבל תהליכים סביבו לא מבוססים. הבעיה היא לא רק חוסר אמינות (אם כי גם זה). העניין הוא ש-terraform.tfstate חי על המחשב של מישהו, apply יכול לרוץ ללא ביקורת, והיסטוריית השינויים בתשתית היא היסטוריית ה-git של אדם אחד שמבצע commit "פעם בשבוע כשאני זוכר." פרקטיקה זו מובילה ל-state drift, קונפליקטים בנעילות, וזמן השבתה לא מתוכנן. לפי HashiCorp, אוטומציה של plan/apply מפחיתה את ה-MTTR ב-70%.
במשך 7+ שנים ו-50+ פרויקטים, פיתחנו גישה שהופכת כאוס לתהליך ניתן לניהול. שילוב Terraform ב-CI/CD מבצע אוטומציה של plan על כל PR, apply לאחר אישור, ומספק היסטוריה מלאה ב-pipeline. להלן סכמה מוכחת עם state מרוחק, תגובות אוטומטיות, ואבטחת OIDC. צרו קשר לבדיקת ה-IaC שלכם — נבחן את הפרויקט שלכם.
למה לשלב Terraform ב-CI/CD?
ניהול תשתית ידני הוא דרך ישירה ל-state drift וטעויות אנוש. pipeline אוטומטי מבטיח:
- ביקורת קוד לפני כל apply — שינויים גלויים לכל הצוות.
- State מאוחסן ב-backend מרוחק מרכזי — ללא קונפליקטים או אובדן.
- היסטוריית שינויים מלאה: מי, מתי, ומה השתנה.
- Apply רק לאחר בדיקת plan מוצלחת — הגנה מפני שבירה מקרית.
הניסיון מראה: מעבר ל-GitOps ו-CI/CD עבור Terraform מפחית את זמן הפריסה ב-60% ומפחית את הסיכון לתקלות פי 3 בהשוואה לגישה הידנית.
ארכיטקטורה: איפה לאחסן State ואיך לעבוד עם Workspaces
לפני הגדרת CI/CD, יש לטפל ב-state מרוחק. S3 + DynamoDB עבור AWS, GCS עבור GCP, Azure Blob עבור Azure, או Terraform Cloud. State מקומי ב-CI הוא אנטי-פטרן — הוא מת עם ה-runner. לפי תיעוד Terraform הרשמי, state מרוחק עם נעילה הוא חובה לשיתוף פעולה בצוות.
דוגמה לתצורת backend.tf
# backend.tf
terraform {
backend "s3" {
bucket = "mycompany-terraform-state"
key = "production/main.tfstate"
region = "eu-west-1"
dynamodb_table = "terraform-state-lock"
encrypt = true
}
}# backend.tf terraform { backend "s3" { bucket = "mycompany-terraform-state" key = "production/main.tfstate" region = "eu-west-1" dynamodb_table = "terraform-state-lock" encrypt = true } } עבור State Locking הוא קריטי. ללא נעילה, שני dynamodb_table במקביל (למשל, שני PRs שמוזגים בו-זמנית) יכולים להוביל ל-state פגום או לשינויי תשתית מתנגשים.
איך להגן על סביבת הייצור במהלך Apply אוטומטי?
עיקרון מפתח — סכמה דו-שלבית: plan אוטומטי, apply ידני עם הרשאות ייצור. אנו מוסיפים terraform apply לשלב ה-apply ומשתמשים ב-when: manual להפרדת גישה. בנוסף, RBAC ב-GitLab/GitHub מוגדר כך שרק משתמשים מסוימים יכולים לאשר apply.
עבור שינויים קריטיים (מחיקת משאבים), ניתן להוסיף כללי אישור — למשל, לבקש אישור נפרד ממנהל הצוות.
Pipeline: Plan על PR, Apply לאחר Merge
סכמה דו-שלבית סטנדרטית עם validate:
# .gitlab-ci.yml
stages:
- validate
- plan
- apply
terraform:validate:
stage: validate
image: hashicorp/terraform:1.7
script:
- terraform init -backend=false
- terraform validate
- terraform fmt -check -recursive
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
- if: $CI_COMMIT_BRANCH == "main"
terraform:plan:
stage: plan
image: hashicorp/terraform:1.7
script:
- terraform init
- terraform plan -out=tfplan -var-file="environments/${ENV}/terraform.tfvars"
- terraform show -json tfplan > tfplan.json
artifacts:
paths:
- tfplan
- tfplan.json
expire_in: 1 week
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
- if: $CI_COMMIT_BRANCH == "main"
terraform:apply:
stage: apply
image: hashicorp/terraform:1.7
script:
- terraform init
- terraform apply -auto-approve tfplan
dependencies:
- terraform:plan
rules:
- if: $CI_COMMIT_BRANCH == "main"
when: manual
environment:
name: production
environment: production על apply הוא חובה לייצור. Plan רץ אוטומטית, apply דורש לחיצת כפתור מאדם עם ההרשאות המתאימות.
איך להגדיר תגובה אוטומטית של תוצאות Plan ב-Pull Request?
הדבר הכי valuable ב-terraform pipeline הוא לראות את ה-diff ישירות ב-PR, מבלי ללכת ל-CI. לשם כך, אנו משתמשים ב-Atlantis או בסקריפט מותאם עם GitHub/GitLab API. Atlantis מספק פידבק מהיר פי 2 בזכות תגובות בזמן אמת בהשוואה לפתרונות מובנים.
ב-GitHub Actions באמצעות # .gitlab-ci.yml stages: - validate - plan - apply terraform:validate: stage: validate image: hashicorp/terraform:1.7 script: - terraform init -backend=false - terraform validate - terraform fmt -check -recursive rules: - if: $CI_PIPELINE_SOURCE == "merge_request_event" - if: $CI_COMMIT_BRANCH == "main" terraform:plan: stage: plan image: hashicorp/terraform:1.7 script: - terraform init - terraform plan -out=tfplan -var-file="environments/${ENV}/terraform.tfvars" - terraform show -json tfplan > tfplan.json artifacts: paths: - tfplan - tfplan.json expire_in: 1 week rules: - if: $CI_PIPELINE_SOURCE == "merge_request_event" - if: $CI_COMMIT_BRANCH == "main" terraform:apply: stage: apply image: hashicorp/terraform:1.7 script: - terraform init - terraform apply -auto-approve tfplan dependencies: - terraform:plan rules: - if: $CI_COMMIT_BRANCH == "main" when: manual environment: name: production :
---
- name: Terraform Plan
uses: dflook/terraform-plan@v1
with:
path: infrastructure/
var_file: |
environments/production/terraform.tfvars
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}ה-action מוסיף אוטומטית תגובה ל-PR עם פלט ה-when: manual המלא: מה יתווסף, ישתנה, יימחק. ב-commits הבאים לענף, התגובה מתעדכנת, לא נוצרת מחדש.
Atlantis לעבודת צוות — הגדרת Terraform אוטומטית
אם הצוות גדול וזקוק ל-workflow מלא עם פקודות dflook/terraform-github-actions ו-- name: Terraform Plan uses: dflook/terraform-plan@v1 with: path: infrastructure/ var_file: | environments/production/terraform.tfvars env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} ישירות מתגובות PR — Atlantis מתמודד עם זה out of the box. הוא רץ כשירות נפרד (Helm chart בקלאסטר או VM עצמאי), נרשם ל-GitHub/GitLab webhooks.
---
# atlantis.yaml version: 3
projects:
- name: production
dir: infrastructure/environments/production
workspace: production
autoplan:
when_modified: ["*.tf", "../modules/**/*.tf"]
enabled: true
apply_requirements: [approved, mergeable]
---terraform plan — apply בלתי אפשרי ללא אישור PR וסטטוס "mergeable" (כל הבדיקות הנדרשות עברו).
| מאפיין | Atlantis | GitLab CI native |
|---|---|---|
| התקנה | Helm chart / עצמאי | מובנה ב-GitLab |
| תגובות PR | /atlantis plan |
דרך API (dflook/action) |
| בקרת גישה | /atlantis apply |
# atlantis.yaml version: 3 projects: - name: production dir: infrastructure/environments/production workspace: production autoplan: when_modified: ["*.tf", "../modules/**/*.tf"] enabled: true apply_requirements: [approved, mergeable] + RBAC |
| תמיכה במספר repos | out of the box | דורש הגדרה לכל repo |
| OIDC | דרך IAM role | דרך GitLab CI variables |
אבטחה: אישורים ב-CI
אישורי AWS סטטיים ב-CI Variables מקובלים להתחלה, אבל האפשרות הטובה ביותר היא שילוב OIDC. מערכת ה-CI מקבלת token זמני דרך OIDC וממירה אותו ל-IAM role באמצעות apply_requirements: [approved, mergeable]. ללא סודות ארוכי טווח.
---
- name: Configure AWS credentials via OIDC
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::123456789:role/github-actions-terraform
aws-region: eu-west-1
---ה-IAM role מוגדר עם trust policy המוגבל ל-repo וענף ספציפיים. ה-token חי למשך שעה ולא יכול לדלוף מה-pipeline.
מה כלול בעבודה (תוצרים)
| שלב | תוצאה |
|---|---|
| בדיקת IaC קיים | דוח עם המלצות, הערכת state drift |
| הגדרת state מרוחק | S3/DynamoDB או מקביל עם נעילה, גיבויים |
| Pipeline (validate+plan+apply) | CI/CD עובד במערכת שלכם |
| שילוב OIDC | IAM role, trust policy, tokens |
| תגובות אוטומטיות | הודעות PR עם diff |
| תיעוד והדרכה | README, runbook, מפגש של שעתיים |
| אחריות | תמיכה חינם למשך חודש לאחר היישום |
לוח זמנים ואיך להתחיל
שילוב plan/apply בסיסי ב-GitLab CI עם state מרוחק — מיום אחד. הגדרה עם Atlantis, OIDC, תגובות אוטומטיות, ואסטרטגיית workspaces לסביבות מרובות — מיומיים עד 3 ימים. העלות מחושבת באופן אישי לאחר בדיקת תשתית ה-IaC הנוכחית שלכם. קבלו ייעוץ — המהנדסים שלנו יעריכו את הפרויקט שלכם ויציעו את הפתרון האופטימלי.







