الحالة البعيدة والخلفيات
الحالة البعيدة والخلفيات
في الدرس السابق تعلّمت ما هي حالة Terraform ولماذا توجد. بشكل افتراضي، يكتب Terraform تلك الحالة إلى ملف باسم terraform.tfstate على قرصك المحلي. هذا يعمل للتعلم — ولا شيء آخر تماماً. في اللحظة التي يلمس فيها مهندس ثانٍ نفس البنية التحتية، أو تُنفّذ عملية تشغيل CI، تُسبّب الحالة المحلية انقساماً في المشهد: يمتلك مشغّلان كل منهما نظرة مختلفة للواقع، وقد يُدمّر الـ apply التالي موارد أنشأها الآخر بصمت. تحلّ الخلفيات البعيدة هذا المشكل بتخزين الحالة في موقع مشترك ودائم — والأهم — بإضافة آلية قفل بحيث تستطيع عملية واحدة فقط تعديل الحالة في وقت واحد.
يغطي هذا الدرس الخلفيتَين اللتين ستصادفهما في كل مؤسسة إنتاجية تقريباً (S3 مع قفل DynamoDB، وخلفيات HTTP)، وكيف يعمل قفل الحالة وما يحدث عند فشله، وكيفية التعامل مع البيانات الحساسة التي تكتبها Terraform حتماً في الحالة.
لماذا الحالة البعيدة غير قابلة للتفاوض في الفرق
تنهار الحالة المحلية بثلاث طرق مختلفة تحتاج كل منها إلى حادثة مؤلمة لتتعلمها:
- لا مشاركة: مهندس ثانٍ يستنسخ المستودع لا يملك ملف الحالة. أول
terraform planله يُظهر كل مورد على أنه "سيُنشأ" — بنية تحتية موجودة بالفعل في السحابة. - لا قفل: مهمتا CI تُشغّلان في وقت واحد تستطيعان قراءة نفس الحالة، وحساب خطة، ثم الكتابة مجدداً — مع أن الكتابة الثانية تُلغي الأولى بصمت. تُترك الموارد يتيمة دون سجل في الحالة.
- لا متانة: فشل قرص الحاسوب المحمول أو مستودع
.gitتالف يعني ضياع الحالة. مقارنة ما تعتقد Terraform أنه موجود مقابل ما تملكه السحابة فعلاً هو تمرين جنائي يستغرق أياماً.
خلفية S3 + DynamoDB
هذا هو المعيار الفعلي للبنية التحتية المبنية على AWS. تُخزَّن الحالة ككائن JSON في حاوية S3 (مع تمكين الإصدار والتشفير من جهة الخادم). يُوفّر القفلَ جدولُ DynamoDB بسمة نصية واحدة باسم LockID. عند بدء عملية Terraform، تكتب عنصر قفل إلى DynamoDB؛ عند انتهائها (نجاحاً أو فشلاً)، تحذف العنصر. أي عملية متزامنة تحاول كتابة نفس عنصر القفل تحصل على فشل في التحقق الشرطي من DynamoDB وتخرج Terraform بخطأ بدلاً من المتابعة بدون قفل.
مع تهيئة الحاوية والجدول، اضبط الخلفية في وحدة Terraform الجذر. تقع إعدادات الخلفية في كتلة terraform {} ولا يمكنها الإشارة إلى متغيرات أو محليات — يجب أن تكون القيم سلاسل ثابتة. هذا مقصود: تحتاج Terraform لحل الخلفية قبل تقييم أي شيء آخر في الإعداد.
key هو مسار كائن S3 داخل الحاوية. نظام تسمية مسطح (prod.tfstate) يصبح غير قابل للصيانة على نطاق واسع. استخدم تسلسلاً يعكس شجرة خدماتك: <team>/<service>/<environment>/terraform.tfstate. تُفصل كثير من المؤسسات أيضاً طبقات الشبكة والحوسبة والبيانات في ملفات حالة مستقلة حتى لا يتمكن وحدة حوسبة معطوبة من إفساد حالة الشبكة. هذا هو مبدأ "عزل الحالة" وهو أحد أكثر القرارات الهيكلية تأثيراً ستتخذها في مشروع Terraform.قفل الحالة: كيف يعمل وماذا تفعل عند انهياره
كل أمر Terraform يمكنه تعديل الحالة — apply وdestroy وstate mv وimport — يكتسب قفلاً قبل البدء. الأوامر التي تقرأ الحالة فقط — plan وoutput وshow — لا تكتسب قفلاً بشكل افتراضي. يحتوي سجل القفل المخزن في DynamoDB على نوع العملية، واسم الجهاز، وإصدار Terraform، والطابع الزمني.
terraform force-unlock بينما apply آخر قيد التقدم فعلاً، فقد أزلت الضمانة الوحيدة للتزامن. ستقرأ العملية التالية حالة قديمة، وتحسب خطة غير صحيحة، وقد تحذف أو تُعيد إنشاء موارد كانت العملية الأولى تُعدّلها. تأكد دائماً أن عملية القفل ميتة (تحقق من حالة مهمة CI، اتصل بالمهندس) قبل إلغاء القفل. على الأقل، انتظر 10 دقائق بعد الطابع الزمني للقفل.خلفيات HTTP (GitLab، Terraform Cloud، مخصصة)
خلفية HTTP هي واجهة عامة: تُنفّذ Terraform طلبات GET وPOST (تحديث) وDELETE (إلغاء قفل) ضد أي خادم HTTP يُطبّق البروتوكول. يمتلك GitLab CI/CD خلفية حالة HTTP مدمجة (واحدة لكل مشروع، لكل بيئة)، مما يجعله الاختيار الافتراضي للمؤسسات الموجودة بالفعل على GitLab. يستخدم Terraform Cloud وHCP Terraform بروتوكولاً متوافقاً مع HTTP تحت الغطاء.
البيانات الحساسة في الحالة: الواقع الإنتاجي
حالة Terraform ليست جرداً بسيطاً. إنها تُخزّن كل خصائص كل مورد مُدار — بما فيها تلك التي يُعلّمها مزود السحابة كحساسة. مثيل RDS المُنشأ حديثاً يكتب كلمة مرور المدير بنص عادي في الحالة. مفتاح وصول IAM يكتب secret بنص عادي. مورد شهادة TLS يكتب المفتاح الخاص. هذا ليس خللاً في Terraform؛ إنه نتيجة حتمية لإدارة البنية التحتية المتوازنة: تحتاج Terraform معرفة القيمة الحالية لتقرر ما إذا كانت تحتاج للتغيير.
- شفّر الحالة أثناء الراحة: مكّن دائماً SSE في S3 (AES256 أو AWS KMS بمفتاح يديره العميل). للبيئات المنظّمة بشكل صارم، استخدم KMS CMK حتى تستطيع تدقيق وتدوير مفتاح التشفير بشكل مستقل.
- قيّد الوصول بـ IAM: الأدوار التي تُشغّل Terraform فقط يجب أن تملك
s3:GetObjectوs3:PutObjectوdynamodb:PutItemعلى حاوية الحالة وجدول القفل. يجب ألا يمتلك المهندسون وصولاً مباشراً إلى حاويات S3 الإنتاجية — يجب أن يتفاعلوا عبر خطوط CI فقط. - لا تُودع الحالة في git أبداً: أضف
*.tfstateو*.tfstate.backupإلى.gitignoreفي كل مشروع Terraform. استخدمgit-secretsأو hook ما قبل الإيداع لمنع الإيداعات العرضية. - استخدم
sensitive = trueفي المخرجات: عَلِّم أي مخرجات تحتوي على قيمة سرية كحساسة. ستحجب Terraform قيمتها في مخرجات CLI وملفات الخطة — لكنها ستبقى في الحالة. الحساسية في Terraform حرس تجربة مستخدم، لا حد أمان.
encrypt = true (AES256) بـ KMS CMK لأحمال العمل الإنتاجية: أضف kms_key_id = "arn:aws:kms:us-east-1:123456789012:key/mrk-..." إلى إعداد الخلفية. هذا يمنحك استخدام مفتاح مدقَّق بـ CloudTrail، وتدوير المفتاح، والقدرة على إلغاء الوصول إلى كل الحالة التاريخية بتعطيل المفتاح — تحكم لا تستطيع AES256 مع المفاتيح المُدارة بـ AWS توفيره.الترحيل بين الخلفيات
عند تغيير إعداد الخلفية — مثلاً، الانتقال من محلي إلى S3، أو تغيير مفتاح S3 — تكتشف Terraform التغيير عند الـ terraform init التالي وتطلب منك ترحيل الحالة الموجودة. شغّل دائماً terraform plan فوراً بعد الترحيل لتأكيد أن الحالة المُرحَّلة تتطابق مع ما تملكه السحابة فعلاً. الترحيل الناجح يُظهر صفراً من التغييرات المخططة.
الخلاصة
خلفيات الحالة البعيدة هي الأساس التشغيلي لأي سير عمل Terraform يعتمد على الفريق. توفر مجموعة S3 + DynamoDB متانة تخزين الكائنات، وتاريخاً بإصدارات، وتشفيراً أثناء الراحة، وقفلاً ذرياً — تغطية كل أوجه فشل الحالة المحلية. توفر خلفيات HTTP (GitLab، Terraform Cloud) نفس الضمانات عبر بروتوكول موحّد. فهم قفل الحالة — كيف يُكتسب، وكيفية الاسترداد بأمان من الأقفال العالقة، ولماذا تُسبّب العمليات المتزامنة بدون قفل تلفاً في البيانات — هو المعرفة التي تفصل المهندسين الذين يستخدمون Terraform عن الذين يُشغّلونه بأمان على نطاق واسع. أخيراً، معاملة الحالة كأصل حساس (تشفيرها، تقييد الوصول، عدم إيداعها في git) ليست اختيارية: ملف حالتك هو تفريغ جزئي لكل سر تحتفظ به بنيتك التحتية.