Terraform مقابل CloudFormation: الدليل النهائي
نشرت: 2022-03-11إذا كنت ، مثلي ، قد جابت الإنترنت لمساعدتك في الاختيار بين CloudFormation و Terraform كأداة البنية التحتية كرمز (IaC) التالية دون العثور على إجابة محددة ، فقد شاركت ألمك لفترة طويلة. الآن ، لدي خبرة كبيرة في كلتا الأداتين ويمكنني اتخاذ قرار مستنير بشأن أي منهما سأستخدمه.
TL ؛ DR
بالنسبة لمشروع IaC الخاص بك على AWS ، اختر CloudFormation ، للأسباب التالية:
- يميز CloudFormation بين الكود (أي القوالب) وتطبيقات الكود (أي الحزم). في Terraform ، لا يوجد مثل هذا التمييز. المزيد عن هذا في القسم التالي.
- لا يتعامل Terraform مع إدارة التبعية الأساسية بشكل جيد للغاية. المزيد عن ذلك في قسم لاحق.
التفريق بين الكود والتشكيلات
يتمثل أحد الاختلافات بين CloudFormation و Terraform في كيفية ارتباط الكود والتشكيلات ببعضها البعض داخل كل خدمة.
يحتوي CloudFormation على مفهوم المكدس ، وهو إنشاء مثيل للقالب. يمكن إنشاء مثيل إعلان لا نهائي من نفس النموذج بواسطة عميل معين في حساب معين أو عبر الحسابات أو بواسطة عملاء مختلفين.
لا يحتوي Terraform على مثل هذا المفهوم ويتطلب علاقة رأس برأس بين الكود وإنشاء مثيل له. سيكون مشابهًا لتكرار الكود المصدري لخادم الويب لكل خادم تريد تشغيله ، أو تكرار الكود في كل مرة تحتاج فيها إلى تشغيل تطبيق بدلاً من تشغيل الإصدار المترجم.
هذه النقطة تافهة تمامًا في حالة الإعداد البسيط ، ولكنها سرعان ما تصبح نقطة ألم رئيسية للعمليات المتوسطة إلى الكبيرة الحجم. في Terraform ، في كل مرة تحتاج فيها إلى تدوير مكدس جديد من كود موجود ، تحتاج إلى تكرار الكود. يعد نسخ / لصق ملفات البرامج النصية طريقة سهلة للغاية لتخريب نفسك وإفساد الموارد التي لم تكن تنوي لمسها.
لا يمتلك Terraform في الواقع مفهومًا للمكدسات مثل CloudFormation ، والذي يُظهر بوضوح أن Terraform قد تم بناؤه من الألف إلى الياء للحصول على تطابق واحد لواحد بين الكود والموارد التي يديرها. تم تصحيح هذا لاحقًا جزئيًا من خلال مفهوم البيئات (التي تمت إعادة تسميتها منذ ذلك الحين باسم "مساحات العمل") ، ولكن طريقة استخدامها تجعل من السهل جدًا نشرها في بيئة غير مرغوب فيها. هذا لأنه يتعين عليك تشغيل terraform workspace select
قبل النشر ، وسيؤدي نسيان هذه الخطوة إلى نشر مساحة العمل المحددة مسبقًا ، والتي قد تكون أو لا تكون المساحة التي تريدها.
من الناحية العملية ، من الصحيح أن هذه المشكلة يتم تخفيفها عن طريق استخدام وحدات Terraform ، ولكن حتى في أفضل الأحوال ، قد تحتاج إلى قدر كبير من التعليمات البرمجية المعيارية. في الواقع ، كانت هذه المشكلة حادة للغاية لدرجة أن الناس احتاجوا إلى إنشاء أداة مجمعة حول Terraform لمعالجة هذه المشكلة: Terragrunt.
إدارة الدولة والأذونات
هناك اختلاف مهم آخر بين CloudFormation و Terraform وهو كيفية إدارة كل منهما للحالة والأذونات.
يدير CloudFormation حالات المكدس نيابة عنك ولا يمنحك أي خيارات. لكن حالات مكدس CloudFormation كانت صلبة في تجربتي. أيضًا ، يتيح CloudFormation للمستخدمين الأقل امتيازًا إدارة الحزم دون الحصول على جميع الأذونات اللازمة التي تتطلبها الحزمة نفسها. هذا لأن CloudFormation يمكنه الحصول على الأذونات من دور خدمة مرتبط بالمكدس بدلاً من الأذونات من المستخدم الذي يقوم بتشغيل عملية المكدس.
يتطلب منك Terraform تزويده ببعض النهايات الخلفية لإدارة الحالات. الملف الافتراضي هو ملف محلي ، وهو أمر غير مُرضٍ تمامًا ، نظرًا لما يلي:
- ترتبط متانة ملف حالتك تمامًا بمتانة الجهاز المخزن عليه.
- هذا يجعل العمل الجماعي مستحيلًا.
لذلك أنت بحاجة إلى حالة قوية ومشتركة ، والتي يتم تحقيقها في AWS عادةً باستخدام دلو S3 لتخزين ملف الحالة ، مصحوبًا بجدول DynamoDB للتعامل مع التزامن.
هذا يعني أنك بحاجة إلى إنشاء حاوية S3 وجدول DynamoDB يدويًا لكل مكدس تريد إنشاء مثيل له ، وكذلك إدارة الأذونات يدويًا لهذين الكائنين لتقييد المستخدمين الأقل امتيازًا من الوصول إلى البيانات التي لا ينبغي لهم الوصول إليها. إذا كان لديك عدد قليل من الحزم ، فلن يمثل ذلك مشكلة كبيرة ، ولكن إذا كان لديك 20 مكدسًا لإدارتها ، فسيصبح ذلك مرهقًا للغاية.
بالمناسبة ، عند استخدام مساحات عمل Terraform ، لا يمكن أن يكون لديك جدول DynamoDB واحد لكل مساحة عمل. هذا يعني أنك إذا كنت تريد مستخدم IAM مع الحد الأدنى من الأذونات لأداء عمليات النشر ، فسيكون هذا المستخدم قادرًا على العبث بأقفال جميع مساحات العمل لأن أذونات DynamoDB ليست محددة بدقة على مستوى العنصر.
إدارة التبعية
في هذه النقطة ، يمكن أن يكون كل من CloudFormation و Terraform صعبًا بعض الشيء. إذا قمت بتغيير المعرّف المنطقي (أي الاسم) لأحد الموارد ، فسيعتبر كلاهما أنه يجب تدمير المورد القديم وإنشاء واحد جديد. لذلك من الجيد عمومًا تغيير المعرّف المنطقي للموارد في أي من الأداة ، خاصةً للمكدسات المتداخلة في CloudFormation.
كما هو مذكور في القسم الأول ، لا يتعامل Terraform مع التبعيات الأساسية. لسوء الحظ ، لا يولي مطورو Terraform اهتمامًا كبيرًا لهذه المشكلة التي طال أمدها ، على الرغم من النقص الواضح في الحلول البديلة.
نظرًا لأن إدارة التبعية المناسبة أمر بالغ الأهمية لأداة IaC ، فإن مثل هذه المشكلات في Terraform تستدعي مدى ملاءمتها للتساؤل بمجرد تضمين العمليات التجارية الحيوية ، مثل النشر في بيئة إنتاج. تمنح CloudFormation إحساسًا أكثر احترافًا ، ودائمًا ما تهتم AWS بشدة بالتأكد من أنها تقدم أدوات على مستوى الإنتاج لعملائها. في كل السنوات التي كنت أستخدم فيها CloudFormation ، لم أواجه أبدًا مشكلة في إدارة التبعية.
يسمح CloudFormation للمكدس بتصدير بعض متغيرات الإخراج الخاصة به ، والتي يمكن بعد ذلك إعادة استخدامها بواسطة مكدسات أخرى. لكي نكون صادقين ، هذه الوظيفة محدودة ، حيث لن تتمكن من إنشاء أكثر من مكدس واحد لكل منطقة. هذا لأنه لا يمكنك تصدير متغيرين بنفس الاسم ، ولا تحتوي المتغيرات المصدرة على مساحات أسماء.
لا يقدم Terraform مثل هذه التسهيلات ، لذلك يتبقى لك خيارات أقل استحسانًا. يسمح لك Terraform باستيراد حالة مكدس آخر ، لكن هذا يمنحك الوصول إلى جميع المعلومات الموجودة في هذا المكدس ، بما في ذلك العديد من الأسرار المخزنة في الحالة. بدلاً من ذلك ، يمكن للمكدس تصدير بعض المتغيرات في شكل ملف JSON مخزن في حاوية S3 ، ولكن مرة أخرى ، هذا الخيار أكثر تعقيدًا: عليك أن تقرر أي حاوية S3 ستستخدمها ومنحها الأذونات المناسبة ، وكتابة كل كود السباكة بنفسك من جانب الكاتب والقارئ.
تتمثل إحدى ميزات Terraform في أنه يحتوي على مصادر بيانات. وبالتالي يمكن لـ Terraform الاستعلام عن الموارد التي لا يديرها Terraform. ومع ذلك ، من الناحية العملية ، فإن هذا ليس له صلة كبيرة عندما تريد كتابة نموذج عام لأنك لن تفترض أي شيء عن الحساب المستهدف. المكافئ في CloudFormation هو إضافة المزيد من معلمات القالب ، والتي تتضمن بالتالي التكرار واحتمال حدوث أخطاء ؛ ومع ذلك ، في تجربتي ، لم يكن هذا مشكلة.
بالعودة إلى مسألة إدارة التبعية في Terraform ، هناك مثال آخر هو ظهور خطأ عند محاولة تحديث إعدادات موازن التحميل والحصول على ما يلي:
Error: Error deleting Target Group: ResourceInUse: Target group 'arn:aws:elasticloadbalancing:us-east-1:723207552760:targetgroup/strategy-api-default-us-east-1/14a4277881e84797' is currently in use by a listener or a rule status code: 400, request id: 833d8475-f702-4e01-aa3a-d6fa0a141905
قد يكون السلوك المتوقع هو أن Terraform يكتشف أن المجموعة المستهدفة هي تبعية لبعض الموارد الأخرى التي لم يتم حذفها ، وبالتالي ، لا يجب أن تحاول حذفها - ولكن لا ينبغي أن تسبب أي خطأ.
عمليات
على الرغم من أن Terraform هي أداة سطر أوامر ، إلا أنه من الواضح جدًا أنها تتوقع من الإنسان تشغيلها ، لأنها تفاعلية للغاية. من الممكن تشغيله في وضع الدُفعات (أي من برنامج نصي) ، لكن هذا يتطلب بعض وسيطات سطر الأوامر الإضافية. حقيقة أن Terraform قد تم تطويره ليتم تشغيله بواسطة البشر افتراضيًا أمر محير للغاية ، نظرًا لأن الغرض من أداة IaC هو الأتمتة.
Terraform من الصعب تصحيحه. غالبًا ما تكون رسائل الخطأ أساسية جدًا ولا تسمح لك بفهم الخطأ الذي يحدث ، وفي هذه الحالة سيتعين عليك تشغيل Terraform باستخدام TF_LOG=debug
، والذي ينتج قدرًا هائلاً من المخرجات لتتصفحها. ومما يزيد الأمر تعقيدًا أن Terraform يقوم أحيانًا بإجراء مكالمات API إلى AWS والتي تفشل ، ولكن الفشل لا يمثل مشكلة مع Terraform. في المقابل ، يوفر CloudFormation رسائل خطأ واضحة بشكل معقول مع تفاصيل كافية للسماح لك بفهم مكان المشكلة.
مثال على رسالة خطأ Terraform:

Error: error reading S3 bucket Public Access Block: NoSuchBucket: The specified bucket does not exist status code: 404, request id: 19AAE641F0B4AC7F, host id: rZkgloKqxP2/a2F6BYrrkcJthba/FQM/DaZnj8EQq/5FactUctdREq8L3Xb6DgJmyKcpImipv4s=
تُظهر رسالة الخطأ أعلاه رسالة خطأ واضحة لا تعكس في الواقع المشكلة الأساسية (والتي كانت في هذه الحالة مشكلة أذونات).
تُظهر رسالة الخطأ هذه أيضًا كيف يمكن أن يرسم Terraform نفسه أحيانًا في الزاوية. على سبيل المثال ، إذا قمت بإنشاء حاوية S3 aws_s3_bucket_public_access_block
في تلك المجموعة ، وإذا أجريت لسبب ما بعض التغييرات في كود Terraform الذي يدمر هذه المجموعة - على سبيل المثال ، في "التغيير يعني حذف وإنشاء" مسكتك الموضحة أعلاه - سيعلق Terraform أثناء محاولة تحميل aws_s3_bucket_public_access_block
ولكنه يفشل باستمرار مع الخطأ أعلاه. سيكون السلوك الصحيح من Terraform هو استبدال أو حذف aws_s3_bucket_public_access_block
حسب الاقتضاء.
أخيرًا ، لا يمكنك استخدام البرامج النصية المساعدة CloudFormation مع Terraform. قد يكون هذا مصدر إزعاج ، خاصة إذا كنت تأمل في استخدام إشارة cfn ، والتي تخبر CloudFormation أن مثيل EC2 قد انتهى من تهيئة نفسه وأنه جاهز لخدمة الطلبات.
بناء الجملة والمجتمع والتراجع
من الناحية التركيبية ، يتمتع Terraform بميزة جيدة مقارنةً بـ CloudFormation - فهو يدعم الحلقات. لكن في تجربتي الخاصة ، يمكن أن تكون هذه الميزة خطيرة بعض الشيء. عادة ، يمكن استخدام حلقة لإنشاء عدد من الموارد المتطابقة ؛ ومع ذلك ، عندما تريد تحديث المكدس بعدد مختلف ، فقد تكون هناك فرصة لأنك قد تحتاج إلى ربط الموارد القديمة والجديدة (على سبيل المثال ، استخدام zipmap()
لدمج القيم من صفيفتين والتي أصبحت الآن بأحجام مختلفة لأن إحدى المصفوفات لها حجم الحلقة القديمة والأخرى بحجم الحلقة الجديدة). صحيح أن مثل هذه المشكلة يمكن أن تحدث بدون حلقات ، لكن بدون حلقات ، ستكون المشكلة أكثر وضوحًا للشخص الذي يكتب السيناريو. استخدام الحلقات في مثل هذه الحالة يحجب المشكلة.
ما إذا كان بناء جملة Terraform أو صيغة CloudFormation أفضل هو في الغالب مسألة تفضيلات. دعم CloudFormation في البداية JSON فقط ، ولكن من الصعب جدًا قراءة قوالب JSON. لحسن الحظ ، يدعم CloudFormation أيضًا YAML ، والذي يسهل قراءته ويسمح بالتعليقات. تميل بنية CloudFormation إلى أن تكون مطولة تمامًا ، على الرغم من ذلك.
يستخدم بناء جملة Terraform HCL ، وهو نوع من مشتق JSON وهو مميز تمامًا. يوفر Terraform وظائف أكثر من CloudFormation ، وعادة ما يكون من الأسهل فهمها. لذلك يمكن القول أن Terraform لديه ميزة طفيفة في هذه النقطة.
ميزة أخرى لـ Terraform هي مجموعتها المتوفرة بسهولة من الوحدات النمطية التي يديرها المجتمع ، وهذا يبسط قوالب الكتابة. قد تكون إحدى المشكلات أن هذه الوحدات النمطية قد لا تكون آمنة بما يكفي للامتثال لمتطلبات المؤسسة. لذلك بالنسبة للمؤسسات التي تتطلب مستوى عالٍ من الأمان ، قد تكون مراجعة هذه الوحدات (بالإضافة إلى الإصدارات الأخرى فور ظهورها) ضرورة.
بشكل عام ، تعد وحدات Terraform النمطية أكثر مرونة من الحزم المتداخلة CloudFormation. تميل المكدس المتداخلة CloudFormation إلى إخفاء كل شيء تحتها. من المكدس المتداخل ، ستُظهر عملية التحديث أنه سيتم تحديث المكدس المتداخل ولكنه لا يُظهر بالتفصيل ما الذي سيحدث داخل المكدس المتداخل.
النقطة الأخيرة ، التي قد تكون مثيرة للجدل في الواقع ، هي أن CloudFormation تحاول التراجع عن عمليات النشر الفاشلة. هذه ميزة مثيرة للاهتمام تمامًا ولكنها للأسف قد تكون طويلة جدًا (على سبيل المثال ، قد يستغرق الأمر ما يصل إلى ثلاث ساعات حتى تقرر CloudFormation أن النشر إلى Elastic Container Service قد فشل). في المقابل ، في حالة الفشل ، يتوقف Terraform أينما كان. سواء كانت ميزة التراجع شيئًا جيدًا أم لا ، فهي قابلة للنقاش ، لكني أصبحت أقدر حقيقة أن المكدس يتم الاحتفاظ به في حالة عمل قدر الإمكان عندما يكون الانتظار الطويل بمثابة مقايضة مقبولة.
دفاعًا عن Terraform مقابل CloudFormation
Terraform له مزايا على CloudFormation. الأهم ، في رأيي ، هو أنه عند تطبيق التحديث ، يُظهر لك Terraform جميع التغييرات التي توشك على إجرائها ، بما في ذلك البحث في جميع الوحدات التي تستخدمها. على النقيض من ذلك ، فإن CloudFormation ، عند استخدام مكدسات متداخلة ، يوضح لك فقط أن الحزمة المتداخلة تحتاج إلى تحديث ، ولكنها لا توفر طريقة للتعمق في التفاصيل. قد يكون هذا محبطًا ، لأن هذا النوع من المعلومات مهم جدًا معرفته قبل الضغط على زر "انتقال".
كلا من ملحقات دعم CloudFormation و Terraform. في CloudFormation ، من الممكن إدارة ما يسمى "بالموارد المخصصة" باستخدام وظيفة AWS Lambda من إنشائك كنهاية خلفية. بالنسبة إلى Terraform ، تكون الإضافات أسهل بكثير في الكتابة وتشكل جزءًا من الكود. لذلك هناك ميزة لـ Terraform في هذه الحالة.
يمكن لـ Terraform التعامل مع العديد من بائعي السحابة. يؤدي ذلك إلى وضع Terraform في وضع يسمح له بالقدرة على توحيد عملية نشر معينة بين العديد من الأنظمة الأساسية السحابية. على سبيل المثال ، لنفترض أن لديك عبء عمل واحد موزّع بين AWS و Google Cloud Platform (GCP). عادةً ما يتم نشر جزء AWS من عبء العمل باستخدام CloudFormation ، وجزء GCP باستخدام Cloud Deployment Manager في GCP. باستخدام Terraform ، يمكنك بدلاً من ذلك استخدام برنامج نصي واحد لنشر وإدارة كلتا الحزمتين في الأنظمة الأساسية السحابية الخاصة بهما. بهذه الطريقة ، ما عليك سوى نشر مكدس واحد بدلاً من اثنين.
غير الحجج لـ Terraform مقابل CloudFormation
هناك عدد غير قليل من الحجج التي لا تزال تدور حول الإنترنت. أكبر ما تم طرحه هو أنه نظرًا لأن Terraform متعدد السحابة ، يمكنك استخدام أداة واحدة لنشر جميع مشاريعك ، بغض النظر عن النظام الأساسي السحابي الذي يتم تنفيذه. من الناحية الفنية ، هذا صحيح ، لكنه قد لا يمثل ميزة كبيرة ، خاصة عند إدارة مشاريع سحابية فردية نموذجية. الحقيقة هي أن هناك تطابقًا واحدًا تقريبًا بين الموارد المعلنة في (على سبيل المثال) CloudFormation ونفس الموارد المعلنة في نص Terraform. نظرًا لأنه يتعين عليك معرفة تفاصيل الموارد الخاصة بالسحابة في كلتا الحالتين ، فإن الاختلاف ينحصر في بناء الجملة ، والذي لا يمثل أكبر مشكلة في إدارة عمليات النشر.
يجادل البعض أنه باستخدام Terraform ، يمكن للمرء تجنب حبس البائع. لا تحمل هذه الحجة بمعنى أنه باستخدام Terraform ، فأنت مقيد من قِبل HashiCorp (منشئ Terraform) ، تمامًا بنفس الطريقة التي تستخدم بها CloudFormation ، فأنت مقفل بواسطة AWS ، وهكذا دواليك بالنسبة إلى السحابة الأخرى المنصات.
حقيقة أن وحدات Terraform أسهل في الاستخدام هي أقل أهمية بالنسبة لي. بادئ ذي بدء ، أعتقد أن AWS تريد عمدًا تجنب استضافة مستودع واحد لقوالب CloudFormation القائمة على المجتمع بسبب المسؤولية المتصورة عن الثغرات الأمنية التي يصنعها المستخدمون وخروقات برامج الامتثال المختلفة.
على المستوى الشخصي ، أفهم تمامًا فوائد استخدام المكتبات في حالة تطوير البرامج ، حيث يمكن أن تصل هذه المكتبات بسهولة إلى عشرات الآلاف من أسطر التعليمات البرمجية. ومع ذلك ، في حالة IaC ، يكون حجم الكود عادةً أقل من ذلك بكثير ، وعادة ما تكون هذه الوحدات عدة عشرات من الأسطر. إن استخدام النسخ / اللصق ليس في الواقع فكرة سيئة بمعنى أنه يتجنب مشاكل الحفاظ على التوافق وتفويض أمنك لأشخاص مجهولين.
يعد استخدام النسخ / اللصق أمرًا مستاءً من قبل العديد من المطورين ومهندسي DevOps ، وهناك أسباب وجيهة وراء ذلك. ومع ذلك ، فإن وجهة نظري هي أن استخدام النسخ / اللصق لمقتطفات من التعليمات البرمجية يتيح لك تخصيصها بسهولة وفقًا لاحتياجاتك ، وليست هناك حاجة لإنشاء مكتبة منها وقضاء الكثير من الوقت في جعلها عامة. عادةً ما يكون الألم المصاحب للاحتفاظ بهذه المقتطفات من التعليمات البرمجية منخفضًا جدًا ، ما لم يتم تكرار التعليمات البرمجية الخاصة بك ، على سبيل المثال ، في عشرات القوالب أو أكثر. في مثل هذه الحالة ، يكون تخصيص الكود واستخدامه كمكدسات متداخلة أمرًا منطقيًا ، وربما تكون فوائد عدم تكرار نفسك أكبر من الانزعاج من عدم القدرة على رؤية ما سيتم تحديثه داخل المكدس المتداخل عند إجراء تحديث عملية.
CloudFormation مقابل استنتاج Terraform
مع CloudFormation ، تريد AWS تزويد عملائها بأداة صلبة ستعمل على النحو المنشود في جميع الأوقات. يعمل فريق Terraform أيضًا بالطبع - ولكن يبدو أن جانبًا مهمًا من أدواتهم ، وهو إدارة التبعية ، للأسف ليس أولوية.
قد يكون لـ Terraform مكان في مشروعك ، خاصةً إذا كان لديك بنية متعددة السحابة ، وفي هذه الحالة تكون البرامج النصية لـ Terraform إحدى الطرق لتوحيد إدارة الموارد عبر مختلف بائعي السحابة الذين تستخدمهم. ولكن لا يزال بإمكانك تجنب سلبيات Terraform في هذه الحالة من خلال استخدام Terraform فقط لإدارة الحزم التي تم تنفيذها بالفعل باستخدام أدوات IaC الخاصة بالسحابة الخاصة بها.
الشعور العام بـ Terraform مقابل CloudFormation هو أن CloudFormation ، على الرغم من عدم الكمال ، هو أكثر احترافًا وموثوقية ، وأنا أوصي به بالتأكيد لأي مشروع ليس متعدد السحابة على وجه التحديد.