لقد تعلمت هذه الدروس الستة من العمل مع Cloudformation لبقية حياتي.

لقد بدأت العمل مع تشكيل السحابة منذ 4 سنوات. منذ ذلك الحين قمت بتحطيم الكثير من البنى التحتية، حتى تلك التي كانت في مرحلة الإنتاج بالفعل. ولكن في كل مرة أخطأت فيها شيئاً، تعلمت شيئاً جديداً. ومن خلال هذه التجربة، سأشارككم بعضًا من أهم الدروس التي تعلمتها.

لقد تعلمت هذه الدروس الستة من العمل مع Cloudformation لبقية حياتي.

الدرس 1: اختبار التغييرات قبل نشرها

لقد تعلمت هذا الدرس بعد وقت قصير من بدء العمل معه تشكيل السحابة. لا أتذكر بالضبط ما الذي كسرته حينها، لكني أتذكر بالتأكيد أنني استخدمت الأمر تحديث aws cloudformation. يقوم هذا الأمر ببساطة بطرح القالب دون أي التحقق من صحة التغييرات التي سيتم نشرها. لا أعتقد أن هناك حاجة إلى أي تفسير لسبب وجوب اختبار كافة التغييرات قبل نشرها.

وبعد هذا الفشل، تغيرت على الفور خط أنابيب النشر، مع استبدال أمر التحديث بالأمر إنشاء مجموعة التغيير

# OPERATION is either "UPDATE" or "CREATE"
changeset_id=$(aws cloudformation create-change-set 
    --change-set-name "$CHANGE_SET_NAME" 
    --stack-name "$STACK_NAME" 
    --template-body "$TPL_PATH" 
    --change-set-type "$OPERATION" 
    --parameters "$PARAMETERS" 
    --output text 
    --query Id)

aws cloudformation wait 
    change-set-create-complete --change-set-name "$changeset_id"

بمجرد إنشاء مجموعة التغييرات، لن يكون لها أي تأثير على المكدس الموجود. على عكس أمر التحديث، لا يؤدي أسلوب Changeset إلى بدء النشر الفعلي. وبدلاً من ذلك، يقوم بإنشاء قائمة بالتغييرات التي يمكنك مراجعتها قبل النشر. يمكنك عرض التغييرات في واجهة وحدة تحكم aws. ولكن إذا كنت تفضل أتمتة كل ما تستطيع، فتحقق منها في سطر الأوامر:

# this command is presented only for demonstrational purposes.
# the real command should take pagination into account
aws cloudformation describe-change-set 
    --change-set-name "$changeset_id" 
    --query 'Changes[*].ResourceChange.{Action:Action,Resource:ResourceType,ResourceId:LogicalResourceId,ReplacementNeeded:Replacement}' 
    --output table

يجب أن ينتج هذا الأمر إخراجًا مشابهًا لما يلي:

--------------------------------------------------------------------
|                         DescribeChangeSet                        |
+---------+--------------------+----------------------+------------+
| Action  | ReplacementNeeded  |      Resource        | ResourceId |
+---------+--------------------+----------------------+------------+
|  Modify | True               |  AWS::ECS::Cluster   |  MyCluster |
|  Replace| True               |  AWS::RDS::DBInstance|  MyDB      |
|  Add    | None               |  AWS::SNS::Topic     |  MyTopic   |
+---------+--------------------+----------------------+------------+

انتبه بشكل خاص إلى التغييرات التي يكون فيها الإجراء استبدل, حذف او اين مطلوب استبدال - صحيح. هذه هي أخطر التغييرات وعادة ما تؤدي إلى فقدان المعلومات.

بمجرد مراجعة التغييرات، يمكن نشرها

aws cloudformation execute-change-set --change-set-name "$changeset_id"

operation_lowercase=$(echo "$OPERATION" | tr '[:upper:]' '[:lower:]')
aws cloudformation wait "stack-${operation_lowercase}-complete" 
    --stack-name "$STACK_NAME"

الدرس 2: استخدام سياسة المكدس لمنع استبدال الموارد ذات الحالة أو إزالتها

في بعض الأحيان لا يكون مجرد عرض التغييرات كافيًا. نحن جميعا بشر وجميعنا نخطئ. بعد وقت قصير من بدء استخدام مجموعات التغييرات، أجرى زميلي في الفريق عملية نشر أدت دون قصد إلى تحديث قاعدة البيانات. لم يحدث شيء سيئ لأنها كانت بيئة اختبار.

على الرغم من أن البرامج النصية لدينا عرضت قائمة بالتغييرات وطلبت التأكيد، فقد تم تخطي تغيير الاستبدال لأن قائمة التغييرات كانت كبيرة جدًا لدرجة أنها لم تتناسب مع الشاشة. وبما أن هذا كان تحديثًا عاديًا في بيئة اختبار، لم يتم إيلاء الكثير من الاهتمام للتغييرات.

هناك موارد لا تريد أبدًا استبدالها أو إزالتها. هذه خدمات كاملة الحالة، مثل مثيل قاعدة بيانات RDS أو مجموعة Elasticsearch، وما إلى ذلك. سيكون من الرائع أن ترفض aws النشر تلقائيًا إذا كانت العملية التي يتم تنفيذها تتطلب حذف مثل هذا المورد. لحسن الحظ، لدى Cloudformation طريقة مدمجة للقيام بذلك. وهذا ما يسمى سياسة المكدس، ويمكنك قراءة المزيد عنها في توثيق:

STACK_NAME=$1
RESOURCE_ID=$2

POLICY_JSON=$(cat <<EOF
{
    "Statement" : [{
        "Effect" : "Deny",
        "Action" : [
            "Update:Replace",
            "Update:Delete"
        ],
        "Principal": "*",
        "Resource" : "LogicalResourceId/$RESOURCE_ID"
    }]
}
EOF
)

aws cloudformation set-stack-policy --stack-name "$STACK_NAME" 
    --stack-policy-body "$POLICY_JSON"

الدرس 3: استخدم UsePreviousValue عند تحديث مكدس بمعلمات سرية

عندما تقوم بإنشاء كيان RDS mysql، تطلب منك AWS تقديم MasterUsername وMasterUserPassword. نظرًا لأنه من الأفضل عدم الاحتفاظ بالأسرار في الكود المصدري وأردت أتمتة كل شيء على الإطلاق، فقد قمت بتطبيق "آلية ذكية" حيث سيتم الحصول على بيانات الاعتماد من s3 قبل النشر، وإذا لم يتم العثور على بيانات الاعتماد، فسيتم إنشاء بيانات اعتماد جديدة و مخزنة في s3 .

سيتم بعد ذلك تمرير بيانات الاعتماد هذه كمعلمات إلى الأمر cloudformation create-change-set. أثناء تجربة البرنامج النصي، حدث أن تم فقدان الاتصال بـ s3، وتعاملت "الآلية الذكية" الخاصة بي مع الأمر كإشارة لإنشاء بيانات اعتماد جديدة.

إذا بدأت باستخدام هذا البرنامج النصي في الإنتاج وحدثت مشكلة الاتصال مرة أخرى، فسيتم تحديث المكدس ببيانات اعتماد جديدة. في هذه الحالة بالذات، لن يحدث شيء سيء. ومع ذلك، فقد تخليت عن هذا النهج وبدأت في استخدام أسلوب آخر، مع توفير بيانات الاعتماد مرة واحدة فقط - عند إنشاء المكدس. وفي وقت لاحق، عندما يحتاج المكدس إلى التحديث، بدلاً من تحديد القيمة السرية للمعلمة، سأستخدمها ببساطة UsePreviousValue=true:

aws cloudformation create-change-set 
    --change-set-name "$CHANGE_SET_NAME" 
    --stack-name "$STACK_NAME" 
    --template-body "$TPL_PATH" 
    --change-set-type "UPDATE" 
    --parameters "ParameterKey=MasterUserPassword,UsePreviousValue=true"

الدرس 4: استخدام تكوين التراجع

استخدم فريق آخر عملت معه هذه الوظيفة تشكيل السحابة، مُسَمًّى تكوين التراجع. لم أصادفها من قبل وأدركت بسرعة أنها ستجعل نشر مجموعاتي أكثر روعة. أستخدمه الآن في كل مرة أقوم فيها بنشر الكود الخاص بي إلى lambda أو ECS باستخدام cloudformation.

كيف يعمل: أنت تحدد إنذار CloudWatch في المعلمة --التراجع عن التكوينعند إنشاء مجموعة التغييرات. لاحقًا، عند تنفيذ مجموعة من التغييرات، يقوم aws بمراقبة التنبيه لمدة دقيقة واحدة على الأقل. يقوم بتراجع النشر إذا تغير التنبيه إلى ALARM خلال هذا الوقت.

فيما يلي مثال لمقتطف من القالب تشكيل السحابةالذي أخلق فيه إنذار Cloudwatch، الذي يتتبع مقياس مستخدم السحابة كعدد الأخطاء في سجلات السحابة (يتم إنشاء المقياس عبر مرشح متري):

Resources:
  # this metric tracks number of errors in the cloudwatch logs. In this
  # particular case it's assumed logs are in json format and the error logs are
  # identified by level "error". See FilterPattern
  ErrorMetricFilter:
    Type: AWS::Logs::MetricFilter
    Properties:
      LogGroupName: !Ref LogGroup
      FilterPattern: !Sub '{$.level = "error"}'
      MetricTransformations:
      - MetricNamespace: !Sub "${AWS::StackName}-log-errors"
        MetricName: Errors
        MetricValue: 1
        DefaultValue: 0

  ErrorAlarm:
    Type: AWS::CloudWatch::Alarm
    Properties:
      AlarmName: !Sub "${AWS::StackName}-errors"
      Namespace: !Sub "${AWS::StackName}-log-errors"
      MetricName: Errors
      Statistic: Maximum
      ComparisonOperator: GreaterThanThreshold
      Period: 1 # 1 minute
      EvaluationPeriods: 1
      Threshold: 0
      TreatMissingData: notBreaching
      ActionsEnabled: yes

الآن إنذار يمكن استخدامها كما العودة المشغل عند تنفيذ صندوق الأدوات:

ALARM_ARN=$1

ROLLBACK_TRIGGER=$(cat <<EOF
{
  "RollbackTriggers": [
    {
      "Arn": "$ALARM_ARN",
      "Type": "AWS::CloudWatch::Alarm"
    }
  ],
  "MonitoringTimeInMinutes": 1
}
EOF
)

aws cloudformation create-change-set 
    --change-set-name "$CHANGE_SET_NAME" 
    --stack-name "$STACK_NAME" 
    --template-body "$TPL_PATH" 
    --change-set-type "UPDATE" 
    --rollback-configuration "$ROLLBACK_TRIGGER"

الدرس 5: تأكد من نشر أحدث إصدار من القالب

من السهل نشر إصدار أقل من أحدث إصدار من قالب التكوين السحابي، ولكن القيام بذلك سيؤدي إلى الكثير من الضرر. لقد حدث لنا هذا مرة واحدة: لم يقم أحد المطورين بدفع أحدث التغييرات من Git وقام دون قصد بنشر إصدار سابق من المكدس. أدى هذا إلى توقف التطبيق الذي يستخدم هذه المكدس.

شيء بسيط مثل إضافة فحص لمعرفة ما إذا كان الفرع محدثًا قبل الالتزام به سيكون أمرًا جيدًا (بافتراض أن git هي أداة التحكم في الإصدار الخاصة بك):

git fetch
HEADHASH=$(git rev-parse HEAD)
UPSTREAMHASH=$(git rev-parse master@{upstream})

if [[ "$HEADHASH" != "$UPSTREAMHASH" ]] ; then
   echo "Branch is not up to date with origin. Aborting"
   exit 1
fi

الدرس السادس: لا تعيد اختراع العجلة

قد يبدو الأمر وكأنه نشر مع تشكيل السحابة - من السهل. كل ما تحتاجه هو مجموعة من نصوص bash التي تنفذ أوامر aws cli.

منذ 4 سنوات، بدأت باستخدام نصوص برمجية بسيطة تسمى الأمر aws cloudformation create-stack. وسرعان ما لم يعد السيناريو بسيطًا. كل درس تم تعلمه جعل النص أكثر تعقيدًا. لم يكن الأمر صعبًا فحسب، بل كان مليئًا بالأخطاء أيضًا.

أعمل حاليًا في قسم صغير لتكنولوجيا المعلومات. لقد أظهرت التجربة أن كل فريق لديه طريقته الخاصة في نشر مكدسات التكوين السحابي. وهذا سيء. سيكون من الأفضل أن يتبع الجميع نفس النهج. لحسن الحظ، هناك العديد من الأدوات المتاحة لمساعدتك في نشر وتكوين مجموعات تشكيل السحابة.

ستساعدك هذه الدروس على تجنب الأخطاء.

المصدر: www.habr.com

إضافة تعليق