لماذا OpenTofu بدلاً من الاستمرار في إدارة SSH يدوياً
حتى خمسة أو ستة عملاء، تصمد الإدارة اليدوية: تتذكر ما يعمل أين، وقائمة إعداد الخادم محفوظة. بعد ذلك، تصبح الذاكرة مخاطرة تشغيلية. خادم VPS المُوفَّر يدوياً لا تتوفر له حالة قابلة للقراءة: لا تعرف دون الاتصال به إن كان جدار الحماية مُهيَّأً، أو إن كان Docker على الإصدار المتوقع، أو إن كان هذا الخادم لا يزال ضمن دوران التحميل.
OpenTofu يحل مشكلة مختلفة عن Ansible. Ansible يدير *تهيئة* خادم موجود بالفعل — ما يعمل عليه، أي ملفات موجودة، أي خدمات تعمل. OpenTofu يدير *دورة حياة* الخادم نفسه: الإنشاء، تحديث الخصائص، الحذف. ويحتفظ بملف حالة (terraform.tfstate) يعرف بالضبط ما هو مُوفَّر وما ليس كذلك. الأداتان متكاملتان: OpenTofu يُوفِّر، Ansible يُهيِّئ.
في أغسطس 2023، غيّرت HashiCorp رخصة Terraform من MPL-2.0 إلى BUSL-1.1، وهي رخصة غير حرة تُقيّد بعض الاستخدامات التجارية. ردّ المجتمع بإنشاء OpenTofu، فرع متوافق مع HCL للإصدارات السابقة لـ Terraform 1.6، ومستضاف الآن تحت CNCF (مؤسسة الحوسبة السحابية الأصلية) والـ Linux Foundation. الأمر هو tofu لا terraform، لكن ملفات .tf والمنطق متطابقان.
ما تكسبه مع حالة تصريحية
- جرد موثوق — يخبرك ملف
terraform.tfstateبالضبط بأي خوادم موجودة، مع أي عناوين IP وخصائص، دون الاتصال بكل واحد. - قابلية إعادة الإنتاج — عميل جديد أو مشروع جديد يحصل على نفس خادم VPS مُهيَّئاً بنفس الطريقة، من نفس ملف
.tfالموجود في Git. - حذف نظيف — يزيل
tofu destroyالموارد بالترتيب الصحيح، دون ترك خوادم يتيمة لا تزال تُدفَع فواتيرها. - فرق قابل للقراءة — يعرض
tofu planبالضبط ما سيُنشأ أو يُعدَّل أو يُحذَف قبل التنفيذ، مثلgit diffللبنية التحتية. - تكامل مع Ansible — ينشئ OpenTofu خادم VPS ويضع البيانات الوصفية (مفتاح SSH، الاسم، الشبكة)؛ Ansible يتولى نشر Docker وNginx وتطبيقاتك.
- قابل للإصدار والتدقيق — تصبح بنيتك التحتية مستودع Git بعمليات commit ومراجعات كود وسجل تغييرات.
- رخصة مفتوحة المصدر مستدامة — OpenTofu تحت MPL-2.0، دون قيود تجارية، مع حوكمة مجتمعية تحت CNCF.
المتطلبات الأساسية قبل البدء
يفترض هذا الدليل أن لديك خادم VPS بصلاحية root وعنوان IPv4 مخصص لتشغيل أحمال العمل، ومحطة تطوير (macOS أو Linux أو Windows مع WSL2) تُشغّل منها tofu. OpenTofu نفسه لا يعمل على خادم VPS الهدف: ينفذ محلياً ويتحدث إلى API المزود أو daemon Docker الخادم.
لمتابعة الأمثلة، تحتاج إلى: OpenTofu مثبت محلياً (انظر opentofu.org/docs/intro/install)، وصول API أو بيانات اعتماد SSH لخادم VPS الهدف، وGit لإصدار ملفات .tf. لا توجد تبعيات إضافية مطلوبة — OpenTofu يُنزِّل المزودين بنفسه عند tofu init.
للتحكم في Docker على خادم VPS بعيد عبر OpenTofu، يجب أن يستمع daemon Docker الخادم على مقبس Unix الخاص به (افتراضياً) أو على منفذ TCP مؤمَّن. يتصل مزود kreuzwerker/docker بهذا المقبس عبر SSH أو TCP.
إعداد OpenTofu لأسطول خوادم VPS
تثبيت OpenTofu محلياً
توجّه إلى opentofu.org/docs/intro/install للحصول على التعليمات حسب نظام تشغيلك. على macOS مع Homebrew: brew install opentofu. على Debian/Ubuntu: يوفر المستودع الرسمي لـ OpenTofu حزمة opentofu. تحقق من التثبيت بـ tofu version — يجب أن يُعيد الأمر الإصدار المثبت.
هيكلة مشروع البنية التحتية كبيانات
أنشئ دليلاً مخصصاً وأربعة ملفات معيارية.
# main.tf — الموارد الرئيسية
# variables.tf — تصريحات المتغيرات
# outputs.tf — القيم المُعرَّضة بعد apply
# terraform.tfvars — القيم الفعلية (أضفها لـ gitignore إن كانت أسرار)هذه البنية ليست إلزامية لـ OpenTofu، لكنها الاصطلاح المعتمد على نطاق واسع: يحمل main.tf الموارد، يُصرِّح variables.tf بالأنواع والقيم الافتراضية، يكشف outputs.tf ما يحتاج Ansible أو أداة أخرى لقراءته بعد التوفير (عنوان IP الخادم، اسم المضيف…)، ويحتوي terraform.tfvars على القيم الفعلية التي لا تريد كتابتها مباشرة في main.tf.
تصريح المزود وإنشاء مفتاح SSH
OpenTofu يثبّت المزودين المطلوبين عند tofu init. مزود hashicorp/tls ينشئ زوج مفاتيح SSH محلياً، مما يُزيل الحاجة لإدارة المفاتيح يدوياً.
terraform {
required_providers {
tls = {
source = "hashicorp/tls"
version = "~> 4.0"
}
}
}
resource "tls_private_key" "vps_key" {
algorithm = "ED25519"
}
output "private_key_pem" {
value = tls_private_key.vps_key.private_key_pem
sensitive = true
}شغّل tofu init لتنزيل المزود، ثم tofu apply لإنشاء المفتاح. استرجعه بـ tofu output -raw private_key_pem > ~/.ssh/vps_key && chmod 600 ~/.ssh/vps_key.
توفير خادم VPS باستخدام null وlocal-exec
إذا لم يكن لمزود خادم VPS الخاص بك مزود OpenTofu رسمي، يُتيح لك مزود hashicorp/null مع local-exec تنفيذ أمر محلي (استدعاء API بـ curl، سكريبت shell) ونمذجة المورد في الحالة.
resource "null_resource" "vps_provision" {
triggers = {
server_name = var.server_name
}
provisioner "local-exec" {
command = <<EOT
curl -s -X POST https://api.your-provider.com/v1/servers \
-H "Authorization: Bearer ${var.api_token}" \
-d '{"name": "${var.server_name}", "image": "ubuntu-22.04"}'
EOT
}
}هذا النمط مناسب لمرحلة انتقالية. إذا كان مزودك يكشف REST API، يكفي سكريبت shell يُستدعى عبر local-exec لإنشاء الخادم وكتابة عنوان IP في ملف يكشفه outputs.tf لاحقاً.
التحكم في Docker على خادم VPS باستخدام مزود kreuzwerker
بمجرد توفير خادم VPS وتثبيت Docker (عبر Ansible عادةً)، يُتيح لك مزود kreuzwerker/docker تصريح الحاويات والشبكات والأحجام في OpenTofu.
terraform {
required_providers {
docker = {
source = "kreuzwerker/docker"
version = "~> 3.0"
}
}
}
provider "docker" {
host = "ssh://root@${var.server_ip}:22"
}
resource "docker_container" "app" {
name = "my-app"
image = docker_image.app.image_id
}
resource "docker_image" "app" {
name = "nginx:alpine"
}يتصل المزود بـ daemon Docker الخاص بخادم VPS عبر SSH — لا يلزم فتح منفذ TCP إضافي. الإصدار المستقر للمزود متاح على Terraform Registry.
إصدار الحالة للعمل الجماعي
للتطوير الفردي، تكفي الحالة المحلية (terraform.tfstate). في بيئة الفريق أو CI/CD، مطوران يُشغّلان tofu apply في آنٍ واحد يُفسدان الحالة. الحل هو backend بعيد مع قفل.
OpenTofu يدعم S3 أصلاً (AWS، MinIO المستضاف ذاتياً) وGitLab Managed Terraform State. مع bucket MinIO على خادم VPS:
terraform {
backend "s3" {
bucket = "tofu-state"
key = "production/terraform.tfstate"
region = "eu-west-1"
endpoint = "https://minio.your-domain.com"
skip_credentials_validation = true
skip_metadata_api_check = true
skip_region_validation = true
force_path_style = true
}
}القفل تلقائي: إذا كان tofu apply يعمل، يُرفض الثاني حتى ينتهي الأول.
دمج OpenTofu في pipeline CI/CD
يُشغّل pipeline نموذجي لـ Woodpecker CI أو Forgejo Actions الأمر tofu plan على كل pull request (لمراجعة بشرية لفرق البنية التحتية) وtofu apply عند الدمج في الفرع الرئيسي.
steps:
- name: tofu-plan
image: ghcr.io/opentofu/opentofu:latest
commands:
- tofu init
- tofu plan -out=tfplan
- name: tofu-apply
image: ghcr.io/opentofu/opentofu:latest
commands:
- tofu apply tfplan
when:
branch: main
event: pushالحالة البعيدة (الخطوة السابقة) ضرورية هنا: runner CI ليس لديه وصول إلى الحالة المحلية على محطة العمل الخاصة بك.
افصل مساحات العمل حسب البيئة
يوفر OpenTofu خاصية workspaces لعزل حالات متعددة في نفس backend: ينشئ tofu workspace new staging مساحة معزولة، ويُبدِّل tofu workspace select production إلى الإنتاج. هذا أخف من نسخ مجلدات .tf. عملياً، مساحة عمل واحدة لكل عميل أو بيئة (staging، prod) تمنع tofu destroy في staging من لمس الإنتاج. سمِّ مواردك بـ ${terraform.workspace} لتبقى مميزة في الحالة.
Ansible وOpenTofu: الحدود بين الأداتين
يتكرر السؤال: Ansible يؤدي العمل بالفعل، لماذا إضافة أداة؟ الحد واضح متى رُسم صراحةً.
OpenTofu يجيب على "ما الموجود؟": ينشئ الخادم، يُخصّص له عنوان IP، يضع مفتاح SSH، يسجّل حالته. إن حذفته من ملف .tf وشغّلت tofu apply، اختفى الخادم — OpenTofu يمتلك دورة الحياة.
Ansible يجيب على "في أي حالة يوجد ما هو موجود؟": يثبّت Docker، يُهيِّئ Nginx، يضع ملف .env، يُعيد تشغيل خدمة. إذا كان الخادم موجوداً بالفعل، Ansible يجعله ما تطلبه — لكن إذا لم يكن موجوداً، Ansible لا يستطيع إنشاءه.
التدفق الطبيعي لوكالة: OpenTofu يُوفِّر خادم VPS ويكشف عنوان IP الخاص به كـ output، playbook Ansible يستهلك هذا الـ output عبر جرد ديناميكي، يُهيِّئ الخادم وينشر التطبيقات. المقالة Ansible: أتمتة تهيئة خوادم VPS الخاصة بك تغطي جانب التهيئة بالتفصيل.
استكشاف الأخطاء: المشكلات الشائعة
ثلاثة مواقف تتكرر عند اعتماد OpenTofu على أسطول موجود.
الأخطاء الشائعة وطريقة إصلاحها
-
Error acquiring the state lock— عطل أثناءapplyيترك ملف.terraform.tfstate.lock.infoعلى backend. يرفض OpenTofu المتابعة طالما القفل موجود. بعد التحقق من عدم وجودapplyآخر يعمل، أزل القفل بـtofu force-unlock <LOCK_ID>(يظهر المعرّف في رسالة الخطأ). على backend S3/MinIO، الملف مرئي في bucket. -
tofu planيعرضdestroy + createغير متوقع — بعض خصائص المورد تفرض إعادة إنشاءه (force new resource) عند تغييرها: اسم الخادم، نوع صورة نظام التشغيل، المنطقة. إذا عدّلت أحد هذه الخصائص، لا يستطيع OpenTofu إجراء تحديث في المكان — يحذف ويُعيد الإنشاء. اقرأ الخطة بعناية قبل التطبيق واستخدمtofu plan -target=resource.nameلتضييق النطاق. - حالة مفقودة أو غير متزامنة — إذا فُقد ملف الحالة والخوادم لا تزال موجودة، يُدرج
tofu state listما يعتقد OpenTofu أنه مُوفَّر، ويستوردtofu import <resource.type.name> <external-id>مورداً موجوداً في الحالة دون إعادة إنشائه. هذه أداة الاسترداد حين تباينت الواقع والحالة. - المزود غير موجود بعد
tofu init— تحقق من أنsourceللمزود صحيح (مثلkreuzwerker/dockerلاdocker/docker) وأن لديك وصولاً للإنترنت من الجهاز الذي يُشغّلtofu init. في بيئة معزولة، نزّل المزودين مسبقاً واستخدمplugin_cache_dir. -
Error: No valid credential sources found— لا يجد OpenTofu بيانات اعتماد للمزود. تحقق من متغيرات البيئة المتوقعة من المزود (غالباًTF_VAR_api_tokenأو ملف بيانات اعتماد خاص بالمزود) ومن أنterraform.tfvarsيُقرأ (يجب أن يكون في نفس مجلدmain.tf).
بنيتك التحتية تصبح بيانات ذات إصدارات
OpenTofu لا يحل محل SSH، بل يجعل SSH استثناءً. يصبح التدفق اليومي: تعديل ملف .tf، تشغيل tofu plan لمراجعة الفرق، التحقق، تشغيل tofu apply. الخوادم التي لم تعد بحاجة إلى إدارتها تُحذف بـ tofu destroy وتختفي من الفواتير.
لوكالة تتجاوز العشرة عملاء، هذا هو الرافعة التي تحوّل إدارة البنية التحتية من عمل ذاكرة إلى عمل بيانات. خادم ServOrbit Cloud VPS بصلاحية root وعنوان IPv4 مخصص واختيار نظام التشغيل هو الوحدة الأساسية التي تُوفِّرها وتحذفها ملفات .tf الخاصة بك عند الطلب. بنيتك التحتية تصبح بيانات ذات إصدارات.