كيف تقرأ هذه الصفحة. كل قسم مطويّ تحت عنوانه : انقر على « عرض … » لفتحه، وأعد طيّه عندما تنتهي. ترتيب القراءة : الهدف، ثم باختصار (كل الأوامر، للنسخ بالترتيب)، ثم الشيفرة (ملف
main.tfمشروحًا سطرًا سطرًا)، ثم Terraform، في الطرفية (T1 إلى T13، أمر واحد في كل مرة مع مخرجاته الحقيقية). الشرح المفصّل خطوة بخطوة، مع تثبيت الأدوات وتحضير حساب AWS والمخرجات المنتظرة لكل حركة، موجود في الملحق : الملحق A لـ Windows (PowerShell)، الملحق B لـ Linux وmacOS وWSL 2 وGit Bash. افتح ملحقًا واحدًا فقط، ملحق نظامك. يجمع الملحق C، المشترك، الحالات التي يتعطّل فيها شيء.
تصل إلى فريق يدير كل بنيته التحتية بـ Terraform. قبل أن يسمحوا لك بلمس حساب AWS، تطلب منك رئيستك شيئًا واحدًا : « أرِني أنك تتقن الدورة الكاملة على جهازك. ملف واحد يكفي. أريد أن أرى الخطة قبل apply، وstate بعده، والتعديل مكشوفًا، ومجلدًا نظيفًا في النهاية. » هذا بالضبط هذا المشروع. يكتب المزوّد local ملفًا نصيًا على قرصك بدلًا من إنشاء خادم، لكن الأوامر والجمل المعروضة والملفات المُنتَجة هي نفسها كما لـ bucket S3 أو مستودع GitHub. كل ما تقرأه هنا، ستعيد قراءته في المشاريع الثمانية التالية.
الخطوات العشر في هذا المخطط مفصّلة، مع المخرجات المنتظرة لكل أمر، في الملحق A (Windows) أو الملحق B (Linux، macOS، WSL 2، Git Bash) في أسفل الصفحة. أما أوامر Terraform نفسها، المتطابقة على كل الأنظمة، فتُشرح واحدًا واحدًا في Terraform، في الطرفية.
عُدّة الدورة : https://github.com/hrhouma2/aiopsatlas-terraform-labo-fr
تستنسخ العُدّة في مجلد lab-terraform، وتتحقق من أدواتك، وتُنشئ مجلد عمل فارغًا، وتكتب فيه main.tf بنفسك، ثم تنفّذ الدورة : init، fmt، validate، plan، apply، التحقق، state، التعديل، destroy. في النهاية، لا يعرض terraform state list شيئًا بعد الآن ويقول etat : Ressources encore gérées : 0 (0 attendu à la fin d'une séance). (الموارد التي ما زالت مُدارة : 0، وهو المتوقع في نهاية الجلسة). تحتوي العُدّة على الحل النموذجي في projets/01-terraform-local/، لا تفتحه إلا إذا علقت : الهدف كتابة الملف يدويًا.
Windows (PowerShell)
git clone https://github.com/hrhouma2/aiopsatlas-terraform-labo-fr.git lab-terraform
cd lab-terraform
dir # explorer : labo.ps1, labo.sh, README.md, projets\
.\labo.ps1 prerequis # attendu : Prérequis : 4 outils requis présents sur 4.
.\labo.ps1 nouveau projet-01-local # crée travail\projet-01-local
cd travail\projet-01-local
code . # VS Code : créer main.tf, coller le code de la section « Le code »
terraform init # attendu : Terraform has been successfully initialized!
terraform fmt
terraform validate # attendu : Success! The configuration is valid.
terraform plan # attendu : Plan: 1 to add, 0 to change, 0 to destroy.
terraform apply # répondre yes ; attendu : Apply complete! Resources: 1 added, 0 changed, 0 destroyed.
Get-Content .\message.txt # attendu : Bonjour, ce fichier a été créé avec Terraform.
Get-ChildItem -Force # .terraform, .terraform.lock.hcl, main.tf, message.txt, terraform.tfstate
terraform state list # attendu : local_file.message
terraform state show local_file.message
# modifier la ligne content dans main.tf (voir T10), puis :
terraform plan # attendu : Plan: 1 to add, 0 to change, 1 to destroy.
terraform apply # répondre yes ; attendu : Apply complete! Resources: 1 added, 0 changed, 1 destroyed.
Get-Content .\message.txt # attendu : Deuxième version du fichier créée avec Terraform.
terraform destroy # répondre yes ; attendu : Destroy complete! Resources: 1 destroyed.
terraform state list # attendu : rien
cd ..\..
.\labo.ps1 etat # attendu : Ressources encore gérées : 0 (0 attendu à la fin d'une séance).(التعليقات في الكتلة : attendu = المنتظر ؛ répondre yes = أجب بـ yes ؛ rien = لا شيء ؛ modifier la ligne content = عدّل سطر content.)
إذا رفض PowerShell .\labo.ps1 (رسالة تفيد بأن تنفيذ السكربتات معطَّل على هذا النظام) : Set-ExecutionPolicy -Scope CurrentUser RemoteSigned، أجب بـ O، وأعد التشغيل.
Linux وmacOS وWSL 2 وGit Bash
git clone https://github.com/hrhouma2/aiopsatlas-terraform-labo-fr.git lab-terraform
cd lab-terraform
ls # explorer : labo.ps1, labo.sh, README.md, projets/
./labo.sh prerequis # attendu : Prérequis : 4 outils requis présents sur 4.
./labo.sh nouveau projet-01-local # crée travail/projet-01-local
cd travail/projet-01-local
code . # VS Code : créer main.tf, coller le code de la section « Le code »
terraform init # attendu : Terraform has been successfully initialized!
terraform fmt
terraform validate # attendu : Success! The configuration is valid.
terraform plan # attendu : Plan: 1 to add, 0 to change, 0 to destroy.
terraform apply # répondre yes ; attendu : Apply complete! Resources: 1 added, 0 changed, 0 destroyed.
cat message.txt # attendu : Bonjour, ce fichier a été créé avec Terraform.
ls -la # .terraform, .terraform.lock.hcl, main.tf, message.txt, terraform.tfstate
terraform state list # attendu : local_file.message
terraform state show local_file.message
# modifier la ligne content dans main.tf (voir T10), puis :
terraform plan # attendu : Plan: 1 to add, 0 to change, 1 to destroy.
terraform apply # répondre yes ; attendu : Apply complete! Resources: 1 added, 0 changed, 1 destroyed.
cat message.txt # attendu : Deuxième version du fichier créée avec Terraform.
terraform destroy # répondre yes ; attendu : Destroy complete! Resources: 1 destroyed.
terraform state list # attendu : rien
cd ../..
./labo.sh etat # attendu : Ressources encore gérées : 0 (0 attendu à la fin d'une séance).إذا أجاب ./labo.sh بـ Permission denied : chmod +x labo.sh، مرة واحدة فقط.
يتّسع المشروع في ملف واحد، main.tf، يُنشأ في travail/projet-01-local/. اكتبه أو الصقه بالضبط هكذا (إنه كلمةً كلمة الحل النموذجي للعُدّة، projets/01-terraform-local/main.tf) :
terraform {
required_providers {
local = {
source = "hashicorp/local"
version = "~> 2.5"
}
}
}
provider "local" {}
resource "local_file" "message" {
filename = "${path.module}/message.txt"
content = "Bonjour, ce fichier a été créé avec Terraform."
}ثلاث كتل، من الأعم إلى الأخص.
| السطر | ما يقوله لـ Terraform |
|---|---|
terraform { … } | إعدادات Terraform نفسه لهذا المجلد. |
required_providers { local = { … } } | « يحتاج هذا المشروع إلى إضافة تُسمّى local. » |
source = "hashicorp/local" | من أين يُنزَّل : المزوّد local الذي تنشره HashiCorp على Terraform Registry. |
version = "~> 2.5" | أي إصدار يُقبل : 2.5 أو أحدث، لكن ليس 3.0. على جهاز الدورة، اختار init الإصدار v2.9.1. |
provider "local" {} | « فعّل هذا المزوّد. » الأقواس فارغة لأن المزوّد local ليس لديه ما يُكوَّن (لا منطقة، لا حساب). |
resource "local_file" "message" { … } | « أدِر كائنًا من النوع local_file، أسمّيه message في شيفرتي. » يأتي النوع من المزوّد (local_ + file) ؛ والاسم لك. معًا يشكّلان العنوان local_file.message. |
filename = "${path.module}/message.txt" | أين يُكتب الملف. path.module هو المجلد الذي يحتوي على main.tf هذا ؛ سيعرضه Terraform ./message.txt. |
content = "Bonjour, ce fichier a été créé avec Terraform." | النص الذي يُكتب فيه (« مرحبًا، أُنشئ هذا الملف بـ Terraform. »). هذا السطر هو ما ستغيّره في الخطوة T10. |
يشغّل Terraform الأوامر من المجلد الحالي. إذا كتبت filename = "message.txt"، يُنشأ الملف حيث تكتب terraform apply، وهو عمومًا المجلد الصحيح، لكن ليس دائمًا (عندما تُستدعى الشيفرة كوحدة من مجلد آخر، في الوحدة 5). يشير path.module دائمًا إلى مجلد ملف .tf، بغضّ النظر عن المكان الذي يُشغَّل منه Terraform. تُدرج الصياغة ${…} قيمة تعبير في سلسلة نصية : يصبح "${path.module}/message.txt" هو "./message.txt".
يعمل الأمر رغم ذلك : يستنتج Terraform من النوع local_file أنه يحتاج إلى المزوّد hashicorp/local، ويعرض init : Finding latest version of hashicorp/local... بدلًا من Finding hashicorp/local versions matching "~> 2.5".... هذا ما تفعله الورشتان الأساسيتان في هذه الوحدة، للذهاب إلى الأقصر. لكن بدون قيد إصدار، قد يحصل زميلان يشغّلان init بفارق ستة أشهر على إصدارَين مختلفَين من المزوّد. في مشروع حقيقي، نكتب الكتلة دائمًا.
تُكتب أوامر هذا القسم في المجلد travail/projet-01-local، بعد كتابة main.tf. وهي متطابقة على Windows وLinux وmacOS : Terraform هو البرنامج نفسه في كل مكان. المخرجات هي مخرجات جهاز الدورة (Terraform 1.12.2، Windows 11)، مأخوذة كما هي ؛ فقط المعرّفات (id=ff6b93dc…) والبصمات تتغيّر من جهاز إلى آخر. أما الأوامر التي تعتمد على النظام (قراءة الملف، سرد المجلد)، فهي في ملحقك.
صورة تحتفظ بها لكل القسم : قدّم لك الدرس 01 المهندس المعماري. كل أمر أدناه إحدى حركاته. init يفتتح ورشة البناء، وplan يكتب الكشف، وapply ينفّذه، وstate يعيد قراءة السجل، وdestroy يفكّك كل شيء.
القاعدة : جديد واحد فقط لكل أمر. نبدأ بالأمر الذي لا يأخذ أي معامل ولا يمسّ شيئًا.
terraform versionTerraform v1.12.2
on windows_amd64ما يطلبه الأمر : « يا Terraform، أي إصدار أنت، وعلى أي نظام ؟ » لا معامل، لا ملف مقروء، لا شيء معدَّل. إذا فشل هذا الأمر (terraform : Le terme «terraform» n'est pas reconnu… أو command not found)، فلن يعمل شيء آخر : المشكلة في التثبيت أو PATH، راجع الملحق A.1 أو B.1. على جهاز الدورة، يضيف Terraform أحيانًا سطرَين Your version of Terraform is out of date! : هذه معلومة، لا خطأ.
المقابل المعروف : aws --version، git --version، python --version. الحركة نفسها، الهدف نفسه.
terraform initInitializing the backend...
Initializing provider plugins...
- Finding hashicorp/local versions matching "~> 2.5"...
- Installing hashicorp/local v2.9.1...
- Installed hashicorp/local v2.9.1 (signed by HashiCorp)
Terraform has created a lock file .terraform.lock.hcl to record the provider
selections it made above. Include this file in your version control repository
so that Terraform can guarantee to make the same selections by default when
you run "terraform init" in the future.
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.
…ما يطلبه الأمر : « اقرأ main.tf الخاص بي، ونزّل المزوّدين الذين يطلبهم، وحضّر هذا المجلد للعمل. »
جديد واحد فقط : يصبح المجلد مشروع Terraform. اقرأ المخرجات سطرًا سطرًا :
| السطر | ما حدث |
|---|---|
Initializing the backend... | الـ backend هو المكان الذي سيُحفظ فيه state. لا شيء محدَّد في main.tf، إذًا سيكون ملفًا محليًا، terraform.tfstate. |
Finding hashicorp/local versions matching "~> 2.5"... | قرأ Terraform قيد الإصدار الخاص بك ويبحث على الـ Registry. |
Installing hashicorp/local v2.9.1... | اختار الأحدث الذي يحترم ~> 2.5، وينزّله في .terraform/. |
(signed by HashiCorp) | الإضافة موقَّعة : لديك فعلًا المزوّد الحقيقي. |
Terraform has created a lock file .terraform.lock.hcl | الإصدار المختار مدوَّن في ملف يُحتفظ به في Git : init التالي، عند زميل، سيأخذ الإصدار نفسه. |
Terraform has been successfully initialized! | الجملة المنتظرة. |
ظهر شيئان في مجلدك : المجلد المخفي .terraform/ (المزوّد المنزَّل، حوالي 18 ميغابايت على جهاز الدورة، لا يُوضع في Git أبدًا) والملف .terraform.lock.hcl (22 سطرًا، يُوضع في Git). ستراهما في الملحق، الخطوة A.6 أو B.6.
المقابل المعروف : npm install أو pip install -r requirements.txt. نقرأ قائمة تبعيات، وننزّل، ونقفل الإصدارات (package-lock.json).
يرفض Terraform المتابعة ويقول لك ماذا تفعل. يجيب terraform plan بدون init :
Error: Inconsistent dependency lock file
The following dependency selections recorded in the lock file are
inconsistent with the current configuration:
- provider registry.terraform.io/hashicorp/local: required by this configuration but no version is selected
To make the initial dependency selections that will initialize the dependency
lock file, run:
terraform initوterraform validate بدون init :
Error: Missing required provider
This configuration requires provider registry.terraform.io/hashicorp/local,
but that provider isn't available. You may be able to install it
automatically by running:
terraform initفي الحالتَين، السطر الأخير هو الحل. يمكن إعادة تشغيل init بلا خطر كما تشاء ؛ لا يمسّ مواردك أبدًا.
terraform fmtما يطلبه الأمر : « أعد محاذاة المسافات والإزاحات في ملفاتي .tf وفق الأسلوب الرسمي. »
جديد واحد فقط : المخرجات الفارغة. يعرض fmt اسم كل ملف عدّله ؛ إذا لصقت الشيفرة كما هي، فليس لديه ما يصحّحه ولا يعرض شيئًا. هذا ليس خطأ، بل أفضل إجابة ممكنة. لو كنت أزحت سطرًا بشكل خاطئ، لكان عرض main.tf وأعاد كتابة الملف.
المقابل المعروف : prettier --write، black، gofmt. تتحقق العُدّة من هذه النقطة بـ terraform fmt -check -recursive، الذي لا يعدّل شيئًا ويخرج بخطأ (الرمز 3) إذا لم يكن ملف بالتنسيق الصحيح.
terraform validateSuccess! The configuration is valid.ما يطلبه الأمر : « أعد قراءة كتلي. هل أسماء الوسائط موجودة، هل الأقواس مغلقة، هل تشير المراجع إلى شيء ما ؟ »
جديد واحد فقط : يستشير Terraform المزوّد لمعرفة الوسائط الصالحة لـ local_file. لذلك يطلب validate تنفيذ init قبله. لا يقرأ state، ولا يتصل بأي API، ولا ينشئ شيئًا. الجملة المنتظرة : Success! The configuration is valid.
ما يلتقطه : contenu بدلًا من content (An argument named "contenu" is not expected here. Did you mean "content"?)، قوس منسي (Error: Unclosed configuration block)، علامة اقتباس غير مغلقة (Error: Unterminated template string)، نوع غير موجود (The provider hashicorp/local does not support resource type "local_fichier".). يستعرضها الملحق C واحدة واحدة.
ما لا يلتقطه : مسار غير موجود، اسم bucket مأخوذ أصلًا، معمارية سيئة. يقول validate « هذا HCL صحيح »، لا « هذه فكرة جيدة ».
terraform planTerraform 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:
# local_file.message will be created
+ resource "local_file" "message" {
+ content = "Bonjour, ce fichier a été créé avec Terraform."
+ content_base64sha256 = (known after apply)
+ content_base64sha512 = (known after apply)
+ content_md5 = (known after apply)
+ content_sha1 = (known after apply)
+ content_sha256 = (known after apply)
+ content_sha512 = (known after apply)
+ directory_permission = "0777"
+ file_permission = "0777"
+ filename = "./message.txt"
+ id = (known after apply)
}
Plan: 1 to add, 0 to change, 0 to destroy.
─────────────────────────────────────────────────────────────────────────────
Note: You didn't use the -out option to save this plan, so Terraform can't
guarantee to take exactly these actions if you run "terraform apply" now.ما يطلبه الأمر : « قارن ما تصفه شيفرتي بما تعرفه أصلًا، وقل لي ماذا ستفعل، دون أن تفعله. »
جديد واحد فقط : الكشف. لم يُنشأ شيء ؛ message.txt ما زال غير موجود. اقرأه من الأعلى إلى الأسفل :
| السطر | كيف تقرأه |
|---|---|
+ create | المفتاح : في هذه الخطة، لا يوجد سوى إنشاءات. |
# local_file.message will be created | عنوان المورد (النوع . الاسم) ومصيره. |
+ resource "local_file" "message" { | الكتلة بأكملها مسبوقة بـ + : كل شيء جديد. |
+ content = "Bonjour, …" | خاصية كتبتها أنت : يعرف Terraform قيمتها. |
+ content_md5 = (known after apply) | خاصية سيحسبها المزوّد بعد الإنشاء : بصمة المحتوى. لا يستطيع Terraform تخمينها قبل ذلك. |
+ directory_permission = "0777" | خاصية لم تكتبها : للمزوّد قيمة افتراضية. |
+ filename = "./message.txt" | ${path.module}/message.txt الخاص بك، محلولًا. |
Plan: 1 to add, 0 to change, 0 to destroy. | السطر الذي يُقرأ أولًا، دائمًا. إنشاء واحد، لا تعديل، لا تدمير. |
Note: You didn't use the -out option… | معلومة : هذا الكشف غير مسجَّل ؛ سيعيد apply حسابه. بلا أهمية هنا. |
المقابل المعروف : git diff قبل git commit، أو وضع « المحاكاة » (--dry-run، -WhatIf) في سكربت. الفرق : يُظهر لك سكربت --dry-run ما سيفعله ؛ ويُظهر لك terraform plan ما ينقص بين الشيفرة والواقع، بعد إعادة قراءة الواقع.
يعرض المزوّد local، لـ local_file، كل ما يعرف حسابه : ست بصمات للمحتوى (md5، sha1، sha256، sha512، ونسختان مشفَّرتان بـ base64)، والأذونات، والمعرّف. لم تكتب منها سوى اثنتَين (filename، content) ؛ والباقي خصائص يملؤها المزوّد. الأمر نفسه لـ bucket S3 : تكتب ثلاثة أسطر، وتعرض الخطة ثلاثين (ARN، المنطقة، معرّف المالك…). تعلّم التعرّف على أسطرك وتصفّح الأخرى سريعًا، ما عدا السطر الأخير Plan: الذي لا يُتصفَّح سريعًا أبدًا.
terraform applyTerraform 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:
# local_file.message will be created
+ resource "local_file" "message" {
+ content = "Bonjour, ce fichier a été créé avec Terraform."
…
+ filename = "./message.txt"
+ id = (known after apply)
}
Plan: 1 to add, 0 to change, 0 to destroy.
Do you want to perform these actions?
Terraform will perform the actions described above.
Only 'yes' will be accepted to approve.
Enter a value: yes
local_file.message: Creating...
local_file.message: Creation complete after 0s [id=ff6b93dc92e7e1d2ba4f9dad3cc16e03ac649b45]
Apply complete! Resources: 1 added, 0 changed, 0 destroyed.ما يطلبه الأمر : « أعد حساب الكشف، أرِني إياه، وإذا أجبت بـ yes، نفّذه. »
جديد واحد فقط : السؤال. يتوقف Terraform عند Enter a value: وينتظر. اكتب yes كاملة، ثم Enter. y أو Y أو oui أو سطر فارغ يعطي Apply cancelled. ولا يُمسّ شيء : هذه حماية، لا عيب. ثم ثلاثة أسطر : Creating...، وCreation complete after 0s [id=…] (المعرّف الذي كانت الخطة تعلنه (known after apply) معروف الآن)، والجملة المنتظرة : Apply complete! Resources: 1 added, 0 changed, 0 destroyed. الأعداد الثلاثة هي أعداد الخطة.
الآن، message.txt موجود في مجلدك، وظهر ملف جديد بجانبه : terraform.tfstate. اذهب للتحقق منه بملحقك (A.6 أو B.6) قبل المتابعة : يحتوي الملف فعلًا على Bonjour, ce fichier a été créé avec Terraform.
المقابل المعروف : سكربت يكتب الملف، Set-Content أو echo > message.txt. الفرق : يكتب السكربت وينسى ؛ ويكتب Terraform ويدوّن في سجله أنه كتب، وتحت أي معرّف، وبأي محتوى.
terraform state listlocal_file.messageما يطلبه الأمر : « اسرد كل ما تديره في هذا المجلد. »
جديد واحد فقط : state يُقرأ. سطر واحد، مورد واحد : العنوان local_file.message، نفسه كما في الخطة. يثبت هذا السطر أن Terraform ربط كتلة شيفرتك بالملف الحقيقي : هذا ما سيتيح له تعديله أو تدميره لاحقًا دون أن تعيد إخباره أيّهما.
قبل apply، كان الأمر نفسه يجيب No state file was found! : لم يكن السجل موجودًا بعد. وبعد destroy (T12)، لن يجيب بشيء على الإطلاق.
المقابل المعروف : docker ps، kubectl get pods، aws s3 ls. « ما الذي يعمل، ما الذي يوجد ؟ » إلا أن state list لا يذهب ليرى الواقع : إنه يقرأ دفتره.
terraform state show local_file.message# local_file.message:
resource "local_file" "message" {
content = "Bonjour, ce fichier a été créé avec Terraform."
content_base64sha256 = "G+tDdGue1Lx5hU3LpqBWf3y3haa0ggckj6t/9bj5ocs="
content_base64sha512 = "oB7gPsGHBDNnXe9Hzx4zQ3/nAF1kM9wlfDV/OdMjPybCPurPeN4P8myOoZxFg3dwvs+xLBRJxo4Q3H0qGS8l5g=="
content_md5 = "6daf774f0eb6d3da439c871afec7cf90"
content_sha1 = "ff6b93dc92e7e1d2ba4f9dad3cc16e03ac649b45"
content_sha256 = "1beb43746b9ed4bc79854dcba6a0567f7cb785a6b48207248fab7ff5b8f9a1cb"
content_sha512 = "a01ee03ec1870433675def47cf1e33437fe7005d6433dc257c357f39d3233f26c23eeacf78de0ff26c8ea19c45837770becfb12c1449c68e10dc7d2a192f25e6"
directory_permission = "0777"
file_permission = "0777"
filename = "./message.txt"
id = "ff6b93dc92e7e1d2ba4f9dad3cc16e03ac649b45"
}ما يطلبه الأمر : « أرِني كل ما تعرفه عن المورد local_file.message. »
جديد واحد فقط : يأخذ الأمر معاملًا، العنوان المقروء في T7. قارن مع خطة T5 : كل القيم (known after apply) ممتلئة الآن. الـ id هو بصمة SHA-1 للمحتوى، القيمة نفسها كـ content_sha1 وكـ [id=…] الذي عرضه apply. هذا سجل المهندس المعماري، غرفةً غرفة.
إذا أخطأت في العنوان (local_file.mesage)، يجيب Terraform بـ No instance found for the given address! ويحيلك إلى terraform state list.
الملف terraform.tfstate هو JSON : رقم تسلسلي ("serial")، وإصدار Terraform، وقائمة "resources" حيث لكل مورد بالضبط الخصائص التي يعرضها لك state show. يمكنك فتحه لقراءته. لا تعدّله أبدًا يدويًا : فاصلة منزاحة، ولن يتعرّف Terraform بعدها على ما بناه، أو سيعتقد أنه يدير شيئًا لم يعد موجودًا. للتصرف في state، توجد أوامر (terraform state rm، terraform state mv، terraform import) ستراها في الوحدة 4.
قاعدتان أخريان، منذ اليوم. قد يحتوي state على أسرار (هنا، نص الملف ؛ في مكان آخر، كلمة مرور قاعدة بيانات) : لا يُشارَك عبر رسالة ولا يُودَع في Git. وهو ذاكرة Terraform الوحيدة : إذا حذفته، يعتقد Terraform أن لا شيء موجود ويقترح إعادة إنشاء كل شيء، في حين أن الموارد ما زالت هناك، وفي السحابة، ما زالت تُفوتَر.
terraform outputWarning: No outputs found
The state file either has no outputs defined, or all the defined outputs are
empty. Please define an output in your configuration with the `output`
keyword and run `terraform refresh` for it to become available. If you are
using interpolation, please verify the interpolated value is not empty. You
can use the `terraform console` command to assist.ما يطلبه الأمر : « اعرض القيم التي اختارت الشيفرة إظهارها بكتل output. »
جديد واحد فقط : تحذير (Warning)، لا خطأ. لا يملك main.tf الخاص بك أي كتلة output، إذًا ليس لدى Terraform ما يعرضه ويقول لك ذلك. ستكتب أول outputs لك في المشروع 02 ؛ هنا، يُستخدم الأمر لرؤية الفرق بين « فشل الأمر » (Error:) و« لا شيء لعرضه » (Warning:).
افتح main.tf، واستبدل سطر content بهذا، واحفظ :
content = "Deuxième version du fichier créée avec Terraform."ثم :
terraform planlocal_file.message: Refreshing state... [id=ff6b93dc92e7e1d2ba4f9dad3cc16e03ac649b45]
Terraform used the selected providers to generate the following execution
plan. Resource actions are indicated with the following symbols:
-/+ destroy and then create replacement
Terraform will perform the following actions:
# local_file.message must be replaced
-/+ resource "local_file" "message" {
~ content = "Bonjour, ce fichier a été créé avec Terraform." -> "Deuxième version du fichier créée avec Terraform." # forces replacement
~ content_base64sha256 = "G+tDdGue1Lx5hU3LpqBWf3y3haa0ggckj6t/9bj5ocs=" -> (known after apply)
~ content_base64sha512 = "oB7gPsGHBDNnXe9Hzx4zQ3/nAF1kM9wlfDV/OdMjPybCPurPeN4P8myOoZxFg3dwvs+xLBRJxo4Q3H0qGS8l5g==" -> (known after apply)
~ content_md5 = "6daf774f0eb6d3da439c871afec7cf90" -> (known after apply)
~ content_sha1 = "ff6b93dc92e7e1d2ba4f9dad3cc16e03ac649b45" -> (known after apply)
~ content_sha256 = "1beb43746b9ed4bc79854dcba6a0567f7cb785a6b48207248fab7ff5b8f9a1cb" -> (known after apply)
~ content_sha512 = "a01ee03ec1870433675def47cf1e33437fe7005d6433dc257c357f39d3233f26c23eeacf78de0ff26c8ea19c45837770becfb12c1449c68e10dc7d2a192f25e6" -> (known after apply)
~ id = "ff6b93dc92e7e1d2ba4f9dad3cc16e03ac649b45" -> (known after apply)
# (3 unchanged attributes hidden)
}
Plan: 1 to add, 0 to change, 1 to destroy.ما يطلبه الأمر : الشيء نفسه كما في T5. لكن هذه المرة لدى Terraform سجل للمقارنة.
جديد واحد فقط : الرمز -/+، « تدمير ثم إعادة إنشاء ». ثلاثة مؤشرات تقول لك ذلك، ويجب أن تعرف التعرّف عليها :
| المؤشر | أين | ما يقوله |
|---|---|---|
must be replaced | العنوان # local_file.message must be replaced | ليس will be updated in-place. |
# forces replacement | في نهاية السطر ~ content = "…" -> "…" | هذه الخاصية هي التي تُلزم بالاستبدال. يقول ~ أمامها إن القيمة تتغيّر ؛ ويقول التعليق إن هذا التغيير لا يمكن إجراؤه في المكان. |
Plan: 1 to add, 0 to change, 1 to destroy. | السطر الأخير | تدمير واحد وإنشاء واحد، صفر تعديل. |
انظر أيضًا إلى السطر الأول، الجديد : Refreshing state... [id=…]. قبل المقارنة، ذهب Terraform ليعيد قراءة الملف الحقيقي للتحقق من أنه ما زال مطابقًا لسجله. هنا كان سيكشف انحرافًا (الدرس 01)، لو كنت عدّلت message.txt يدويًا.
الفرق الجوهري بين
~و-/+. بالنسبة لملف نصي، الاستبدال أو التعديل في المكان يؤدّيان إلى النتيجة نفسها : في النهاية، المحتوى هو الجديد. أما بالنسبة لقاعدة بيانات أو قرص أو مستخدم، فـ-/+يعني فقدان الكائن ومعرّفه : بيانات القرص، وكلمة مرور المستخدم، وعنوان IP الخادم. المزوّد هو من يقرّر، خاصيةً خاصية، ما يفرض استبدالًا ؛ وأنت تقرأ ذلك في الخطة قبل أن تقولyes. يستبدل المزوّدlocalالملف بمجرد تغييرcontent: لا~وحده أبدًا لهذه الخاصية.
terraform apply…
Plan: 1 to add, 0 to change, 1 to destroy.
Do you want to perform these actions?
Terraform will perform the actions described above.
Only 'yes' will be accepted to approve.
Enter a value: yes
local_file.message: Destroying... [id=ff6b93dc92e7e1d2ba4f9dad3cc16e03ac649b45]
local_file.message: Destruction complete after 0s
local_file.message: Creating...
local_file.message: Creation complete after 0s [id=1df9196ac94445f0943c35b75c8c2e1bdf3e0cd6]
Apply complete! Resources: 1 added, 0 changed, 1 destroyed.ما يطلبه الأمر : الشيء نفسه كما في T6.
لا جديد في الأمر ؛ كل شيء في المخرجات. أربعة أسطر إجراء بدلًا من سطرَين : Destroying...، Destruction complete، ثم Creating...، Creation complete. الترتيب هو ترتيب الرمز -/+ : الناقص أولًا، ثم الزائد. وتغيّر المعرّف (ff6b93dc… قبل، 1df9196a… بعد) : إنه كائن آخر، ليس الكائن نفسه معدَّلًا. تحقق من المحتوى الجديد بملحقك (A.8 أو B.8) : Deuxième version du fichier créée avec Terraform.
حصيلة T5 إلى T11 : رأيت الكشفَين اللذَين ستعيد قراءتهما طوال مسارك المهني : + (إنشاء) و-/+ (استبدال). الثالث، ~ (تعديل في المكان)، غير موجود لـ content في local_file ؛ ستصادفه في المشاريع السحابية، مثلًا عندما يتغيّر وسم (tag) على مورد AWS.
terraform destroylocal_file.message: Refreshing state... [id=1df9196ac94445f0943c35b75c8c2e1bdf3e0cd6]
Terraform used the selected providers to generate the following execution
plan. Resource actions are indicated with the following symbols:
- destroy
Terraform will perform the following actions:
# local_file.message will be destroyed
- resource "local_file" "message" {
- content = "Deuxième version du fichier créée avec Terraform." -> null
- content_base64sha256 = "36Hz+L76pjLbvY4LIzPfw+UsqNneFneSfFGjtfRLxkI=" -> null
…
- filename = "./message.txt" -> null
- id = "1df9196ac94445f0943c35b75c8c2e1bdf3e0cd6" -> null
}
Plan: 0 to add, 0 to change, 1 to destroy.
Do you really want to destroy all resources?
Terraform will destroy all your managed infrastructure, as shown above.
There is no undo. Only 'yes' will be accepted to confirm.
Enter a value: yes
local_file.message: Destroying... [id=1df9196ac94445f0943c35b75c8c2e1bdf3e0cd6]
local_file.message: Destruction complete after 0s
Destroy complete! Resources: 1 destroyed.ما يطلبه الأمر : « دمّر كل ما تديره في هذا المجلد، وأرِني الكشف أولًا. »
جديد واحد فقط : الرمز - وحده، وسؤال أخطر : Do you really want to destroy all resources? … There is no undo. تنتقل كل خاصية إلى -> null : لن يبقى شيء. الجملة المنتظرة : Destroy complete! Resources: 1 destroyed. اختفى الملف message.txt من مجلدك.
هذا هو الأمر الذي يختم كل جلسة في هذه الدورة. هنا يمحو ملفًا نصيًا ؛ وفي المشروع 03 سيحذف bucket كان، لولا ذلك، سيبقى مُفوتَرًا.
terraform state listما يطلبه الأمر : الطلب نفسه كما في T7.
لا جديد، ومخرجات فارغة : لم يعد Terraform يدير شيئًا في هذا المجلد. ما زال الملف terraform.tfstate موجودًا، لكن قائمته "resources" هي []، وظهر terraform.tfstate.backup بجانبه (نسخة ما قبل destroy، التي يحتفظ بها Terraform احتياطًا). يجعلك ملحقك (A.9 وA.10، أو B.9 وB.10) تسرد المجلد وتشغّل etat للدليل النهائي : Ressources encore gérées : 0 (0 attendu à la fin d'une séance).
حصيلة T1 إلى T13 : init مرة واحدة، ثم fmt، validate، plan، apply، state list، state show، ثم plan وapply للتعديل، ثم destroy، ثم state list. ثلاثة عشر أمرًا، خمس جمل يجب التعرّف عليها : successfully initialized!، The configuration is valid.، Plan: N to add, N to change, N to destroy.، Apply complete!، Destroy complete!.
الرسالة التي يجب إيصالها. كان سكربت PowerShell أو bash سيكتب
message.txtفي سطر واحد، ويحذفه في سطر آخر. ما لا يفعله السكربت ورأيت Terraform يفعله : الإعلان قبل التصرف (plan)، وطلب موافقة صريحة (yes)، وتدوين ما أنشأه (state list)، وإعادة قراءة الواقع قبل كل قرار (Refreshing state...)، والتمييز بين التعديل والاستبدال (-/+)، ومعرفة فكّ كل شيء دون أن يُعاد إخباره بماذا (destroy).
لا يمسّ المشروع 01 حساب AWS. لكن المشروع 03 ينشئ bucket S3 حقيقيًا، وستحتاج إلى حساب جاهز. يُنجَز هذا القسم في المتصفح، وهو متطابق على Windows وLinux وmacOS، ويمكنك إنجازه قبل دورة Terraform في هذا المشروع أو بعدها. الأمران aws configure وaws sts get-caller-identity المرافقان له موجودان في ملحقك (A.2 أو B.2).
إذا كنت تعمل في AWS Academy أو AWS Educate أو sandbox توفّره المدرسة أو حساب مختبر مؤقت : استخدم بيانات الاعتماد التي تقدّمها المنصة وانتقل مباشرة إلى الخطوة A.2 أو B.2 (حالة « Academy »). لا تُنشئ مستخدم IAM إذا كان معلّمك يمنحك أصلًا وصولًا مؤقتًا.
ca-central-1 إذا لم يفرض المختبر منطقة أخرى.يُستخدم حساب root فقط لإنشاء الحساب، وإدارة الفوترة، والقيام بالعمليات الحسّاسة. فعّل MFA (المصادقة الثنائية) على حساب root، ثم أنشئ مستخدمًا منفصلًا لعمل المختبر، كما يلي.
IAM وافتح خدمة IAM.terraform-admins.AdministratorAccess، وحدّد السياسة AdministratorAccess.للمختبر فقط. يمنح
AdministratorAccessوصولًا كاملًا إلى كل خدمات الحساب وموارده. هذا عملي للتعلّم ؛ وليس نموذج أمان للإنتاج، حيث نمنح Terraform الأذونات التي يحتاجها فقط (الوحدة 4).
terraform-admin.terraform-admins → Next → Create user.terraform-admin.aws-cli-terraform-lab → Create access key..csv أو انسخ Access key وSecret access key في مدير كلمات مرور. لن تُعرض Secret access key مرة أخرى أبدًا.ما لا يجب فعله أبدًا. لا تلصق أبدًا Access Key أو Secret Access Key أو رمز جلسة أو ملف
.envأوterraform.tfstateفي GitHub أو Word أو Teams أو Discord أو Slack أو تذكرة أو بريد إلكتروني. تمنح هذه العناصر الوصول إلى الحساب. إذا تسرّب مفتاح : IAM → المستخدم → Security credentials → Deactivate ثم Delete، ونُنشئ آخر.
قبل إعادة تشغيل terraform destroy مرة ثانية على مجلد دُمّر أصلًا، اكتب على الورق ما سيقوله السطر الأخير من الخطة. ثم شغّله. بعد ذلك، أعد إنشاء الملف بـ terraform apply، وافتح message.txt في VS Code، وأضف كلمة يدويًا، واحفظ، واكتب terraform plan : ماذا يقول سطر Refreshing state...، وأي رمز يظهر، وكيف يُسمّى هذا الفارق في الدرس 01 ؟ اختم بـ destroy : يجب أن يعود المجلد إلى Ressources encore gérées : 0.
تُكتب كل أوامر هذا الملحق في PowerShell (Windows Terminal أو PowerShell 7)، بـ .\labo.ps1 …. المخرجات المنسوخة هي مخرجات جهاز الدورة، على Windows 11 وTerraform 1.12.2.
git --version يجيب)، VS Code مثبَّت مع الأمر code متاحًا في PowerShell (وإلا : VS Code → Ctrl+Shift+P → « Shell Command: Install 'code' command in PATH »، أو أعد التثبيت مع تحديد « Add to PATH »)..\labo.ps1 (رسالة تفيد بأن تنفيذ السكربتات معطَّل على هذا النظام) : Set-ExecutionPolicy -Scope CurrentUser RemoteSigned، أجب بـ O، وأعد التشغيل. مرة واحدة فقط لكل جهاز..\labo.ps1 etat : Ressources encore gérées : 0 (0 attendu à la fin d'une séance).الأبسط، بمدير حزم Windows :
winget install Hashicorp.Terraformأغلق PowerShell، وأعد فتحه، ثم :
terraform versionنقطة التحقق :
Terraform v1.12.2
on windows_amd64قد يكون إصدارك أحدث ؛ كل ما هو 1.6 أو أعلى مناسب. إذا أضاف Terraform Your version of Terraform is out of date!، فهذه معلومة، لا خطأ.
بدون winget، بالملف التنفيذي الرسمي : اذهب إلى https://developer.hashicorp.com/terraform/install، واختر Windows، ونزّل الإصدار AMD64، وفكّ ضغط .zip، وأنشئ المجلد C:\terraform، وانقل terraform.exe إليه، ثم أضف C:\terraform إلى PATH : قائمة ابدأ → « متغيرات البيئة » → تحرير متغيرات بيئة النظام → متغيرات البيئة → في متغيرات النظام، حدّد Path → تحرير → جديد → C:\terraform → موافق. أغلق كل نوافذ PowerShell، وأعد الفتح، وأعد كتابة terraform version.
إذا رأيت شيئًا آخر : terraform : Le terme «terraform» n'est pas reconnu comme nom d'applet de commande… → Terraform ليس في PATH، أو لم يُعاد تشغيل PowerShell بعد التثبيت. الملحق C.
لا يستخدم المشروع 01 حساب AWS ؛ تحضّر هذه الخطوة المشروع 03. يمكنك إنجازها الآن أو تأجيلها.
.msi : Next، اقبل الترخيص، احتفظ بالمجلد الافتراضي، Install.aws --versionنقطة التحقق : إصدار يبدأ بـ aws-cli/2 (على جهاز الدورة : aws-cli/2.22.18). إذا رأيت aws-cli/1، فهذا الإصدار القديم : ألغِ تثبيته.
ثم كوّن المفاتيح المُنشأة في القسم وحدة تحكم AWS، في المتصفح :
aws configureAWS Access Key ID [None]: TON_ACCESS_KEY_ID
AWS Secret Access Key [None]: TA_SECRET_ACCESS_KEY
Default region name [None]: ca-central-1
Default output format [None]: jsonتحقق من أن CLI يتحدث فعلًا إلى AWS :
aws sts get-caller-identityمثال على الإجابة (القيم هي قيم حسابك) :
{
"UserId": "AIDA...",
"Account": "123456789012",
"Arn": "arn:aws:iam::123456789012:user/terraform-admin"
}حالة AWS Academy أو sandbox مؤقت : افتح المختبر، وانقر على AWS Details أو Credentials، وانسخ Access Key وSecret Key وSession Token (إلزامي مع الوصول المؤقت)، ثم :
aws configure set aws_access_key_id TON_ACCESS_KEY_ID
aws configure set aws_secret_access_key TA_SECRET_ACCESS_KEY
aws configure set aws_session_token TON_SESSION_TOKEN
aws configure set region ca-central-1
aws configure set output json
aws sts get-caller-identityانتقل إلى المجلد الذي تحفظ فيه مشاريعك (مثلًا C:\Users\<toi>\Documents)، ثم :
git clone https://github.com/hrhouma2/aiopsatlas-terraform-labo-fr.git lab-terraform
cd lab-terraform
dirنقطة التحقق : يسرد dir : projets، labo.ps1، labo.sh، README.md (و.gitattributes، .gitignore مع dir -Force). ثم :
.\labo.ps1 prerequisOK terraform 1.12.2
OK aws 2.22.18
OK git 2.49.0.windows.1
OK code 1.135.0
OK gh 2.81.0 (optionnel)
ABSENT az (optionnel, projet 08B seulement)
OK gcloud 544.0.0 (optionnel)
Prérequis : 4 outils requis présents sur 4.الأدوات الأربع المطلوبة هي terraform وaws وgit وcode. أما gh وaz وgcloud فاختيارية ويمكن أن تكون ABSENT (غائبة) بلا عواقب قبل الوحدة 3. إذا كان aws بحالة ABSENT لأنك أجّلت A.2، فيقول السطر الأخير 3 outils requis présents sur 4 (3 أدوات مطلوبة موجودة من 4) : يمكنك رغم ذلك متابعة هذا المشروع.
.\labo.ps1 nouveau projet-01-localDossier travail\projet-01-local créé (ignoré par Git). Tapez :
cd travail\projet-01-localافعل ما يقوله لك السكربت (« أُنشئ المجلد … (يتجاهله Git). اكتب : »)، ثم افتح المجلد في VS Code :
cd travail\projet-01-local
code .يتجاهل Git المجلد travail\ : يمكنك الكتابة فيه بحرية دون تلويث العُدّة. يبقى الحل النموذجي في projets\01-terraform-local\.
إذا لم يفعل code . شيئًا : افتح VS Code يدويًا، File → Open Folder، واختر lab-terraform\travail\projet-01-local.
main.tfفي VS Code : أيقونة New File في المستكشف الأيسر، سمِّ الملف main.tf (انتبه : ليس main.tf.txt، لا يضيف VS Code امتدادًا لكن المفكرة في Windows تفعل ذلك)، والصق شيفرة القسم الشيفرة : ملفًا ملفًا، واحفظ بـ Ctrl+S.
تحقق من PowerShell :
Get-Content .\main.tfنقطة التحقق : الأسطر الخمسة عشر للملف، من terraform { إلى }. ثم :
Get-ChildItemمدخل واحد فقط : main.tf. إذا رأيت main.tf.txt، فأعد التسمية : Rename-Item main.tf.txt main.tf.
نفّذ T2 إلى T6 من القسم Terraform، في الطرفية :
terraform init
terraform fmt
terraform validate
terraform plan
terraform applyأجب بـ yes على سؤال apply. نقاط التحقق، بالترتيب : Terraform has been successfully initialized!، لا شيء لـ fmt، Success! The configuration is valid.، Plan: 1 to add, 0 to change, 0 to destroy.، Apply complete! Resources: 1 added, 0 changed, 0 destroyed.
تحقق مما ظهر في المجلد :
Get-ChildItem -Force.terraform
.terraform.lock.hcl
main.tf
message.txt
terraform.tfstate(يعرض -Force أيضًا المدخلات المخفية، التي يبدأ اسمها بنقطة ؛ بدونه، لن ترى سوى main.tf وmessage.txt وterraform.tfstate.) خمسة مدخلات :
| المدخل | من أنشأه | ما هو |
|---|---|---|
.terraform | init | مجلد مخفي، المزوّد المنزَّل. أبدًا في Git. |
.terraform.lock.hcl | init | إصدارات المزوّدين المختارة. في Git. |
main.tf | أنت | الشيفرة. |
message.txt | apply | المورد. |
terraform.tfstate | apply | State، السجل. أبدًا في Git، أبدًا مُشارَك. |
اقرأ الملف المُنشأ :
Get-Content .\message.txtBonjour, ce fichier a été créé avec Terraform.يمكنك أيضًا التحقق منه في مستكشف Windows : افتح المجلد lab-terraform\travail\projet-01-local، وانقر نقرًا مزدوجًا على message.txt.
نفّذ T7 وT8 وT9 :
terraform state list
terraform state show local_file.message
terraform outputنقاط التحقق : local_file.message ؛ الكتلة الكاملة مع filename = "./message.txt" وid من أربعين حرفًا ؛ Warning: No outputs found.
إذا كنت فضوليًا، فانظر إلى state نفسه، دون تعديله :
Get-Content .\terraform.tfstateJSON مع "serial" و"terraform_version": "1.12.2" وقائمة "resources" تحتوي على local_file.message. أعد إغلاقه. لا نحرّره يدويًا أبدًا.
في VS Code، استبدل سطر content في main.tf بـ :
content = "Deuxième version du fichier créée avec Terraform."احفظ، ثم نفّذ T10 وT11 :
terraform plan
terraform applyأجب بـ yes. نقاط التحقق : # local_file.message must be replaced، و# forces replacement في نهاية سطر content، وPlan: 1 to add, 0 to change, 1 to destroy.، ثم Apply complete! Resources: 1 added, 0 changed, 1 destroyed.
Get-Content .\message.txtDeuxième version du fichier créée avec Terraform.نفّذ T12 وT13 :
terraform destroy
terraform state listأجب بـ yes. نقاط التحقق : Destroy complete! Resources: 1 destroyed.، ثم مخرجات فارغة لـ state list.
Get-ChildItem -Force.terraform
.terraform.lock.hcl
main.tf
terraform.tfstate
terraform.tfstate.backupاختفى message.txt. ما زال terraform.tfstate موجودًا لكنه لم يعد يحتوي على مورد ؛ وterraform.tfstate.backup هو نسخة ما قبل destroy. يبقى .terraform و.terraform.lock.hcl : هذا طبيعي، سيفيدانك إذا أعدت تشغيل apply.
اصعد إلى جذر العُدّة وشغّل etat :
cd ..\..
.\labo.ps1 etattravail projet-01-local : aucune ressource
Ressources encore gérées : 0 (0 attendu à la fin d'une séance).(أي : « travail projet-01-local : لا موارد » و« الموارد التي ما زالت مُدارة : 0 (0 متوقع في نهاية الجلسة) ».) لو كنت نسيت destroy، لكانت المخرجات تقول travail projet-01-local : 1 ressource dans le state ثم Ressources encore gérées : 1 (0 attendu à la fin d'une séance). : هذا هو الحاجز الوقائي الذي ستشغّله في نهاية كل جلسة، عندما تكون الموارد مُفوتَرة.
لإعادة البدء من الصفر، بدلًا من تنظيف المجلد : .\labo.ps1 nouveau projet-01-reprise، وتنطلق من مجلد فارغ.
تُكتب كل أوامر هذا الملحق في طرفية bash (أو zsh على macOS)، بـ ./labo.sh …. مخرجات Terraform هي مخرجات جهاز الدورة (Terraform 1.12.2) ؛ أما مخرجات ls -la فأُخذت تحت Git Bash، وتختلف أعمدة الحقوق والمالك والتاريخ عندك.
git --version يجيب)، VS Code مثبَّت مع الأمر code متاحًا في الطرفية (على macOS : VS Code → Cmd+Shift+P → « Shell Command: Install 'code' command in PATH »)../labo.sh بـ Permission denied : chmod +x labo.sh، مرة واحدة فقط../labo.sh etat : Ressources encore gérées : 0 (0 attendu à la fin d'une séance).اتبع الصفحة الرسمية https://developer.hashicorp.com/terraform/install لنظامك. باختصار :
apt مع مفتاح GPG، أوامر منسوخة من الصفحة الرسمية)، ثم sudo apt-get install terraform.brew tap hashicorp/tap ثم brew install hashicorp/tap/terraform..zip Linux AMD64 (أو ARM64)، unzip، ثم sudo mv terraform /usr/local/bin/.winget)، يراه Git Bash في PATH.أغلق الطرفية، وأعد فتحها، ثم :
terraform versionنقطة التحقق : Terraform v1.12.2 (أو أحدث) يليه on linux_amd64 أو on darwin_arm64 أو on windows_amd64 بحسب جهازك. كل ما هو 1.6 أو أعلى مناسب.
إذا رأيت شيئًا آخر : bash: terraform: command not found → الملف التنفيذي ليس في مجلد من PATH (echo $PATH)، أو لم تُعاد فتح الطرفية. الملحق C.
لا يستخدم المشروع 01 حساب AWS ؛ تحضّر هذه الخطوة المشروع 03. يمكنك إنجازها الآن أو تأجيلها.
اتبع https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html لنظامك (حزمة .zip مع ./aws/install على Linux، .pkg على macOS). ثم :
aws --versionنقطة التحقق : إصدار يبدأ بـ aws-cli/2. إذا رأيت aws-cli/1، فهذا الإصدار القديم : ألغِ تثبيته.
كوّن المفاتيح المُنشأة في القسم وحدة تحكم AWS، في المتصفح :
aws configureAWS Access Key ID [None]: TON_ACCESS_KEY_ID
AWS Secret Access Key [None]: TA_SECRET_ACCESS_KEY
Default region name [None]: ca-central-1
Default output format [None]: jsonتحقق من أن CLI يتحدث فعلًا إلى AWS :
aws sts get-caller-identityمثال على الإجابة (القيم هي قيم حسابك) :
{
"UserId": "AIDA...",
"Account": "123456789012",
"Arn": "arn:aws:iam::123456789012:user/terraform-admin"
}حالة AWS Academy أو sandbox مؤقت : افتح المختبر، وانقر على AWS Details أو Credentials، وانسخ Access Key وSecret Key وSession Token (إلزامي مع الوصول المؤقت)، ثم :
aws configure set aws_access_key_id TON_ACCESS_KEY_ID
aws configure set aws_secret_access_key TA_SECRET_ACCESS_KEY
aws configure set aws_session_token TON_SESSION_TOKEN
aws configure set region ca-central-1
aws configure set output json
aws sts get-caller-identityانتقل إلى المجلد الذي تحفظ فيه مشاريعك (مثلًا ~/projets)، ثم :
git clone https://github.com/hrhouma2/aiopsatlas-terraform-labo-fr.git lab-terraform
cd lab-terraform
lsنقطة التحقق : يسرد ls : labo.ps1 labo.sh projets README.md (و.gitattributes، .gitignore مع ls -a). ثم :
./labo.sh prerequisOK terraform 1.12.2
OK aws 2.22.18
OK git 2.49.0.windows.1
OK code 1.135.0
OK gh 2.81.0 (optionnel)
ABSENT az (optionnel, projet 08B seulement)
OK gcloud 544.0.0 (optionnel)
Prérequis : 4 outils requis présents sur 4.(مخرجات مأخوذة تحت Git Bash، ومن هنا git 2.49.0.windows.1 ؛ على Linux ستقرأ إصدار Git الخاص بك.) الأدوات الأربع المطلوبة هي terraform وaws وgit وcode. أما gh وaz وgcloud فاختيارية ويمكن أن تكون ABSENT بلا عواقب قبل الوحدة 3. إذا كان aws بحالة ABSENT لأنك أجّلت B.2، فيقول السطر الأخير 3 outils requis présents sur 4 : يمكنك رغم ذلك متابعة هذا المشروع.
./labo.sh nouveau projet-01-localDossier travail/projet-01-local créé (ignoré par Git). Tapez :
cd travail/projet-01-localافعل ما يقوله لك السكربت، ثم افتح المجلد في VS Code :
cd travail/projet-01-local
code .يتجاهل Git المجلد travail/ : يمكنك الكتابة فيه بحرية دون تلويث العُدّة. يبقى الحل النموذجي في projets/01-terraform-local/.
إذا لم يفعل code . شيئًا : افتح VS Code يدويًا، File → Open Folder، واختر lab-terraform/travail/projet-01-local.
main.tfفي VS Code : أيقونة New File في المستكشف الأيسر، سمِّ الملف main.tf، والصق شيفرة القسم الشيفرة : ملفًا ملفًا، واحفظ بـ Ctrl+S (Cmd+S على macOS).
طريق ثالث، بلا محرّر، إذا كنت تفضّل الطرفية :
cat > main.tf <<'EOF'
terraform {
required_providers {
local = {
source = "hashicorp/local"
version = "~> 2.5"
}
}
}
provider "local" {}
resource "local_file" "message" {
filename = "${path.module}/message.txt"
content = "Bonjour, ce fichier a été créé avec Terraform."
}
EOF(تمنع علامتا الاقتباس المفردتان حول 'EOF' bash من تفسير ${path.module} : بدونهما، سيُفرَّغ سطر filename.) تحقق :
cat main.tf
ls -latotal 1
drwxr-xr-x 1 rehou 197609 0 sept. 15 14:47 .
drwxr-xr-x 1 rehou 197609 0 sept. 15 14:47 ..
-rw-r--r-- 1 rehou 197609 286 sept. 15 14:47 main.tfنقطة التحقق : الأسطر الخمسة عشر للملف، ومدخل واحد فقط في المجلد، main.tf، بحجم 286 بايتًا تقريبًا.
نفّذ T2 إلى T6 من القسم Terraform، في الطرفية :
terraform init
terraform fmt
terraform validate
terraform plan
terraform applyأجب بـ yes على سؤال apply. نقاط التحقق، بالترتيب : Terraform has been successfully initialized!، لا شيء لـ fmt، Success! The configuration is valid.، Plan: 1 to add, 0 to change, 0 to destroy.، Apply complete! Resources: 1 added, 0 changed, 0 destroyed.
تحقق مما ظهر في المجلد :
ls -latotal 14
drwxr-xr-x 1 rehou 197609 0 sept. 15 14:47 .
drwxr-xr-x 1 rehou 197609 0 sept. 15 14:47 ..
drwxr-xr-x 1 rehou 197609 0 sept. 15 14:47 .terraform
-rw-r--r-- 1 rehou 197609 1257 sept. 15 14:47 .terraform.lock.hcl
-rw-r--r-- 1 rehou 197609 286 sept. 15 14:47 main.tf
-rw-r--r-- 1 rehou 197609 50 sept. 15 14:47 message.txt
-rw-r--r-- 1 rehou 197609 1667 sept. 15 14:47 terraform.tfstate(يعرض -a أيضًا المدخلات المخفية، التي يبدأ اسمها بنقطة ؛ ويعطي -l التفاصيل.) خمسة مدخلات إضافةً إلى . و.. :
| المدخل | من أنشأه | ما هو |
|---|---|---|
.terraform | init | مجلد مخفي، المزوّد المنزَّل. أبدًا في Git. |
.terraform.lock.hcl | init | إصدارات المزوّدين المختارة. في Git. |
main.tf | أنت | الشيفرة. |
message.txt | apply | المورد. 50 بايتًا : النص، بلا سطر جديد في النهاية. |
terraform.tfstate | apply | State، السجل. أبدًا في Git، أبدًا مُشارَك. |
اقرأ الملف المُنشأ :
cat message.txtBonjour, ce fichier a été créé avec Terraform.(ليس للملف سطر جديد في النهاية : قد يظهر موجّه الأوامر ملتصقًا بنهاية الجملة. هذا طبيعي.)
نفّذ T7 وT8 وT9 :
terraform state list
terraform state show local_file.message
terraform outputنقاط التحقق : local_file.message ؛ الكتلة الكاملة مع filename = "./message.txt" وid من أربعين حرفًا ؛ Warning: No outputs found.
إذا كنت فضوليًا، فانظر إلى state نفسه، دون تعديله :
cat terraform.tfstateJSON مع "serial" و"terraform_version": "1.12.2" وقائمة "resources" تحتوي على local_file.message. أعد إغلاقه. لا نحرّره يدويًا أبدًا.
في VS Code، استبدل سطر content في main.tf بـ :
content = "Deuxième version du fichier créée avec Terraform."احفظ، ثم نفّذ T10 وT11 :
terraform plan
terraform applyأجب بـ yes. نقاط التحقق : # local_file.message must be replaced، و# forces replacement في نهاية سطر content، وPlan: 1 to add, 0 to change, 1 to destroy.، ثم Apply complete! Resources: 1 added, 0 changed, 1 destroyed.
cat message.txtDeuxième version du fichier créée avec Terraform.نفّذ T12 وT13 :
terraform destroy
terraform state listأجب بـ yes. نقاط التحقق : Destroy complete! Resources: 1 destroyed.، ثم مخرجات فارغة لـ state list.
ls -latotal 17
drwxr-xr-x 1 rehou 197609 0 sept. 15 14:47 .
drwxr-xr-x 1 rehou 197609 0 sept. 15 14:47 ..
drwxr-xr-x 1 rehou 197609 0 sept. 15 14:47 .terraform
-rw-r--r-- 1 rehou 197609 1257 sept. 15 14:47 .terraform.lock.hcl
-rw-r--r-- 1 rehou 197609 286 sept. 15 14:47 main.tf
-rw-r--r-- 1 rehou 197609 181 sept. 15 14:47 terraform.tfstate
-rw-r--r-- 1 rehou 197609 1667 sept. 15 14:47 terraform.tfstate.backupاختفى message.txt. انتقل terraform.tfstate من 1667 إلى 181 بايتًا : لم يعد يحتوي على مورد ؛ وterraform.tfstate.backup (1667 بايتًا) هو نسخة ما قبل destroy. يبقى .terraform و.terraform.lock.hcl : هذا طبيعي، سيفيدانك إذا أعدت تشغيل apply.
cat terraform.tfstate{
"version": 4,
"terraform_version": "1.12.2",
"serial": 3,
"lineage": "9ddb3372-803f-0964-7665-8413b8f65ee1",
"outputs": {},
"resources": [],
"check_results": null
}"resources": [] : السجل فارغ. سيكون lineage الخاص بك (المعرّف الفريد لهذا state) مختلفًا.
اصعد إلى جذر العُدّة وشغّل etat :
cd ../..
./labo.sh etattravail projet-01-local : aucune ressource
Ressources encore gérées : 0 (0 attendu à la fin d'une séance).لو كنت نسيت destroy، لكانت المخرجات تقول travail projet-01-local : 1 ressource dans le state ثم Ressources encore gérées : 1 (0 attendu à la fin d'une séance). : هذا هو الحاجز الوقائي الذي ستشغّله في نهاية كل جلسة، عندما تكون الموارد مُفوتَرة.
لإعادة البدء من الصفر، بدلًا من تنظيف المجلد : ./labo.sh nouveau projet-01-reprise، وتنطلق من مجلد فارغ.
كل حالة : الرسالة الدقيقة → السبب → الحركة.
يجيب terraform plan بـ Error: Inconsistent dependency lock file … required by this configuration but no version is selected → لم تشغّل terraform init في هذا المجلد (أو أضفت مزوّدًا منذ ذلك). تنتهي الرسالة بالحل : terraform init، ثم أعد التشغيل.
يجيب terraform validate بـ Error: Missing required provider … You may be able to install it automatically by running: terraform init → السبب نفسه، الحركة نفسها : terraform init.
Error: Unsupported argument … An argument named "contenu" is not expected here. Did you mean "content"? → خطأ مطبعي في اسم وسيط. يقترح Terraform غالبًا الكلمة الصحيحة. صحّح، وأعد الحفظ، وأعد تشغيل validate.
Error: Unclosed configuration block … There is no closing brace for this block before the end of the file. → قوس } ناقص. عدّها : لكل { قوسه }. في main.tf، توجد ثلاثة أزواج متداخلة لكتلة terraform، وزوج لـ provider، وزوج لـ resource.
Error: Invalid multi-line string ثم Error: Unterminated template string … No closing marker was found for the string. → علامة اقتباس " ناقصة في نهاية قيمة. يُستشهد بالسطر الخاطئ (3: content = "Bonjour Terraform).
Error: Invalid resource type … The provider hashicorp/local does not support resource type "local_fichier". → نوع المورد غير موجود في هذا المزوّد. تُسمّى أنواع المزوّد local : local_file وlocal_sensitive_file ؛ تعطي وثائق المزوّد على الـ Registry قائمتها.
Error: Invalid Attribute Combination … No attribute specified when one (and only one) of [content,sensitive_content,content_base64] is required (مكرَّرة أربع مرات) → أزلت سطر content : يجب أن يقول local_file ما يحتويه. أعده.
يقول terraform validate : Success! لكن يجيب terraform plan بـ Error: No configuration files … create a Terraform configuration file (.tf file) and try again. → لا يوجد أي ملف .tf في المجلد : إما أنك لست في travail/projet-01-local (تحقق بـ pwd)، أو أن الملف يُسمّى main.tf.txt. أعد تسميته إلى main.tf. المجلد الفارغ تكوين صالح (فارغ)، ومن هنا Success! المضلِّل.
يجيب terraform apply بـ Apply cancelled. ولا يُنشأ شيء → كتبت شيئًا غير yes (مثلًا y أو Y أو oui أو Enter وحده). أعد التشغيل واكتب yes كاملة.
يجيب terraform state list بـ No state file was found! → لم يُنفَّذ أي apply بعد في هذا المجلد، أو لست في المجلد الصحيح. هذا ليس عطلًا : لا شيء للسرد بعد.
يجيب terraform state show بـ No instance found for the given address! → العنوان مكتوب خطأ، أو دُمّر المورد. يعطي terraform state list العناوين الدقيقة.
يخرج terraform fmt -check بخطأ (الرمز 3) عارضًا main.tf → الملف ليس بالتنسيق الرسمي (الإزاحة، محاذاة =). هذا ليس خطأ صياغة : يصحّحه terraform fmt بدون -check.
بعد destroy، ما زال terraform.tfstate موجودًا وتعتقد أن destroy فشل → لا : افتحه، "resources": []. يبقى الملف، فارغًا، مع terraform.tfstate.backup بجانبه. Destroy complete! Resources: 1 destroyed. هو الحجة.
يعرض .\labo.ps1 etat أو ./labo.sh etat : Ressources encore gérées : 1 → نُسي destroy في أحد المجلدات المسرودة أعلاه (travail projet-01-local : 1 ressource dans le state). اذهب إلى هذا المجلد، terraform destroy، yes، وأعد تشغيل etat.
Windows فقط — terraform : Le terme «terraform» n'est pas reconnu comme nom d'applet de commande, fonction, fichier de script ou programme exécutable. → Terraform ليس في PATH، أو لم يُعاد تشغيل PowerShell بعد التثبيت. أغلق كل نوافذ PowerShell، وأعد الفتح، وأعد كتابة terraform version. إذا استمر الأمر، الملحق A.1 (إضافة C:\terraform إلى PATH).
Windows فقط — aws : Le terme «aws» n'est pas reconnu… → AWS CLI غير مثبَّت أو لم يُعاد تشغيل PowerShell. أعد تثبيت AWS CLI الإصدار 2 (A.2)، وأغلق وأعد فتح PowerShell، وأعد كتابة aws --version.
Windows فقط — .\labo.ps1 مرفوض : رسالة تفيد بأن تنفيذ السكربتات معطَّل على هذا النظام → Set-ExecutionPolicy -Scope CurrentUser RemoteSigned، أجب بـ O، وأعد التشغيل. مرة واحدة فقط لكل جهاز.
Windows فقط — الملف يُسمّى main.tf.txt → تضيف المفكرة .txt. في PowerShell : Rename-Item main.tf.txt main.tf. استخدم VS Code لإنشاء الملفات.
Linux الأصلي وmacOS — bash: terraform: command not found → الملف التنفيذي ليس في مجلد من PATH. sudo mv terraform /usr/local/bin/، أو تحقق من التثبيت بالحزمة (B.1). أعد فتح الطرفية.
macOS وbash — يجيب ./labo.sh بـ Permission denied → chmod +x labo.sh، مرة واحدة فقط. إذا ظهر bash: ./labo.sh: /bin/bash^M: bad interpreter، فللملف نهايات أسطر Windows : git config core.autocrlf input ثم أعد الاستنساخ، أو sed -i 's/\r$//' labo.sh (sed -i '' … على macOS).
يجيب aws sts get-caller-identity بـ AccessDenied أو InvalidClientTokenId → المفتاح المُكوَّن ليس الصحيح، أو انتهت صلاحية رمز جلسة Academy. aws configure بمفتاح terraform-admin (تحقق من أن المستخدم في terraform-admins مع AdministratorAccess)، أو أعد aws configure set … ببيانات اعتماد Academy جديدة. بلا أثر على المشروع 01، الذي لا يستدعي AWS.
مجلد مضغوط أو مستودع Git يحتوي على :
main.tf (الملف النهائي، بالنسخة الثانية من content) ؛sorties.txt : المخرجات الكاملة لـ terraform plan (النسخة الأولى)، وterraform state list بعد apply، وterraform plan الخاص بالتعديل (الذي يحتوي على must be replaced)، وterraform state list بعد destroy (فارغة) ؛README.md على النموذج أدناه.لا تسلّم لا المجلد .terraform/، ولا terraform.tfstate، ولا أي Access Key.
# Projet 01 — Terraform local
- Terraform : (sortie de `terraform version`)
- Système : Windows / Linux / macOS
## Ce que j'ai fait
init, fmt, validate, plan, apply, state list, state show, modification de content, plan, apply, destroy, state list.
## Le fichier terraform.tfstate, en trois lignes à moi
(À quoi il sert. Pourquoi Terraform en a besoin pour destroy. Pourquoi on ne l'édite pas et on ne le partage pas.)
## Ce qui m'a bloqué, et comment j'ai débloqué
(Une ligne, ou « rien ».)(نموذج README بالفرنسية كما في العُدّة : الإصدار والنظام ؛ « ما فعلته » ؛ « ملف terraform.tfstate في ثلاثة أسطر من عندي » — ما فائدته، لماذا يحتاجه Terraform لـ destroy، لماذا لا نحرّره ولا نشاركه ؛ « ما أعاقني وكيف تجاوزته ».)
init، fmt، validate، plan، apply، state، destroy) : https://developer.hashicorp.com/terraform/cli/commandshashicorp/local، المورد local_file : https://registry.terraform.io/providers/hashicorp/local/latest/docs/resources/fileAdministratorAccess : https://docs.aws.amazon.com/aws-managed-policy/latest/reference/AdministratorAccess.htmlجملة تُحفظ : لا ينقر Terraform في وحدة التحكم بدلًا منك. إنه يقرأ شيفرتك، ويقارنها بـ state الخاص به وبالواقع، ويعلن لك ما سيتغيّر، ثم ينشئ أو يستبدل أو يدمّر للوصول إلى الحالة المطلوبة.