Terraform Drift بالعربي: اكشف تغييرات البنية قبل ما تكسر الإنتاج
هتعرف هنا تعمل فحص يومي يكشف أي تغيير اتعمل خارج Terraform، قبل ما أول terraform apply يرجّعه أو يسبب downtime غير متوقع.
المشكلة باختصار
الـ drift معناه إن الواقع على AWS أو Azure أو GCP بقى مختلف عن الكود والـ state اللي Terraform شايفهم. مثال بسيط: مهندس on-call فتح AWS Console أثناء incident ووسّع CIDR في Security Group من 10.0.0.0/16 إلى 0.0.0.0/0 عشان يحل مشكلة بسرعة. الخدمة رجعت تشتغل، بس الكود لسه بيقول القيمة القديمة.
اللي بيحصل فعلاً إن Terraform عند أول plan هيقارن الكود والـ state بالواقع. حسب توثيق HashiCorp، Terraform يعمل refresh أثناء plan وapply، وده ممكن يخليك تكتشف تغييرات اتعملت خارج workflow المعتاد. المشكلة إن الاكتشاف وقت deploy متأخر. أفضل طريقة هنا إنك تعمل فحص مستقل يوميًا أو كل 6 ساعات.
الفكرة الأساسية: افصل كشف drift عن deploy
ركز في النقطة دي: فحص drift مش لازم يغير البنية. استخدم terraform plan -refresh-only عشان تشوف الفرق بين الـ state والواقع بدون تعديل الموارد نفسها. توثيق Terraform يوضح إن -refresh-only هدفه تحديث فهم Terraform للـ state والقيم الخارجة من الموارد، وليس تنفيذ تغيير على البنية.
لو عندك 3 بيئات، وكل بيئة فيها 80 resource، فحص واحد يوميًا غالبًا يكلفك من 2 إلى 8 دقائق حسب عدد providers وسرعة APIs. الرقم مش ثابت، لكنه نطاق عملي في repos متوسطة. المكسب إنك تعرف drift خلال 24 ساعة بدل ما تكتشفه وقت release.
Workflow عملي على GitHub Actions
الافتراض إن عندك Terraform داخل مجلد infra، وإن credentials متخزنة كـ GitHub Secrets. GitHub Actions يدعم on.schedule بصيغة cron، وأقصر تكرار رسميًا هو كل 5 دقائق، لكن لفحص drift اليومي مش محتاج التكرار العالي ده.
name: terraform-drift-check
on:
schedule:
- cron: "15 5 * * *"
workflow_dispatch:
jobs:
drift:
runs-on: ubuntu-latest
permissions:
contents: read
defaults:
run:
working-directory: infra
steps:
- uses: actions/checkout@v4
- uses: hashicorp/setup-terraform@v4
with:
terraform_version: "1.14.6"
terraform_wrapper: false
- name: Terraform init
run: terraform init -input=false
- name: Detect drift without changing resources
run: |
set +e
terraform plan -refresh-only -detailed-exitcode -no-color -input=false > drift.txt
code=$?
cat drift.txt
if [ "$code" = "0" ]; then
echo "No drift detected"
exit 0
fi
if [ "$code" = "2" ]; then
echo "Drift detected"
exit 1
fi
echo "Terraform failed"
exit "$code"
هنا -detailed-exitcode بيخلي الخروج أوضح: صفر يعني مفيش فرق، واثنين يعني فيه plan بتغييرات. إحنا بنحوّل الحالة 2 إلى failure مقصود عشان الفريق ياخد alert من GitHub Actions أو من تكامل Slack لاحقًا.
ماذا تعمل لما يظهر drift
- لو التغيير غلط: افتح PR يرجّع الواقع للكود، أو شغّل apply من المسار الرسمي بعد مراجعة الـ plan.
- لو التغيير كان إصلاح incident: حدّث Terraform code الأول، ثم اعمل plan عادي. متخلّيش الكونسول يبقى المصدر الحقيقي.
- لو المورد اتعمل يدويًا ومحتاج تديره: استخدم import أو import block بدل ما تسيبه خارج Terraform.
مثال واقعي: موقع عنده 50K زائر يوميًا وعدّل حد الـ autoscaling يدويًا من 6 إلى 12 instances أثناء حملة تسويقية. لو الكود لسه 6، أول apply بعد الحملة ممكن يرجّع السعة لنصفها. فحص drift اليومي هيطلع الفرق قبل ما الـ release يعمل rollback للسعة.
الـ trade-off هنا
بتكسب visibility مبكر، وسجل واضح لأي تغيير خارج المسار. بتخسر وقت CI إضافي، واحتمال false positives لو عندك موارد بتتغير طبيعيًا من provider أو autoscaler. عشان كده متتعاملش مع كل drift كأنه خطأ أمني. صنّفه: خطر، مقبول مؤقتًا، أو لازم يتحول لكود.
الطريقة دي بتفشل لو credentials بتاعت CI أوسع من اللازم. استخدم صلاحيات قراءة كافية للفحص، وفصل صلاحيات apply في workflow مختلف. ده يقلل أثر أي secret leak.
متى لا تستخدم هذه الطريقة
متستخدمهاش كبديل لمنصة IaC كاملة لو عندك عشرات الفرق ومئات الـ workspaces. في الحالة دي HCP Terraform أو Spacelift أو Atlantis مع سياسات مراجعة هيدوك governance أفضل. كمان متشغلش terraform apply -refresh-only -auto-approve تلقائيًا لمجرد إن drift ظهر؛ توثيق Terraform نفسه يحذر من استخدام refresh القديم لأنه يغيّر state بدون مراجعة كافية.
مصادر اعتمد عليها المقال
- HashiCorp: Manage resource drift
- Terraform plan command و refresh-only mode
- Terraform refresh command وتحذيراته
- GitHub Actions schedule syntax
- hashicorp/setup-terraform action
الخطوة التالية
افتح repo فيه Terraform، أضف workflow الفحص اليومي، وشغّله يدويًا من workflow_dispatch. لو فشل بكود drift، لا تعمل apply فورًا؛ اقرأ الفرق وصنّفه الأول.