Terraform S3 Lockfile: قفل الـ state بدون DynamoDB
مستوى القارئ: متوسط
هتطلع من المقال بإعداد عملي يخلي Terraform يمنع تشغيلين apply في نفس الوقت على نفس الـ state، من غير ما تضيف DynamoDB table جديدة.
المشكلة باختصار
لو عندك فريق صغير أو متوسط بيستخدم Terraform مع AWS، غالبًا الـ state موجود على S3. المشكلة مش في التخزين. المشكلة في اللحظة اللي CI job وواحد من الفريق يشغلوا terraform apply مع بعض.
اللي بيحصل فعلاً إن كل عملية ممكن تقرأ نفس النسخة من terraform.tfstate، وبعدها تكتب تغييرات مختلفة. النتيجة: drift، موارد orphaned، أو apply ناجح شكله طبيعي لكنه كسر الواقع. Terraform عنده state locking عشان يمنع ده، ولو الـ backend بيدعم القفل فالأوامر اللي ممكن تكتب في state بتقف لو القفل مش متاح.
الافتراض هنا إنك شغال على Terraform مع S3 backend، وعندك بيئة AWS واحدة أو أكثر، وعدد التشغيلات المتزامنة قليل نسبيًا: مثل 5 إلى 30 pipeline في اليوم. لو عندك platform team كبير ومئات التشغيلات اليومية، اقرأ قسم متى لا تستخدم قبل التنفيذ.
الفكرة: ملف .tflock جنب الـ state
قبل فترة طويلة، الإعداد الشائع كان S3 لتخزين الـ state وDynamoDB للقفل. الطريقة دي شغالة، لكنها بتضيف مورد إضافي، IAM permissions إضافية، وشرح أطول لأي مهندس جديد يدخل المشروع.
في S3 backend الحالي، HashiCorp بتوثق خيار use_lockfile = true لتفعيل قفل مبني على ملف داخل نفس bucket. كمان توثيق S3 backend بيقول إن DynamoDB-based locking deprecated وسيتم إزالته في إصدار minor مستقبلي. ركز: deprecated لا تعني إنه اتكسر النهارده، لكنها إشارة واضحة إنك ما تبدأش مشروع جديد عليه.
مثال بسيط: بدل ما تعمل table اسمها terraform-locks وفيها partition key باسم LockID، Terraform يكتب lock file بجانب مسار الـ state. لو Runner A ماسك القفل، Runner B هيستنى أو يفشل حسب إعدادات الأمر.
الإعداد العملي
أفضل طريقة للمشاريع الجديدة على AWS هي S3 backend مع versioning وuse_lockfile. versioning مهم لأن ملف الـ state حساس. AWS بتوضح إن S3 Versioning بيساعدك ترجع نسخة سابقة لو حصل overwrite أو delete غير مقصود.
terraform {
required_version = ">= 1.10.0"
backend "s3" {
bucket = "acme-prod-terraform-state"
key = "prod/network/terraform.tfstate"
region = "eu-central-1"
encrypt = true
use_lockfile = true
}
}
بعد تعديل ملف الـ backend، شغل: