كيف تقرأ هذه الصفحة. عشر خطوات، أمر واحد في كل مرة. لكل منها : الأمر، والمخرجات الدقيقة لجهاز الدورة (Terraform 1.12.2)، وما يجب النظر إليه. اكتب كل أمر بنفسك. كتل « لفهم أفضل » اختيارية. أوامر
terraform …متطابقة في كل مكان ؛ وعندما يعتمد أمر على النظام، تُعطى النسختان، إحداهما تحت الأخرى. إذا لم يعد مجلد الورشة 1 موجودًا أو إذا لم يجبstate listبـlocal_file.bonjour، فأعد الورشة الأساسية 1 أولًا (العُدّة :https://github.com/hrhouma2/aiopsatlas-terraform-labo-fr).
جعلتك الورشة 1 تُنشئ موردًا وتقرأ state. لكن البنية التحتية لا تُنشأ مرة واحدة وإلى الأبد : تُعدَّل، ويكسرها أحد سهوًا، ويومًا ما تُفكَّك. هذه هي الحركات الثلاث لهذه الورشة. ستحذف أولًا bonjour.txt يدويًا، كزميل « ينظّف » مجلدًا، وترى Terraform يلاحظ ذلك ثم يعيد إنشاءه : هذا هو الانحراف من الدرس 01. ثم ستغيّر سطرًا في main.tf وتكتشف أن، بالنسبة للمزوّد local، تغيير محتوى ملف لا يعدّله : بل يستبدله، برمز يجب أن تعرف التعرّف عليه قبل أن تقول yes. وأخيرًا ستدمّر كل شيء، وتتحقق من أن السجل فارغ وأن العُدّة تعدّ صفرًا.
دائمًا المهندس المعماري. الانحراف (drift) هو عامل حرّك جدارًا دون أن يقول : لم يعد المبنى مطابقًا للسجل ؛ يلاحظ المهندس ذلك عندما يذهب ليرى في الموقع (Refreshing state...). التعديل في المكان (~) هو إعادة طلاء جدار : يبقى الجدار نفسه. الاستبدال (-/+) هو هدم الجدار وإعادة بناء واحد في المكان نفسه : له رقم جديد في السجل. التدمير (-) هو الهدم دون إعادة البناء. يقول الكشف دائمًا أيًّا من الثلاثة يتوقع ؛ وأنت تقرأه قبل التوقيع.
| الرمز في الخطة | الجملة في الخطة | ما يفعله Terraform | في هذه الورشة |
|---|---|---|---|
+ | will be created | ينشئ كائنًا جديدًا | الخطوة 3 : الملف المحذوف يدويًا |
~ | will be updated in-place | يغيّر خاصية، ويبقى الكائن | أبدًا لـ content في local_file |
-/+ | must be replaced | يدمّر الكائن، ثم ينشئ آخر | الخطوة 5 : content يتغيّر |
- | will be destroyed | يحذف الكائن | الخطوة 8 : destroy |
الطرفية نفسها كما في الورشة 1، في المجلد travail/atelier-1 من العُدّة lab-terraform. وVS Code لتعديل main.tf. أوامر terraform … متطابقة في كل مكان ؛ وأوامر حذف ملف أو قراءته أو سرده تُعطى في النسختين.
Windows (PowerShell)، من جذر العُدّة :
cd travail\atelier-1Linux وmacOS وWSL 2 وGit Bash :
cd travail/atelier-1ثم :
terraform state listlocal_file.bonjourما يطلبه الأمر : « ماذا تدير في هذا المجلد ؟ »
ما يجب النظر إليه : سطر واحد، local_file.bonjour. هذه الحالة التي تركتك فيها الورشة 1. إذا قرأت No state file was found! أو لا شيء على الإطلاق، فالمجلد ليس الصحيح أو المورد دُمّر : أعد الورشة 1 قبل المتابعة.
Windows (PowerShell) :
Remove-Item .\bonjour.txt
Get-ChildItemLinux وmacOS وWSL 2 وGit Bash :
rm bonjour.txt
lsما تطلبه الأوامر : « احذف bonjour.txt، ثم أرِني المجلد. »
ما يجب النظر إليه : لم يعد bonjour.txt موجودًا ؛ وmain.tf وterraform.tfstate ما زالا هناك. لقد فعلت للتو ما يفعله زميل في وحدة تحكم AWS عندما يحذف bucket « لم يكن يفيد بشيء » : تغيّر الواقع، لكن لا الشيفرة ولا السجل يعرفان ذلك بعد.
terraform planlocal_file.bonjour: Refreshing state... [id=fd9aee5556589b4d797e6d49f8ec894e29e57713]
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:
# local_file.bonjour will be created
+ resource "local_file" "bonjour" {
+ content = "Bonjour Terraform"
+ content_base64sha256 = (known after apply)
…
+ filename = "./bonjour.txt"
+ id = (known after apply)
}
Plan: 1 to add, 0 to change, 0 to destroy.ما يطلبه الأمر : « قارن الشيفرة والسجل والواقع، وقل لي ما ينقص. »
ما يجب النظر إليه : Refreshing state... [id=fd9aee55…] : ذهب Terraform ليرى الملف الذي يذكره سجله، ولم يجده. النتيجة : يحذفه من سجله ويقول الكشف will be created، Plan: 1 to add. الخطة نفسها كما في الورشة 1، الخطوة 5، مع أنك لم تمسّ الشيفرة. هذا هو الانحراف : تحرّك الواقع دون المرور بـ Terraform، وكشفه Terraform لحظة الخطة، لا قبلها.
Refreshing state... في plan (وفي apply) هو ما يعيد قراءة الواقع. ملف حُذف منذ ثلاثة أيام لا يُكتشف إلا في plan التالي.+ وليس -/+ ؟ لم يعد الكائن موجودًا على الإطلاق : لا شيء لتدميره، فقط للإنشاء. -/+ (الخطوة 5) لكائن ما زال موجودًا لكن يجب إعادة صنعه.plan التالي إعادتها كما تقول الشيفرة. تُظهر لك الخطة ذلك ؛ وعليك أن تقرّر ما إذا كانت الشيفرة أو وحدة التحكم هي التي كانت على حق.terraform applylocal_file.bonjour: Refreshing state... [id=fd9aee5556589b4d797e6d49f8ec894e29e57713]
…
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.bonjour: Creating...
local_file.bonjour: Creation complete after 0s [id=fd9aee5556589b4d797e6d49f8ec894e29e57713]
Apply complete! Resources: 1 added, 0 changed, 0 destroyed.ما يطلبه الأمر : « أعد حساب الكشف، انتظر yes مني، ثم نفّذه. »
ما يجب النظر إليه : عاد bonjour.txt، وid الخاص به هو نفسه كما قبل (fd9aee55…) : معرّف local_file هو بصمة محتواه، والمحتوى لم يتغيّر. تحقق بـ Get-Content .\bonjour.txt أو cat bonjour.txt : Bonjour Terraform. لم يكن سكربت ليعرف أنه يجب الإصلاح ؛ عرف Terraform ذلك لأن لديه سجلًا وشيفرة للمقارنة.
في VS Code، عدّل سطر content في main.tf للحصول على :
resource "local_file" "bonjour" {
filename = "${path.module}/bonjour.txt"
content = "Bonjour Terraform, deuxième version"
}احفظ، ثم :
terraform planlocal_file.bonjour: Refreshing state... [id=fd9aee5556589b4d797e6d49f8ec894e29e57713]
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.bonjour must be replaced
-/+ resource "local_file" "bonjour" {
~ content = "Bonjour Terraform" -> "Bonjour Terraform, deuxième version" # forces replacement
~ content_base64sha256 = "SvXkP5Iqo1rJKHgTVJnjanxfsNVGhb+r52mzUqZJYyg=" -> (known after apply)
~ content_base64sha512 = "r3+PevYNJRFsHMz4H4U1DK+lg89nhO9SLJZMAqqtzPKiIv3ilrmbx5sYh2JCW9o5EF0NXanYmuxMvI2QN4Z1Ag==" -> (known after apply)
~ content_md5 = "ff3a967c227a58691a3d34a931d3eeb5" -> (known after apply)
~ content_sha1 = "fd9aee5556589b4d797e6d49f8ec894e29e57713" -> (known after apply)
~ content_sha256 = "4af5e43f922aa35ac92878135499e36a7c5fb0d54685bfabe769b352a6496328" -> (known after apply)
~ content_sha512 = "af7f8f7af60d25116c1cccf81f85350cafa583cf6784ef522c964c02aaadccf2a222fde296b99bc79b188762425bda39105d0d5da9d89aec4cbc8d9037867502" -> (known after apply)
~ id = "fd9aee5556589b4d797e6d49f8ec894e29e57713" -> (known after apply)
# (3 unchanged attributes hidden)
}
Plan: 1 to add, 0 to change, 1 to destroy.ما يطلبه الأمر : الطلب نفسه كما في الخطوة 3. لكن هذه المرة الشيفرة هي التي تغيّرت، لا الواقع.
ما يجب النظر إليه، سطرًا سطرًا. هذه أهم خطة في الوحدة :
| السطر | ما يقوله |
|---|---|
-/+ destroy and then create replacement | المفتاح : الرمز المستخدم هو -/+، « تدمير ثم إنشاء بديل ». |
# local_file.bonjour must be replaced | ليس will be updated in-place : المورد يجب استبداله. |
-/+ resource "local_file" "bonjour" { | تحمل الكتلة بأكملها -/+. |
~ content = "Bonjour Terraform" -> "Bonjour Terraform, deuxième version" # forces replacement | يقول ~ إن القيمة تتغيّر، من القديمة (->) إلى الجديدة. ويقول التعليق # forces replacement إن هذه الخاصية هي التي تُلزم بالاستبدال. |
~ content_md5 = "ff3a967c…" -> (known after apply) | ستتغيّر البصمات ؛ لا يعرف Terraform الجديدة بعد. |
~ id = "fd9aee55…" -> (known after apply) | سيتغيّر المعرّف. سيكون كائنًا آخر. |
# (3 unchanged attributes hidden) | filename وdirectory_permission وfile_permission لا تتحرك ؛ يخفيها Terraform من أجل القراءة. |
Plan: 1 to add, 0 to change, 1 to destroy. | تدمير واحد وإنشاء واحد، صفر تعديل. |
هذا هو مخرجك المطلوب الأول : احتفظ بهذه المخرجات.
الفرق الجوهري بين
~و-/+. يقول~أمامcontentماذا يتغيّر. ويقول-/+أمامresourceكيف سيتصرف Terraform : الهدم، ثم إعادة البناء. بالنسبة لملف نصي، لن ترى الفرق. أما بالنسبة لقاعدة بيانات، فـ-/+يعني أن البيانات تختفي مع الكائن القديم. المزوّد هو من يقرّر، خاصيةً خاصية ؛ وقد قرّر المزوّدlocalأنcontentيفرض الاستبدال. وأنت تقرأ المؤشرات الثلاثة (must be replaced،# forces replacement،1 to destroy) قبل كتابةyes.
local بدلًا من التعديل ؟ لأنه لا يعرف « تصحيح » ملف موجود : يعرف كتابته أو محوه. وid الخاص بـ local_file هو أصلًا بصمة SHA-1 لمحتواه ؛ تغيير المحتوى يغيّر المعرّف، وكائن يتغيّر معرّفه هو، بالنسبة لـ Terraform، كائن آخر. على جهاز الدورة، يفرض file_permission الاستبدال أيضًا. تتصرف مزوّدات أخرى بشكل مختلف : تغيير وسم (tag) على مورد AWS هو ~، وتغيير اسمه غالبًا -/+.apply في الإنتاج، هذا ما سنقرأه.terraform apply -replace=local_file.bonjour يستبدل المورد حتى دون تغيير في الشيفرة. مفيد عندما يكون كائن معطوبًا. ستراه في المشروع 08.terraform applylocal_file.bonjour: Refreshing state... [id=fd9aee5556589b4d797e6d49f8ec894e29e57713]
…
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.bonjour: Destroying... [id=fd9aee5556589b4d797e6d49f8ec894e29e57713]
local_file.bonjour: Destruction complete after 0s
local_file.bonjour: Creating...
local_file.bonjour: Creation complete after 0s [id=bd2b5f8ccbb2cbc2b9bea872211549635a76b092]
Apply complete! Resources: 1 added, 0 changed, 1 destroyed.ما يطلبه الأمر : الطلب نفسه كما في الخطوة 4.
ما يجب النظر إليه : أربعة أسطر إجراء بدلًا من سطرَين، بترتيب الرمز -/+ : Destroying... ثم Destruction complete (القديم، fd9aee55…)، ثم Creating... ثم Creation complete (الجديد، bd2b5f8c…). والسطر الأخير : Apply complete! Resources: 1 added, 0 changed, 1 destroyed. ليس 1 changed : لم يُعدَّل شيء، دُمّر كائن وأُنشئ آخر.
Windows (PowerShell) :
Get-Content .\bonjour.txtLinux وmacOS وWSL 2 وGit Bash :
cat bonjour.txtBonjour Terraform, deuxième versionثم :
terraform state show local_file.bonjour# local_file.bonjour:
resource "local_file" "bonjour" {
content = "Bonjour Terraform, deuxième version"
content_base64sha256 = "hg9L75JxH+5SDk+ZOADZinGONkirydetS0TFjN3uZ3o="
content_base64sha512 = "EjT8mRVQU2JQ+Em/rnbRKYfe7E2UqIWw8yQMMtaatimH5XCKg4ZomW4PI5yO5jhujdSrU04vX17HE2kaqEVSkQ=="
content_md5 = "9a1a1355b48e28ad727200e450b851e1"
content_sha1 = "bd2b5f8ccbb2cbc2b9bea872211549635a76b092"
content_sha256 = "860f4bef92711fee520e4f993800d98a718e3648abc9d7ad4b44c58cddee677a"
content_sha512 = "1234fc991550536250f849bfae76d12987deec4d94a885b0f3240c32d69ab62987e5708a838668996e0f239c8ee6386e8dd4ab534e2f5f5ec713691aa8455291"
directory_permission = "0777"
file_permission = "0777"
filename = "./bonjour.txt"
id = "bd2b5f8ccbb2cbc2b9bea872211549635a76b092"
}ما تطلبه الأوامر : « أرِني الملف الحقيقي، ثم ما يقوله السجل عنه. »
ما يجب النظر إليه : يحتوي الملف على النسخة الثانية. في السجل، content هو القيمة الجديدة، وتغيّرت كل البصمات، وid هو bd2b5f8c…، الذي عرضه Creation complete في الخطوة 6. قارن مع state show من الورشة 1، الخطوة 9 : العنوان نفسه local_file.bonjour، لكن كائن آخر. الشيفرة والسجل والواقع متفقة مجددًا : terraform plan الآن سيقول No changes.
terraform destroylocal_file.bonjour: Refreshing state... [id=bd2b5f8ccbb2cbc2b9bea872211549635a76b092]
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.bonjour will be destroyed
- resource "local_file" "bonjour" {
- content = "Bonjour Terraform, deuxième version" -> null
- content_base64sha256 = "hg9L75JxH+5SDk+ZOADZinGONkirydetS0TFjN3uZ3o=" -> null
…
- filename = "./bonjour.txt" -> null
- id = "bd2b5f8ccbb2cbc2b9bea872211549635a76b092" -> 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.bonjour: Destroying... [id=bd2b5f8ccbb2cbc2b9bea872211549635a76b092]
local_file.bonjour: Destruction complete after 0s
Destroy complete! Resources: 1 destroyed.ما يطلبه الأمر : « دمّر كل ما تديره هنا ؛ أرِني الكشف وانتظر yes مني. »
ما يجب النظر إليه : الرمز الثالث، - وحده، وكل خاصية تنتقل إلى -> null (« لا شيء بعد الآن »). السؤال أخطر مما في apply : Do you really want to destroy all resources? وThere is no undo. اكتب yes. الجملة المنتظرة : Destroy complete! Resources: 1 destroyed. اختفى الملف من المجلد.
terraform state listثم، لترى بماذا يجيب Terraform عندما نطلب منه موردًا لم يعد يديره :
terraform state show local_file.bonjourNo instance found for the given address!
This command requires that the address references one specific instance.
To view the available instances, use "terraform state list". Please modify
the address to reference a specific instance.ما تطلبه الأوامر : « اسرد ما تديره »، ثم « أرِني local_file.bonjour ».
ما يجب النظر إليه : لا يجيب state list بـشيء : لا سطر، لا خطأ، سجل فارغ. هذا مختلف عن No state file was found! من الورشة 1 قبل apply : هنا الملف terraform.tfstate موجود، لكن قائمة موارده فارغة. ويجيب state show بـ No instance found for the given address! : العنوان صحيح، لكن لم يعد يقابله شيء، ويحيلك Terraform إلى state list. هذا هو مخرجك المطلوب الثاني : المخرجات الفارغة لـ terraform state list.
Windows (PowerShell) :
Get-ChildItem -ForceLinux وmacOS وWSL 2 وGit Bash :
ls -latotal 17
drwxr-xr-x 1 rehou 197609 0 Sep 15 14:57 .
drwxr-xr-x 1 rehou 197609 0 Sep 15 14:57 ..
drwxr-xr-x 1 rehou 197609 0 Sep 15 14:57 .terraform
-rw-r--r-- 1 rehou 197609 1228 Sep 15 14:57 .terraform.lock.hcl
-rw-r--r-- 1 rehou 197609 130 Sep 15 14:57 main.tf
-rw-r--r-- 1 rehou 197609 181 Sep 15 14:57 terraform.tfstate
-rw-r--r-- 1 rehou 197609 1653 Sep 15 14:57 terraform.tfstate.backup(سرد ls -la من جهاز الدورة ؛ يعرض Get-ChildItem -Force الأسماء الخمسة نفسها : .terraform، .terraform.lock.hcl، main.tf، terraform.tfstate، terraform.tfstate.backup.)
ما يطلبه الأمر : « أرِني المجلد كله، بما في ذلك الملفات المخفية. »
ما يجب النظر إليه : لم يعد bonjour.txt موجودًا. main.tf سليم : تدمير الموارد لا يمسّ الشيفرة أبدًا. terraform.tfstate ما زال موجودًا لكنه ضئيل (181 بايتًا)، وظهر terraform.tfstate.backup : نسخة السجل من قبل destroy، التي يحتفظ بها Terraform احتياطًا. يبقى أيضًا .terraform/ و.terraform.lock.hcl : إذا أعدت تشغيل apply، فلا حاجة لإعادة init.
افتح state لتراه فارغًا، دون تعديله (Get-Content .\terraform.tfstate أو cat terraform.tfstate) :
{
"version": 4,
"terraform_version": "1.12.2",
"serial": 6,
"lineage": "69fb219e-a88c-a97f-5aed-a33e7c34ff69",
"outputs": {},
"resources": [],
"check_results": null
}"resources": [] : لا شيء. يعدّ "serial" عمليات الكتابة في state (ست هنا : apply مرتَين في الورشة 1، ثم الإصلاح، والاستبدال والتدمير) ؛ و"lineage" هو معرّف هذا state، مختلف عندك.
اصعد إلى جذر العُدّة وشغّل العدّاد :
Windows (PowerShell) :
cd ..\..
.\labo.ps1 etatLinux وmacOS وWSL 2 وGit Bash :
cd ../..
./labo.sh etattravail atelier-1 : aucune ressource
Ressources encore gérées : 0 (0 attendu à la fin d'une séance).الإجابة المنتظرة : aucune ressource (لا موارد) وRessources encore gérées : 0 (الموارد التي ما زالت مُدارة : 0). هذه نهاية الجلسة النظيفة التي سيطلبها كل مشروع في الدورة، عندما تكلّف الموارد مالًا.
bonjour.txt يدويًا ورأيت plan يقترح will be created دون أن تتغيّر الشيفرة : انحراف، مكشوف عند Refreshing state....apply إنشاء الملف بـ نفس id.content وقرأت المؤشرات الثلاثة للاستبدال : must be replaced، # forces replacement، Plan: 1 to add, 0 to change, 1 to destroy.apply السطر Destroying... ثم Creating...، وResources: 1 added, 0 changed, 1 destroyed. ؛ وتغيّر id.destroy كلمة yes مع There is no undo. وأجاب Destroy complete! Resources: 1 destroyed.state list شيئًا ؛ ويُرجع state show القيمة No instance found for the given address! ؛ ويحتوي terraform.tfstate على "resources": [].etat القيمة Ressources encore gérées : 0.state list بـ No state file was found! → لست في travail/atelier-1، أو لم تُنجَز الورشة 1 حتى apply. تحقق من المجلد (يجب أن يعرض Get-ChildItem -Force أو ls -la الملف terraform.tfstate)، وإلا أعد الورشة 1.state list بشيء → دُمّر المورد أصلًا (destroy في نهاية الورشة 1). أعد تشغيل terraform apply، yes، ثم استأنف من الخطوة 2.No changes. → لم يُحذف الملف (خطأ مطبعي في Remove-Item أو rm، أو مجلد خاطئ). تحقق بـ Get-ChildItem أو ls، واحذفه، وأعد تشغيل plan.No changes. → لم يُحفظ main.tf بعد التعديل (VS Code : نقطة بيضاء في علامة التبويب). Ctrl+S ثم أعد التشغيل.Error: Unterminated template string → سقطت علامة الاقتباس الختامية للقيمة الجديدة content أثناء التحرير. أعدها.# forces replacement ليس content → عدّلت وسيطًا آخر في الوقت نفسه (مثلًا file_permission = "0644"). بالنسبة لـ local_file، يفرض هذا أيضًا الاستبدال (مُتحقَّق منه : ~ file_permission = "0777" -> "0644" # forces replacement). أعد الملف كما في الخطوة 5، يجب أن يتغيّر سطر content فقط.Apply cancelled. → كُتب شيء غير yes. أعد التشغيل، واكتب yes كاملة.destroy : No changes. No objects need to be destroyed. ثم Destroy complete! Resources: 0 destroyed. → لم يبقَ شيء أصلًا في state (Either you have not created any objects yet or the existing objects were already deleted outside of Terraform.). انتقل إلى الخطوة 9.destroy، تعتقد أن state لم يُنظَّف لأن terraform.tfstate ما زال موجودًا → هذا طبيعي. افتحه : "resources": []. يبقى الملف، فارغًا، مع .backup بجانبه.etat بـ Ressources encore gérées : 1 → أُلغي destroy أو نُفّذ في مجلد آخر. عُد إلى travail/atelier-1، terraform destroy، yes، وأعد تشغيل etat.