مقدمة
تتيح لك وحدات Terraform تجميع موارد بنيتك التحتية المختلفة في مورد واحد موحد. يمكنك إعادة استخدامها لاحقًا مع إمكانية التخصيص دون الحاجة إلى تكرار تعريفات الموارد كلما احتجت إليها، وهو أمر مفيد للمشاريع الكبيرة ذات الهياكل المعقدة. يمكنك تخصيص مثيلات الوحدات باستخدام متغيرات الإدخال التي تحددها، وكذلك استخراج المعلومات منها باستخدام المخرجات. بالإضافة إلى إنشاء وحداتك المخصصة، يمكنك أيضًا استخدام وحدات جاهزة منشورة علنًا في سجل Terraform. يمكن للمطورين استخدامها وتخصيصها باستخدام مدخلات مثل الوحدات التي تنشئها، ولكن يتم تخزين شيفرتها المصدرية داخل وخارج السحابة. في هذا البرنامج التعليمي، ستنشئ وحدة Terraform تُشغّل عدة وحدات Droplets خلف موازن تحميل لتوفير التكرار. ستستخدم أيضًا ميزتي التكرار المتكرر for_each وcount في لغة تكوين Hashicorp (HCL) لنشر مثيلات وحدات مخصصة متعددة في وقت واحد.
المتطلبات الأساسية
- رمز وصول شخصي إلى DigitalOcean
- تم تثبيت Terraform على نظامك وتم إعداد المشروع مع موفر DO.
- مقدمة عن أنواع البيانات وحلقات HCL
- مقدمة لمخرجات Terraform واستخداماتها
هيكل الوحدة والفوائد
في هذا القسم، ستتعرف على فوائد الوحدات النمطية، ومكان وضعها عادةً في المشروع، وكيفية هيكلتها. صُممت وحدات Terraform المخصصة لتغليف المكونات المتصلة التي تُستخدم عادةً في المشاريع الكبيرة وتُنشر معًا. تتميز هذه الوحدات باستقلاليتها، حيث تجمع فقط الموارد والمتغيرات والمزودين الذين تحتاجهم. تُخزن الوحدات النمطية عادةً في مجلد مركزي في جذر المشروع، كل منها في مجلد فرعي خاص بها. للحفاظ على فصل واضح بين الوحدات النمطية، صمّمها دائمًا بحيث يكون لها غرض واحد وتأكد من عدم احتوائها على وحدات نمطية فرعية. قد يكون تجميع مورد واحد كوحدة نمطية أمرًا زائدًا عن الحاجة، ويؤدي تدريجيًا إلى إزالة بساطة البنية العامة. بالنسبة لمشاريع التطوير والاختبار الصغيرة، لا يُعد دمج الوحدات النمطية ضروريًا، لأنها لا تُحقق تقدمًا كبيرًا في تلك الحالات. كما توفر الوحدات النمطية ميزة تعديل التعريفات في مكان واحد فقط، ثم نشرها على بقية البنية التحتية.
بعد ذلك، يمكنك تحديد الوحدات النمطية واستخدامها وتخصيصها في مشاريع Terraform الخاصة بك.
إنشاء وحدة
في هذا القسم، تُعرّف عدة وحدات Droplets وموازن تحميل كموارد Terraform، ثم تُجمّعها في وحدة نمطية. كما تُهيئ الوحدة الناتجة باستخدام مُدخلات قابلة للتكوين.
ضع الوحدة في الدليل المسمى قطرة-رطلستحفظ الملف في مجلد يُسمى modules. بافتراض وجودك في مجلد terraform-modules الذي أنشأته كجزء من المتطلبات الأساسية، ثبّت الملفين معًا بتشغيل الأمر التالي:
mkdir -p modules/droplet-lbتأمر الحجة -p برنامج mkdir بإنشاء كافة الدلائل في المسار المقدم.
اذهب إليه:
cd modules/droplet-lbكما ذُكر في القسم السابق، تحتوي الوحدات النمطية على الموارد والمتغيرات التي تستخدمها. بدءًا من إصدار Terraform 0.13، يجب أن تحتوي الوحدات النمطية أيضًا على تعريفات لموفري الخدمة الذين تستخدمهم. لا تتطلب الوحدات النمطية أي تكوين خاص للإشارة إلى أن الكود يُمثل وحدة نمطية، لأن Terraform يعتبر أي دليل يحتوي على كود HCL وحدة نمطية، حتى الدليل الجذر للمشروع.
تُعرض المتغيرات المُعرّفة في الوحدة كمدخلات، ويمكن استخدامها في تعريفات الموارد لتخصيصها. ستحتوي الوحدة التي تُنشئها على مدخلين: عدد وحدات Droplets المراد إنشاؤها واسم مجموعتها. لتحرير ملف يُسمى متغيرات.tf قم بإنشاء وفتح المكان الذي ستخزن فيه المتغيرات:
nano variables.tfأضف الأسطر التالية:
variable "droplet_count" {}
variable "group_name" {}احفظ الملف وأغلقه.
يمكنك تعريف Droplet في ملف يسمى قطرات.tf ستحفظه. أنشئه وافتحه للتحرير:
nano droplets.tf
أضف الأسطر التالية:
resource "digitalocean_droplet" "droplets" {
count = var.droplet_count
image = "ubuntu-22-04-x64"
name = "${var.group_name}-${count.index}"
region = "fra1"
size = "s-1vcpu-1gb"
lifecycle {
precondition {
condition = var.droplet_count >= 2
error_message = "At least two droplets must be created."
}
}
}للمعلمة عددمرر متغير droplet_count، الذي يحدد عدد مثيلات المورد المراد إنشاؤه. ستُحدد قيمته عند استدعاء الوحدة من كود المشروع الرئيسي. سيختلف اسم كل قطرة منشورة، ويتحقق ذلك بإضافة فهرس القطرة الحالي إلى اسم المجموعة المُدخل. نشر القطرات في المنطقة فرا1 سيتم تشغيله على Ubuntu 22.04.
قسم دورة الحياة يحتوي على شرط مسبق يتم تنفيذ عملية التحقق قبل نشر الموارد فعليًا. هنا، يتم التحقق من إنشاء نقطتين على الأقل - وجود نقطة واحدة فقط يُفسد غرض مُوازن الأحمال. يمكن العثور على مثال آخر لعمليات التحقق في مستودع k8s-bootstrapper، الذي يحتوي على قوالب لإعداد مجموعة DigitalOcean Kubernetes باستخدام Terraform. هناك، تُستخدم عمليات التحقق لضمان أن عدد العقد في المجموعة ضمن النطاق.
عندما تنتهي، احفظ الملف وأغلقه.
بعد تعريف Droplets، يمكنك الانتقال إلى إنشاء موازن التحميل. عرّف مصدره في ملف يُسمى lb.tf ستحفظه. أنشئه وافتحه للتعديل بتنفيذ الأمر التالي:
nano lb.tfأضف تعريف المصدر الخاص به:
resource "digitalocean_loadbalancer" "www-lb" {
name = "lb-${var.group_name}"
region = "fra1"
forwarding_rule {
entry_port = 80
entry_protocol = "http"
target_port = 80
target_protocol = "http"
}
healthcheck {
port = 22
protocol = "tcp"
}
droplet_ids = [
for droplet in digitalocean_droplet.droplets:
droplet.id
]
}عرّف مُوازن الأحمال باسم المجموعة ليسهل التعرف عليه. عرّفه مع نقاط التوزيع في المنطقة. فرا1 يحدد القسمان التاليان المنافذ والبروتوكولات المستهدفة والمراقبة.
تحصل كتلة "معرّفات القطرات" المميزة على مُعرِّفات القطرات التي يجب أن يُديرها مُوازن الأحمال. نظرًا لوجود عدة قطرات وعدم معرفة عددها مُسبقًا، يُمكنك استخدام حلقة for للتنقل بين مجموعة القطرات (digitalocean_droplet.droplets) والحصول على مُعرِّفاتها. تُحيط حلقة for بأقواس ([]) بحيث تكون المجموعة الناتجة قائمة.
احفظ الملف وأغلقه.
بعد أن حددتَ Droplet وموازن الأحمال والمتغيرات لوحدتك، عليكَ تحديد متطلبات المزوّد وتحديد مزوّدي الخدمة الذين ستستخدمهم الوحدة، بما في ذلك إصدارهم وموقعهم. بدءًا من إصدار Terraform 0.13، يجب على الوحدات تحديد موارد المزوّدين غير التابعة لـ Hashicorp التي ستستخدمها بشكل صريح. هذا لأنها لن ترثها من المشروع الرئيسي.
يمكنك تحديد متطلبات الموفر في ملف يسمى provider.tf ستحفظه. اجعله متاحًا للتعديل بتنفيذ الأمر التالي:
nano provider.tfأضف الأسطر التالية لطلب مزود Digitalocean:
terraform {
required_providers {
digitalocean = {
source = "digitalocean/digitalocean"
version = "~> 2.0"
}
}
}عند الانتهاء، احفظ الملف وأغلقه. الوحدة النمطية قطرة-رطل الآن إلى المزود ديجيتال أوشن احتياجات.
تدعم الوحدات أيضًا مخرجات يمكنك استخدامها لاستخراج معلومات داخلية حول حالة مواردها. يمكنك تحديد مخرج يعرض عنوان IP لموازن التحميل وتخزينه في ملف يُسمى outputs.tf احفظه. أنشئه للتحرير:
nano outputs.tfأضف التعريف التالي:
output "lb_ip" {
value = digitalocean_loadbalancer.www-lb.ip
}سيُظهر هذا الناتج عنوان IP لموازن التحميل. احفظ الملف وأغلقه.
الوحدة قطرة-رطل أصبح الآن جاهزًا للعمل بكامل طاقته. يمكنك استدعاؤه من الكود الرئيسي، الذي ستخزنه في جذر المشروع. أولًا، انتقل إليه بالنقر المزدوج في مجلد الملفات:
cd ../..ثم ملف يسمى main.tf قم بإنشاء وفتح التعديل حيث ستستخدم الوحدة:
nano main.tfأضف الأسطر التالية:
module "groups" {
source = "./modules/droplet-lb"
droplet_count = 3
group_name = "group1"
}
output "loadbalancer-ip" {
value = module.groups.lb_ip
}في هذا الإعلان، الوحدة قطرة-رطل تستدعي دليل المصدر الموجود في الدليل المحدد. المدخلات التي يوفرها هي عدد القطرات و اسم المجموعة يمكنك تكوينه ليتم تعيينه على المجموعة 1 حتى تتمكن من التمييز بين الحالات لاحقًا.
بما أن مُخرَج IP لموازن التحميل مُعَرَّف في وحدة نمطية، فلا يُعرَض تلقائيًا عند نشر المشروع. الحل هو إنشاء مُخرَج آخر عن طريق استرداد قيمته (loadbalancer_ip).
عند الانتهاء، احفظ الملف وأغلقه.
قم بتشغيل الوحدة عن طريق تشغيل:
terraform initوسيكون الناتج على النحو التالي:
OutputInitializing modules...
- groups in modules/droplet-lb
Initializing the backend...
Initializing provider plugins...
- Finding digitalocean/digitalocean versions matching "~> 2.0"...
- Installing digitalocean/digitalocean v2.34.1...
- Installed digitalocean/digitalocean v2.34.1 (signed by a HashiCorp partner, key ID F82037E524B9C0E8)
...
Terraform has been successfully initialized!
You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.
If you ever set or change modules or backend configuration for Terraform,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.يمكنك جدولة المشروع لمعرفة الإجراءات التي سيتخذها Terraform عند التنفيذ:
terraform plan -var "do_token=${DO_PAT}"سيكون الناتج مشابهًا لهذا:
Output...
Terraform used the selected providers to generate the following execution plan. Resource actions are
indicated with the following symbols:
+ create
Terraform will perform the following actions:
# module.groups.digitalocean_droplet.droplets[0] will be created
+ resource "digitalocean_droplet" "droplets" {
...
+ name = "group1-0"
...
}
# module.groups.digitalocean_droplet.droplets[1] will be created
+ resource "digitalocean_droplet" "droplets" {
...
+ name = "group1-1"
...
}
# module.groups.digitalocean_droplet.droplets[2] will be created
+ resource "digitalocean_droplet" "droplets" {
...
+ name = "group1-2"
...
}
# module.groups.digitalocean_loadbalancer.www-lb will be created
+ resource "digitalocean_loadbalancer" "www-lb" {
...
+ name = "lb-group1"
...
}
Plan: 4 to add, 0 to change, 0 to destroy.
...يوضح هذا الإخراج أن Terraform ينشئ ثلاث قطرات تسمى group1-0 وgroup1-1 وgroup1-2، ويقوم أيضًا بإنشاء موازن تحميل يسمى group1-lb والذي يتعامل مع حركة المرور من وإلى القطرات الثلاث.
يمكنك نشر المشروع على السحابة عن طريق تشغيل الأمر التالي:
terraform apply -var "do_token=${DO_PAT}"عند المطالبة، أدخل "نعم". سيعرض الناتج جميع الإجراءات، بالإضافة إلى عنوان IP لموازن الحمل.
Outputmodule.groups.digitalocean_droplet.droplets[1]: Creating...
module.groups.digitalocean_droplet.droplets[0]: Creating...
module.groups.digitalocean_droplet.droplets[2]: Creating...
...
Apply complete! Resources: 4 added, 0 changed, 0 destroyed.
Outputs:
loadbalancer-ip = ip_addressلقد قمت بإنشاء وحدة تحتوي على عدد قابل للتكوين من القطرات وموازن تحميل تم تكوينه تلقائيًا لإدارة حركة المرور الواردة والصادرة.
إعادة تسمية الموارد المنشورة
في القسم السابق، قمتَ بنشر الوحدة التي عرّفتها وسمّيتها "مجموعة". إذا أردتَ تغيير اسمها، فإنّ إعادة تسمية استدعاء الوحدة لن تُحقّق النتائج المرجوّة. ستؤدي إعادة تسمية الاستدعاء إلى تدمير Terraform للموارد وإعادة إنشائها، مما يتسبّب في تعطل النظام بشكل كبير.
على سبيل المثال، main.tf افتحه للتحرير عن طريق تشغيل:
nano main.tfقم بإعادة تسمية وحدة المجموعات إلى group_renamed كما هو محدد:
module "groups_renamed" {
source = "./modules/droplet-lb"
droplet_count = 3
group_name = "group1"
}
output "loadbalancer-ip" {
value = module.groups_renamed.lb_ip
}احفظ الملف وأغلقه. ثم شغّل المشروع مرة أخرى:
terraform initالآن يمكنك التخطيط للمشروع:
terraform plan -var "do_token=${DO_PAT}"سيكون الناتج طويلاً ولكن سيبدو كالتالي:
Output...
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
+ create
- destroy
Terraform will perform the following actions:
# module.groups.digitalocean_droplet.droplets[0] will be destroyed
...
# module.groups_renamed.digitalocean_droplet.droplets[0] will be created
...يتطلب Terraform منك تدمير النسخ الحالية وإنشاء نسخ جديدة. هذا مُدمّر وغير ضروري، وقد يؤدي إلى أعطال غير مقصودة.
بدلاً من ذلك، يمكنك توجيه Terraform لترحيل الموارد القديمة بالاسم الجديد باستخدام الكتلة المُهاجَرة. افتح ملف main.tf للتحرير، وأضف الأسطر التالية في نهاية الملف:
moved {
from = module.groups
to = module.groups_renamed
}عندما تنتهي، احفظ الملف وأغلقه.
الآن يمكنك التخطيط للمشروع:
terraform plan -var "do_token=${DO_PAT}"عندما تقوم بالبرمجة باستخدام الكتلة المنقولة في main.tf، يريد Terraform نقل الموارد بدلاً من إعادة إنشائها:
OutputTerraform will perform the following actions:
# module.groups.digitalocean_droplet.droplets[0] has moved to module.groups_renamed.digitalocean_droplet.droplets[0]
...
# module.groups.digitalocean_droplet.droplets[1] has moved to module.groups_renamed.digitalocean_droplet.droplets[1]
...تغير الموارد المحمولة موقعها في وضع Terraform، مما يعني أن موارد السحابة الفعلية لا يتم تغييرها أو تدميرها أو إعادة إنشائها.
نظرًا لأنك ستقوم بتغيير التكوين بشكل كبير في الخطوة التالية، فقم بتحديث الموارد المنشورة عن طريق تشغيل:
terraform destroy -var "do_token=${DO_PAT}"عندما تم سؤالك، نعم أدخل . ينتهي الإخراج بـ:
Output...
Destroy complete! Resources: 4 destroyed.في هذا القسم، قمتَ بإعادة تسمية الموارد في مشروع Terraform دون إتلافها. الآن، ستنشر نسخًا متعددة من وحدة نمطية من نفس الكود باستخدام for_each وcount.
نشر مثيلات متعددة للوحدات النمطية
في هذا القسم، يمكنك استخدام count و for_each لنشر وحدة droplet-lb عدة مرات مع التخصيص.
استخدام العد
إحدى طرق نشر نسخ متعددة من وحدة نمطية في الوقت نفسه هي تمرير قيمة count إلى معلمة count، والتي تتوفر تلقائيًا لكل وحدة نمطية. افتح ملف main.tf للتحرير:
nano main.tfقم بتغييره إلى ما يلي عن طريق حذف تعريف الإخراج الحالي والكتلة المنقولة:
module "groups" {
source = "./modules/droplet-lb"
count = 3
droplet_count = 3
group_name = "group1-${count.index}"
}بتعيين العدد إلى ٣، ستُوجّه Terraform لنشر الوحدة ثلاث مرات، كل مرة باسم مجموعة مختلف. عند الانتهاء، احفظ الملف وأغلقه.
جدولة النشر عن طريق تشغيل:
terraform plan -var "do_token=${DO_PAT}"سيكون الناتج طويلاً وسيبدو بهذا الشكل:
Output...
Terraform used the selected providers to generate the following execution plan. Resource actions are
indicated with the following symbols:
+ create
Terraform will perform the following actions:
# module.groups[0].digitalocean_droplet.droplets[0] will be created
...
# module.groups[0].digitalocean_droplet.droplets[1] will be created
...
# module.groups[0].digitalocean_droplet.droplets[2] will be created
...
# module.groups[0].digitalocean_loadbalancer.www-lb will be created
...
# module.groups[1].digitalocean_droplet.droplets[0] will be created
...
# module.groups[1].digitalocean_droplet.droplets[1] will be created
...
# module.groups[1].digitalocean_droplet.droplets[2] will be created
...
# module.groups[1].digitalocean_loadbalancer.www-lb will be created
...
# module.groups[2].digitalocean_droplet.droplets[0] will be created
...
# module.groups[2].digitalocean_droplet.droplets[1] will be created
...
# module.groups[2].digitalocean_droplet.droplets[2] will be created
...
# module.groups[2].digitalocean_loadbalancer.www-lb will be created
...
Plan: 12 to add, 0 to change, 0 to destroy.
...يوضح Terraform في المخرجات أن كل واحدة من حالات الوحدة النمطية الثلاث تحتوي على ثلاث وحدات Droplets وموازن تحميل مرتبط بها.
استخدام for_each
يمكنك استخدام for_each للوحدات النمطية عندما تحتاج إلى تخصيص مثيلات أكثر تعقيدًا أو عندما يعتمد عدد المثيلات على بيانات الطرف الثالث (غالبًا ما يتم توفيرها كخريطة) التي لا تُعرف عند كتابة الكود.
الآن، يمكنك تحديد خريطة تربط أسماء المجموعات بعدد القطرات، وتُنفّذ مثيلات droplet-lb بناءً عليها. افتح ملف main.tf للتحرير بتنفيذ:
nano main.tfقم بتغيير الملف على النحو التالي:
variable "group_counts" {
type = map
default = {
"group1" = 1
"group2" = 3
}
}
module "groups" {
source = "./modules/droplet-lb"
for_each = var.group_counts
droplet_count = each.value
group_name = each.key
}أولاً، تُعرّف خريطةً تُسمى group_counts تحتوي على عدد القطرات في مجموعة مُحددة. بعد ذلك، تُستدعى وحدة droplet-lb، مع تحديد أن حلقة for_each يجب أن تعمل على var.group_counts، الخريطة التي عرّفتها سابقًا. تأخذ droplet_count قيمة كل زوج، وهي عدد القطرات في المجموعة الحالية. تأخذ group_name اسم المجموعة.
عند الانتهاء، احفظ الملف وأغلقه.
حاول تطبيق التكوين عن طريق تشغيل الأمر التالي:
terraform plan -var "do_token=${DO_PAT}"يُظهر الإخراج تفاصيل إجراءات Terraform لإنشاء هاتين المجموعتين باستخدام Droplets وLoad Balancers:
Output...
Terraform used the selected providers to generate the following execution plan. Resource actions are
indicated with the following symbols:
+ create
Terraform will perform the following actions:
# module.groups["group1"].digitalocean_droplet.droplets[0] will be created
...
# module.groups["group1"].digitalocean_loadbalancer.www-lb will be created
...
# module.groups["group2"].digitalocean_droplet.droplets[0] will be created
...
# module.groups["group2"].digitalocean_droplet.droplets[1] will be created
...
# module.groups["group2"].digitalocean_droplet.droplets[2] will be created
...
# module.groups["group2"].digitalocean_loadbalancer.www-lb will be created
...في هذه المرحلة، استخدمت count و for_each لنشر عدة مثيلات مخصصة لوحدة من نفس الكود.
نتيجة
في هذا البرنامج التعليمي، أنشأتَ وحدات Terraform ونفّذتَها. استخدمتَ الوحدات لتجميع الموارد المرتبطة منطقيًا معًا، وخصّصتَها لنشر نسخ متعددة ومختلفة من تعريف الكود المركزي. كما استخدمتَ المُخرَجات لعرض خصائص الموارد في الوحدة.









