أذكر تلك الليلة جيداً، كانت الساعة قد تجاوزت الثانية صباحاً بتوقيت القدس. كنت أجلس أمام شاشتي، محاطاً بأكواب القهوة الفارغة، والعرق يتصبب من جبيني. وصلني إشعار أحمر اللون على نظام المراقبة: أحد الخوادم الرئيسية للتطبيق قد توقف عن العمل تماماً. “مش مشكلة”، قلت في نفسي بثقة مهزوزة، “عندي نسخة احتياطية وخادم جاهز للإطلاق”.
وهنا بدأت المأساة الحقيقية. قمت بتشغيل الخادم الجديد الذي كان من المفترض أن يكون “صورة طبق الأصل” عن الخادم القديم. لكن التطبيق لم يعمل. ظهرت أخطاء غريبة لم أرها من قبل. قضيت الساعات الثلاث التالية في مقارنة ملفات الإعدادات يدوياً، سطراً بسطر، بين الخادم الجديد والنسخة الاحتياطية القديمة. اكتشفت أن أحدهم، قبل أشهر، قام بتحديث مكتبة معينة على الخادم القديم لحل مشكلة مؤقتة ونسي توثيق ذلك. تحديث بسيط، تم يدوياً، لم يتم تطبيقه على باقي الخوادم، وكان هو سبب كل هذه الـ “خربطة”. في تلك اللحظة، نظرت إلى رف الخوادم الافتراضية وقلت لزميلي المنهك بجانبي: “يا زلمة، كل خادم من هدول هو نسخة فريدة من الجحيم”.
كانت تلك الليلة هي نقطة التحول. أدركنا أن طريقتنا في إدارة البنية التحتية، التي تعتمد على التدخل اليدوي والتعديلات السريعة، لم تعد مجدية. كنا نعيش في كابوس اسمه “الانحراف التكويني” (Configuration Drift)، ولم نكن نعرف ذلك حتى.
ما هو “الانحراف التكويني” (Configuration Drift)؟ وليش هو كابوس كل مطور؟
ببساطة يا جماعة، الانحراف التكويني هو عندما تبدأ الخوادم والبنى التحتية، التي من المفترض أن تكون متطابقة، في الاختلاف عن بعضها البعض بمرور الوقت. تخيل أنك تبدأ بخمسة خوادم متشابهة تماماً. بعد ستة أشهر، ستجد أن:
- الخادم الأول: عليه تحديث أمني قام به فلان.
- الخادم الثاني: يحتوي على حزمة برمجية إضافية قام بتركيبها علان لحل مشكلة عاجلة.
- الخادم الثالث: لديه إعدادات مختلفة في جدار الحماية قام بها شخص ثالث أثناء اختبار شيء ما.
- الخادم الرابع والخامس: لا أحد يتذكر آخر مرة تم لمسهما فيها.
هذه التغييرات الصغيرة، التي تتم يدوياً وبشكل غير موثق، تتراكم مثل الغبار. في البداية لا تلاحظها، ولكن مع مرور الوقت، تتحول إلى وحش من الفوضى. يصبح من المستحيل التنبؤ بسلوك بيئتك، وتصبح عمليات النشر محفوفة بالمخاطر، واستعادة النظام بعد الكوارث ضرباً من الخيال. أنت لم تعد تدير نظاماً، بل مجموعة من الجزر المنعزلة التي لا تتحدث نفس اللغة.
“الانحراف التكويني لا يحدث فجأة. إنه موت بطيء بألف جرح ورقي، كل جرح هو تعديل يدوي صغير وغير موثق.” – أبو عمر
البنية التحتية كشيفرة (IaC): الحل السحري يبدأ بالكود
هنا يأتي دور المفهوم العبقري: البنية التحتية كشيفرة (Infrastructure as Code – IaC). الفكرة بسيطة جداً في جوهرها: بدلاً من إعداد الخوادم والشبكات وقواعد البيانات يدوياً عبر واجهات رسومية أو أوامر متفرقة، نقوم بتعريف كل هذه البنية التحتية في ملفات نصية (كود).
هذه الملفات تصبح هي “مصدر الحقيقة الوحيد” (Single Source of Truth). هل تريد خادماً جديداً؟ لا تضغط على أي زر، بل قم بتعديل الكود. هل تريد تغيير إعدادات جدار الحماية؟ عدّل الكود. هذا الكود يمكننا تخزينه، مراجعته، واختباره تماماً مثل كود التطبيق نفسه.
مرحباً Terraform: الأداة التي أعادت لنا النظام
Terraform هي أداة مفتوحة المصدر من شركة HashiCorp، وهي أشهر وأقوى أداة لتطبيق مفهوم الـ IaC. ما يميز Terraform هو أسلوبها “التصريحي” (Declarative).
- الأسلوب الأمري (Imperative): أنت تخبر الأداة بالخطوات الدقيقة التي يجب اتخاذها للوصول إلى الهدف (مثلاً: أنشئ خادماً، ثم أضف له قرصاً، ثم اربطه بالشبكة…). هذا أسلوب أدوات الـ Shell Scripts.
- الأسلوب التصريحي (Declarative): أنت تصف للأداة “الحالة النهائية” التي تريدها (مثلاً: أريد خادماً بهذه المواصفات، وهذا القرص، ومتصلاً بهذه الشبكة). و Terraform تتكفل بمعرفة كيفية الوصول إلى هذه الحالة.
هذا الأسلوب التصريحي هو سر قوة Terraform في القضاء على الانحراف التكويني. في كل مرة تقوم بتشغيل Terraform، فإنها تقارن “الحالة المطلوبة” (المعرفة في الكود) مع “الحالة الحقيقية” (ما هو موجود فعلاً على السحابة)، وتعرض عليك التغييرات اللازمة لسد الفجوة. لا مزيد من المفاجآت!
لنطبق الحكي: مثال عملي لإطلاق خادم EC2 على AWS
يكفي كلام نظري، دعونا نرى كيف يبدو هذا على أرض الواقع. لنفترض أننا نريد إنشاء خادم ويب بسيط (EC2 instance) على Amazon Web Services.
الخطوة 1: تعريف “المزوّد” (Provider)
أولاً، نخبر Terraform أننا سنتعامل مع AWS.
# main.tf
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}
# تحديد المنطقة التي سنعمل عليها
provider "aws" {
region = "us-east-1"
}
نصيحة من أبو عمر: دائماً قم بتثبيت إصدار معين من الـ provider (مثل `~> 5.0`) لتجنب المفاجآت عند تحديث الـ provider في المستقبل. هذا يضمن أن الكود الذي يعمل اليوم سيعمل غداً.
الخطوة 2: تعريف “المورد” (Resource)
الآن، لنصف الخادم الذي نريده.
# main.tf
resource "aws_instance" "web_server" {
# Amazon Machine Image - نوع نظام التشغيل
ami = "ami-0c55b159cbfafe1f0"
# حجم الخادم (t2.micro مجاني في الطبقة المجانية)
instance_type = "t2.micro"
tags = {
Name = "MyFirstWebServer-Terraform"
}
}
هذا كل شيء! بهذين المقطعين من الكود، قمنا بتعريف بنية تحتية كاملة (ولو أنها بسيطة). الآن لنرى سحر Terraform.
الخطوة 3: التنفيذ (The Holy Trinity: init, plan, apply)
في الطرفية (Terminal)، داخل المجلد الذي يحتوي على ملف `main.tf`، ننفذ الأوامر التالية:
terraform init: هذا الأمر يقوم بتهيئة بيئة العمل وتنزيل الـ provider الخاص بـ AWS. تنفذه مرة واحدة فقط في البداية.terraform plan: هذا هو أمر الأمان. يقوم Terraform بمقارنة الكود بالحالة الحقيقية ويعرض عليك “خطة” بما سيقوم به. لن يقوم بتنفيذ أي شيء بعد، فقط يعرض النوايا. الخرج سيبدو كالتالي:Plan: 1 to add, 0 to change, 0 to destroy.terraform apply: إذا كانت الخطة تبدو جيدة، فهذا الأمر يقوم بتنفيذها فعلياً. سيطلب منك تأكيداً بكتابة `yes`. بعد بضع دقائق، سيكون خادمك جاهزاً على AWS.
الجمال هنا هو أنه لو قام شخص بتغيير نوع الخادم يدوياً على AWS من `t2.micro` إلى `t2.small`، في المرة القادمة التي تشغل فيها `terraform plan`، ستكتشف Terraform هذا الانحراف فوراً وستقترح عليك إعادته إلى `t2.micro`.
نصائح عملية من خبرة أبو عمر
تعلم الأداة شيء، واستخدامها بحرفية شيء آخر. إليك بعض النصائح التي تعلمتها بالطريقة الصعبة:
- لا تلمس ملف الحالة (State File) يدوياً: ملف `terraform.tfstate` هو عقل Terraform. إياك ثم إياك أن تعدله يدوياً. استخدم دائماً `terraform import` لإدخال موارد موجودة أو اترك Terraform تديره بنفسها.
- استخدم Remote State Backend: عندما تعمل في فريق، تخزين ملف الحالة على جهازك المحلي هو وصفة لكارثة. استخدم backends عن بعد مثل Amazon S3 أو Terraform Cloud. هذا يضمن أن الجميع يعمل على نفس الحالة ويمنع التعارض.
- قسّم الكود باستخدام الوحدات (Modules): لا تكتب كل شيء في ملف واحد. عندما تكبر بنيتك التحتية، استخدم الوحدات (Modules) لتنظيم الكود وإعادة استخدامه. يمكنك إنشاء وحدة خاصة بالشبكات، ووحدة للخوادم، ووحدة لقواعد البيانات.
- كل شيء في Git: بما أن بنيتك التحتية أصبحت كوداً، عاملها ككود. ضع كل ملفات `.tf` في نظام إدارة إصدارات مثل Git. هذا يعطيك تاريخاً كاملاً للتغييرات، القدرة على مراجعة الكود (Pull Requests)، والعودة إلى إصدار سابق إذا حدث خطأ.
الخلاصة: من الفوضى إلى النظام بفضل الكود 😉
بالعودة إلى تلك الليلة المشؤومة، لو كنا نستخدم Terraform، لكانت القصة مختلفة تماماً. بدلاً من قضاء ثلاث ساعات في البحث عن إبرة في كومة قش، كان كل ما سنحتاجه هو أمر واحد: `terraform apply`. كانت Terraform ستكتشف أن الخادم الجديد لا يطابق التعريف الموجود في الكود، وكانت ستقوم بإصلاح كل شيء تلقائياً.
التحول إلى البنية التحتية كشيفرة باستخدام Terraform ليس مجرد تغيير في الأدوات، بل هو تغيير في العقلية. هو الانتقال من رد الفعل وإطفاء الحرائق إلى الفعل الاستباقي والتخطيط المنظم. هو أن تنام قرير العين وأنت تعلم أن بيئتك متناسقة، قابلة للتكرار، ويمكن استعادتها بضغطة زر.
نصيحتي الأخيرة لك: لا تنتظر حتى تحترق خوادمك في منتصف الليل. ابدأ اليوم. ابدأ بمشروع صغير. عرّف خادماً واحداً أو شبكة واحدة. ستجد أن الاستثمار الأولي في تعلم هذه الأداة سيوفر عليك ساعات لا تحصى من الألم والصداع في المستقبل. صدق من جرّب.