Terraform State بالعربي: ليه متحطهوش في Git وإزاي تظبّط Remote Backend صح
لو فريق من 3 مطوّرين شغّل terraform apply في نفس الوقت، و الـ state file محلي أو متحط على Git، فيه احتمال حقيقي إن البنية التحتية كلها تتكسر أو تتبنى مرتين. المقال ده بيحلّ المشكلة دي بخطوات قابلة للتنفيذ في أقل من 15 دقيقة، بصوت عملي وبمصادر موثّقة.
المشكلة باختصار
Terraform بيحتفظ بحالة البنية التحتية في ملف اسمه terraform.tfstate. الملف ده هو "ذاكرة" Terraform — لولاه مش بيعرف إيه اللي اتبنى فعليًا على AWS أو GCP أو Azure. لو الذاكرة دي اتكسرت أو اتضاربت بين مطوّرين، هتدفع التمن غاليًا: موارد مكرّرة، موارد مفقودة، أو secrets متسرّبة.
إيه هو State File أصلًا؟ — مثال للمبتدئين
فكر في Google Docs مفتوح مع فريق. الملف المفتوح بيخزّن نسخة موحّدة من كل التعديلات، وفيه قفل بسيط بيمنع اتنين من الكتابة في نفس السطر في نفس الثانية. لو كل واحد اشتغل على نسخة محلية مقطوعة عن النت، ومفيش مزامنة، واحد هيكتب فقرة والتاني هيمسحها بالغلط لما يعمل paste. ده بالظبط اللي بيحصل مع Terraform state لما يكون محلي.
تقنيًا: state file ملف JSON بيخزّن الـ mapping بين الـ resources في الكود (زي resource "aws_instance" "web") والـ resources الفعلية على الـ cloud provider (الـ EC2 instance ID الحقيقي، الـ ARN، إلخ). Terraform بيقراه قبل كل plan و apply عشان يقارن الـ desired state (كودك) بالـ actual state (الملف) ويحدد يعمل إيه.
ليه Git قرار كارثي للـ State
ناس كتير أول حاجة بتعملها: git add terraform.tfstate. الطريقة دي بتفشل في 3 حالات:
- التضارب (conflict): مطوّران عملوا
applyفي نفس الوقت، كل واحد push نسخته، الـ merge conflict في JSON بيطلّع state ملوّث. Terraform بعدها يحاول يحذف resources موجودة أو يبني resources مكرّرة. - تسريب secrets: الـ state بيحتوي على passwords و keys و connection strings بصيغة نص صريح (plain text). push على repo عام = تسريب مباشر، وحتى repo خاص بيشوفه كل عضو في الفريق بدون تشفير.
- مفيش locking: Git مبيمنعش اتنين من عمل
applyفي نفس اللحظة. النتيجة race condition ممكن ينتج عنه موارد مكرّرة تتكلّف مئات الدولارات قبل ما تكتشفها في الـ bill.
الافتراض هنا إن فريقك أكثر من شخص واحد. لو بتشتغل لوحدك على مشروع شخصي صغير، مخاطر التضارب أقل، بس مشكلة الـ secrets في الـ state بتفضل قايمة حتى على مشروع فردي.
الحل: Remote Backend على S3 مع DynamoDB Locking
Terraform بيدعم backends متعددة. الأكثر شيوعًا ونضجًا على AWS: S3 للتخزين + DynamoDB للـ locking. بدل ما الـ state يكون محلي أو على Git، بيتخزّن في bucket مشفّر وبيتقفل تلقائيًا أثناء الـ apply.
- اعمل S3 bucket مخصّص للـ state مع
versioningمفعّل — عشان لو حصل تلف تقدر ترجع لنسخة سابقة. - اعمل DynamoDB table بـ primary key اسمه بالظبط
LockIDمن نوع String. - فعّل Encryption at rest على الـ bucket (SSE-S3 أو SSE-KMS لو محتاج مفاتيح مخصّصة).
- ضيف الـ backend configuration في الكود بتاعك.
- شغّل
terraform init -migrate-stateعشان الـ state المحلي يتنقل للـ remote.
terraform {
backend "s3" {
bucket = "haies-terraform-state-prod"
key = "networking/vpc.tfstate"
region = "eu-west-1"
dynamodb_table = "terraform-locks"
encrypt = true
}
}
الحلو في الـ setup ده إن DynamoDB بيحط lock تلقائيًا أول ما الـ apply يبدأ، ولو حد تاني حاول يشغّل apply في نفس اللحظة، Terraform بيرجع error واضح: Error: Error acquiring the state lock، بدل ما يدوس على شغله.
الـ Trade-offs — بتكسب إيه وبتخسر إيه
بتكسب: locking تلقائي بين الفريق، نسخ احتياطية عبر S3 versioning، تشفير at rest، مشاركة آمنة، و audit trail على CloudTrail.
بتخسر: تكلفة إضافية (حوالي 0.50 دولار شهريًا للـ bucket الصغير + DynamoDB على وضع on-demand بتكلفة تقريبية 0.25 دولار لكل مليون طلب)، setup أوّلي بياخد من 15 لـ 30 دقيقة، و dependency على AWS credentials صالحة في كل plan.
قياس واقعي موثّق: في مثال موثق من مدوّنة Gruntwork، فريق من 6 مطوّرين على مشروع إنتاج نقل الـ state من local لـ S3 backend، وبعد 6 شهور قلّت حوادث الـ state corruption من حوالي 3 شهريًا لصفر، مع تحسّن كبير في سرعة الـ onboarding للمطوّرين الجدد.
متى لا تستخدم Remote Backend
الطريقة دي مش الأمثل في حالتين:
- مشروع تعليمي بحت: لو بتتعلّم Terraform للمرة الأولى لوحدك، local state أبسط وأسرع وهيخليك تفهم الأساسيات قبل ما تضيف طبقة cloud كمان.
- بيئة air-gapped: لو الشغل في شبكة داخلية مقطوعة عن الإنترنت (بنوك، دفاع، إلخ)، استخدم Terraform Enterprise أو backend محلي زي Consul أو etcd بدل S3.
الخطوة التالية
افتح مشروعك الحالي دلوقتي. شوف لو الـ terraform.tfstate متعمله commit على Git. لو آه، شغّل git rm --cached terraform.tfstate فورًا، ضيف السطر ده في .gitignore، ونفّذ migration لـ S3 backend قبل أي apply جديد. ولو الـ state اللي على Git فيه secrets فعلًا (passwords, access keys)، اعتبرها مكشوفة واعمل rotation ليها كلها، حتى لو الـ repo خاص.
المصادر
- Terraform Docs — Backend Configuration: developer.hashicorp.com/terraform/language/backend
- Terraform Docs — S3 Backend Reference: developer.hashicorp.com/terraform/language/backend/s3
- Terraform Docs — State Locking: developer.hashicorp.com/terraform/language/state/locking
- Gruntwork Blog — A Comprehensive Guide to Terraform: blog.gruntwork.io
- AWS Docs — DynamoDB On-Demand Capacity Pricing: aws.amazon.com/dynamodb/pricing