Terraform Drift: اكشف تغييرات السحابة قبل apply
هتطلع من المقال بخطوة عملية تكشف أي تغيير يدوي حصل في السحابة قبل ما يتحول لمفاجأة وقت deploy.
مستوى القارئ: متوسط
المشكلة باختصار
الـ Terraform state مش دايمًا مرآة كاملة للواقع. لو حد عدّل Security Group من AWS Console، أو غيّر حجم instance أثناء incident، الكود عندك يفضل شكله سليم. اللي بيحصل فعلاً إن أول terraform apply بعد كده يكتشف الفرق متأخر.
في فريق عنده 40 خدمة و3 بيئات، مراجعة شهرية واحدة ممكن تسيب drift لمدة 720 ساعة. فحص يومي يقلل نافذة الاكتشاف إلى 24 ساعة. ولو شغّلته على كل Pull Request، ممكن تشوف المشكلة خلال أقل من ساعة من تغيير الكود.
مثال بسيط قبل التعريف العلمي
ركز في المثال ده. عندك rule في Terraform بتسمح لـ 443 فقط. أثناء incident، حد فتح 22 مؤقتًا من AWS Console عشان يدخل على VM. المشكلة مش في فتحه وقت الطوارئ. المشكلة إنه نسي يرجّعها.
بعد أسبوع، deploy جديد يعمل terraform plan. Terraform يشوف إن الواقع مختلف عن الكود، ويقترح حذف rule الخاصة بـ 22. ده كويس، لكن الاكتشاف جاء وقت تغيير إنتاج. أفضل طريقة إنك تعرف drift ده في نفس اليوم، برسالة واضحة، بدون ما تعمل apply تلقائي.
تعريفًا: Terraform drift هو اختلاف بين التكوين المكتوب في ملفات .tf، والـ state، وحالة الموارد الحقيقية عند مزود السحابة. حسب توثيق Terraform، أمر plan يقرأ حالة الموارد الموجودة ويقارنها بالتكوين الحالي قبل اقتراح أي تغييرات.
الحل: GitHub Actions يعمل plan كتنبيه فقط
استخدم Workflow مجدول. الهدف هنا مش الإصلاح التلقائي. الهدف إن الـ CI يقول لك: فيه فرق محتاج مراجعة. الافتراض إن عندك remote backend مضبوط، وصلاحيات قراءة كافية لمزود السحابة، وTerraform version مثبت في المشروع.
name: terraform-drift-check
on:
schedule:
- cron: "15 5 * * *"
workflow_dispatch:
permissions:
contents: read
pull-requests: write
jobs:
drift:
runs-on: ubuntu-latest
defaults:
run:
working-directory: infra
steps:
- uses: actions/checkout@v4
- uses: hashicorp/setup-terraform@v3
with:
terraform_version: 1.8.5
- name: Init
run: terraform init -input=false
- name: Plan drift
id: plan
continue-on-error: true
run: terraform plan -no-color -detailed-exitcode -out=tfplan
- name: Fail only on Terraform error
if: steps.plan.outcome == 'failure' && steps.plan.outputs.exitcode == '1'
run: exit 1
- name: Report drift
if: steps.plan.outcome == 'failure'
run: |
echo "Terraform drift detected. Review the plan before apply."
terraform show -no-color tfplan | sed -n '1,120p'