البنية التحتية ككود وTerraform
البنية التحتية ككود وTerraform
قبل Terraform، كان توفير بيئة سحابية يعني النقر عبر واجهة الويب، أو تشغيل أوامر AWS CLI بشكل عشوائي، أو كتابة سكريبتات هشة تعمل مرة واحدة ثم تصبح معرفة قبلية لا يجرؤ أحد على تعديلها. النتيجة كانت بنية تحتية كندفة الثلج (Snowflake) — كل بيئة مختلفة قليلاً عن الأخرى، يستحيل إعادة إنتاجها بشكل موثوق، ومخيفة عند محاولة تغييرها.
البنية التحتية ككود (IaC) هي ممارسة وصف بنيتك التحتية في ملفات قابلة للقراءة البشرية ومحفوظة في نظام تحكم بالإصدارات، والسماح لأداة بتوفيرها وإدارتها من تلك الوصف. في Google وMeta وكل بيئة سحابية جادة، لا يُنشأ أي مورد إنتاجي بالنقر. كل شيء — الـ VPCs وصلاحيات IAM وكلاسترات EKS وقواعد بيانات RDS وسجلات DNS — مُعلَن ككود، مراجع عبر Pull Request، ومُطبَّق من خلال pipeline آلي. سجل التدقيق موجود في Git؛ نطاق تأثير أي تغيير مرئي قبل تنفيذه.
IaC التصريحي مقابل الأمري
هناك مقاربتان لـ IaC: أمرية (Imperative) وتصريحية (Declarative). كتب تشغيل Ansible والسكريبتات الشل أمرية — تُحدد الخطوات للوصول إلى الحالة المطلوبة. Terraform تصريحي — تُحدد كيف يجب أن تبدو الحالة النهائية وتترك لـ Terraform تحديد الخطوات.
للنموذج التصريحي ميزة حاسمة على نطاق واسع: الاتساق (Idempotency). تشغيل terraform apply عشر مرات على نفس الإعداد ينتج نفس البنية التحتية في كل مرة. لا آثار جانبية، لا انجراف تراكمي. مع السكريبت الأمري، تشغيله مرتين قد يُنشئ موارد مكررة، أو يفشل على كائنات موجودة بالفعل، أو يترك البيئة منصفة جزئياً.
حلقة Plan / Apply
سير عمل Terraform الجوهري هو حلقة ثلاثية الأطوار: كتابة → خطة → تطبيق. هذا هو الانضباط الذي يفصل IaC الاحترافي عن أسلوب "اكتب سكريبت وادعُ ألا يفشل".
الكتابة: تؤلف ملفات .tf تصف الموارد التي تريدها. يستخدم Terraform لغة HCL (HashiCorp Configuration Language)، وهي لغة إعداد مصممة لتكون مقروءة من البشر والآلات.
الخطة: يحسب terraform plan الفرق بين إعدادك المُعلَن وحالة العالم الحقيقية (المُتتبَّعة في ملف الحالة). يطبع فرقاً دقيقاً — أي موارد ستُنشأ أو تُغيَّر أو تُحذف — دون لمس أي شيء. هذا هو فحصك قبل الإقلاع. في pipelines CI الإنتاجية، يُنشر ناتج الخطة كتعليق PR حتى يتمكن المراجعون من الموافقة على التغييرات الدقيقة قبل تنفيذها.
التطبيق: ينفّذ terraform apply الخطة. يستدعي Terraform APIs المزودين بترتيب التبعية، يُنشئ الموارد بالتوازي حيث أمكن، ويُحدّث ملف الحالة لتسجيل ما أصبح موجوداً.
terraform plan قبل apply، حتى محلياً. في الإنتاج، اجعل أثر الخطة إلزامياً: أنشئه بـ terraform plan -out=tfplan، خزّنه كـ artifact في CI، ثم طبّق تلك الخطة بالضبط بـ terraform apply tfplan. هذا يضمن أن ما تمت مراجعته هو ما يُطبَّق فعلاً — لا شروط سباق حيث تتغير البيئة بين الخطة والتطبيق.
المزودون: نموذج امتداد Terraform
لا معرفة لـ Terraform نفسه بـ AWS أو Kubernetes أو Cloudflare. جميع أنواع الموارد تعيش في المزودين (Providers) — إضافات تترجم تعريفات الموارد التصريحية لـ Terraform إلى استدعاءات API حقيقية. مزود AWS يستدعي AWS APIs؛ مزود Kubernetes يتحدث إلى خادم API للكلاستر؛ مزود GitHub يدير المستودعات وعضويات الفرق.
كتلة المزود في إعدادك تُعلن أي مزود تستخدم وبأي إصدار. يُنزّل Terraform المزودين من Terraform Registry أثناء terraform init ويخزّنهم محلياً في .terraform/.
قيد الإصدار ~> 5.0 هو نمط حرج للإنتاج. يُثبّت الإصدار الرئيسي، ويسمح بتحديثات الترقيع والإصدار الثانوي (5.1، 5.2...) تلقائياً بينما يمنع 6.0 الذي قد يحتوي تغييرات كاسرة. حذف قيود الإصدار يجعل terraform init يُنزّل أحدث إصدار — طريقة صامتة لاستيراد تغييرات كاسرة في قاعدة كود البنية التحتية.
كيف يعرف Terraform ما يوجد: ملف الحالة
يتتبع Terraform كل مورد يديره في ملف الحالة (terraform.tfstate). ملف الحالة هو الجسر بين إعداد HCL الخاص بك والبنية التحتية الحقيقية. عند تشغيل terraform plan، يقرأ Terraform كلاً من الإعداد والحالة، يستدعي المزود لتحديث سمات الموارد الحية، ويحسب الفرق.
لهذا عاقبة مهمة: الموارد التي أُنشئت خارج Terraform (بالنقر في وحدة التحكم، أو بسكريبت فريق آخر) غير مرئية لـ Terraform ما لم تستوردها صراحةً. هذا ميزة (وضوح الملكية) وفخ شائع في آن واحد (المهندسون الذين يتجاوزون Terraform يُنشئون موارد غير متتبعة تُسبب لاحقاً فروقات خطة محيّرة أو تكاليف مهجورة).
terraform.tfstate في Git، ولا تخزّنه محلياً للبنية التحتية المشتركة. يحتوي ملف الحالة على بيانات حساسة — معرفات الموارد وعناوين IP وأحياناً أسراراً مُخرجة من الموارد. والأهم، إذا طبّق مهندسان على نفس ملف الحالة المحلي في آن واحد، يصبح الحالة تالفة وبنيتك التحتية في وضع مجهول. الحل هو backend بعيد (S3 + DynamoDB للقفل، أو Terraform Cloud) — مُغطّى في الدرس السادس. في كل فريق حقيقي، اليوم الأول من إعداد Terraform هو تكوين الـ backend البعيد. الحالة المحلية مقبولة فقط للتجارب الشخصية.
سير عمل Terraform الأول من البداية للنهاية
هذا مثال بسيط لكنه كامل يُنشئ AWS S3 Bucket ويُخرج ARN الخاص به. شغّله على حساب AWS شخصي للحصول على الخبرة العضلية لسير العمل:
لاحظ أن aws_s3_bucket.example.arn يُشير إلى سمة ARN للـ bucket قبل وجود المورد. يحل Terraform هذه المراجع في وقت التطبيق، بناءً على رسم بياني للتبعية لتحديد ترتيب التنفيذ. صيغة المرجع هذه — resource_type.name.attribute — أساسية لكل شيء في Terraform وتُغطى بعمق في الدرس السابع.
terraform plan بدلاً من المحرر، وهو حلقة تغذية راجعة أبطأ.
الدرس التالي يتعمق في صياغة HCL — الكتل، والوسائط، والتعبيرات، ونظام الأنواع، وكيفية كتابة أول إعداد متعدد الموارد. بحلول الدرس العاشر ستكون قد وفّرت مكدساً ويب كاملاً — موازن تحميل، وحدات EC2، وRDS، وRoute 53 — بالكامل من كود Terraform.