私はこれらの6つの教訓を、生涯にわたってクラウドフォーメーションで作業することから学びました。

4年前にcloudformation使い始めました。 それ以来、私は多くのインフラストラクチャを破壊しました。すでに運用されていたインフラストラクチャもです。 しかし、何かを台無しにするたびに、新しいことを学びました。 この経験のおかげで、私が学んだ最も重要な教訓のいくつかを共有します。



画像



レッスン1:展開前に変更を検証する



cloudformation使い始めてすぐに、このレッスンを学びました 。 その時点で何を壊したのかは覚えていませんが、 aws cloudformation updateコマンドを使用したことを正確に覚えています このコマンドは、展開される変更を検証せずにテンプレートを展開するだけです。 説明が必要だとは思わないので、展開する前にすべての変更を確認する必要があります。



この失敗の後、すぐに展開パイプラインを変更し、updateコマンドをcreate-change-setコマンドに置き換えました



# 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"
      
      





変更セットが作成されると、既存のスタックには影響しません。 更新コマンドとは異なり、変更セットのアプローチは実際にはデプロイされません。 代わりに、展開前に確認できる変更のリストを作成します。 awsコンソールインターフェースで変更を表示できます。 ただし、可能なすべてを自動化する場合は、CLIで確認してください。



 # 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 | +---------+--------------------+----------------------+------------+
      
      





ActionがReplaceDelete、またはReplacementNeededがTrueである変更に特に注意してください。 これらは最も危険な変更であり、通常は情報の損失につながります。



変更が表示されたら、展開できます



 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データベースのインスタンスやelastichsearchクラスターなどのステートフルサービスです。実行中の操作でそのようなリソースの削除が必要な場合、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:ロールバック構成を使用する



私が協力した別のチームは、 ロールバック構成と呼ばれるクラウド形成機能を使用していました 。 私は彼女に会ったことはありませんでしたが、これにより私のスタックの展開がさらに良くなることにすぐに気付きました。 現在、cloudformationを使用してコードをラムダまたはECSにデプロイするたびに使用しています。



仕組み:変更セットを作成するときに、 -rollback-configurationパラメーターでCloudWatchアラーム arnを指定します。 その後、変更セットを完了すると、awsは少なくとも1分間アラームを追跡します。 この間にアラームが状態をALARMに変更すると、展開がロールバックされます。



以下は、ユーザーのクラウドメトリックをクラウドログのエラー数として追跡するクラウドウォッチアラームを作成するcloudformationテンプレートからの抜粋の例です(メトリックはMetricFilterを介して作成されます )。



 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:テンプレートの最新バージョンを確実に展開する



cloudformationテンプレートの最新バージョンをデプロイするのは簡単ではありませんが、多くの損害を与えます。 開発者は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
      
      





レッスン6:車輪を再発明しない



cloudformationを使用した展開は簡単に思えるかもしれません。 aws cliコマンドを実行する一連のbashスクリプトが必要です。



4年前、私はaws cloudformation create-stackコマンドと呼ばれる簡単なスクリプトから始めました。 すぐに、スクリプトは単純ではなくなりました。 学んだ教訓ごとに、スクリプトはますます複雑になりました。 難しいだけでなく、たくさんのバグもありました。



現在、私は小さなIT部門で働いています。 経験によれば、各チームには独自のクラウド形成スタックのデプロイ方法があります。 そしてこれは悪いです。 全員が単一のアプローチを使用した方が良いでしょう。 幸いなことに、cloudformationスタックのデプロイと構成に役立つ多くのツールがあります。



これらのレッスンは、間違いを避けるのに役立ちます。



All Articles