私は一緒に働き始めました 雲の形成 4年前。 それ以来、私はすでに運用されていたものを含め、多くのインフラストラクチャを破壊してきました。 しかし、何かを失敗するたびに、私は何か新しいことを学びました。 この経験を通じて私が学んだ最も重要な教訓のいくつかを共有します。
レッスン 1: 変更を展開する前にテストする
働き始めてすぐにこの教訓を学びました 雲の形成。 そのとき正確に何を壊したかは覚えていませんが、次のコマンドを使用したことは間違いなく覚えています awsクラウドフォーメーションのアップデート。 このコマンドは、デプロイされる変更の検証を行わずに、単にテンプレートをロールアウトします。 すべての変更を展開する前にテストする必要がある理由については説明の必要はないと思います。
この失敗の後、私はすぐに変更しました 配備パイプライン、update コマンドをコマンドに置き換えます。 変更セットの作成
# 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"
変更セットが作成されると、既存のスタックには影響しません。 update コマンドとは異なり、変更セットのアプローチは実際のデプロイメントをトリガーしません。 代わりに、展開前に確認できる変更のリストが作成されます。 変更は 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 の変更には特に注意してください。 交換する, 削除 またはどこで 交換が必要 - 真。 これらは最も危険な変更であり、通常は情報の損失につながります。
変更を確認したら、展開できます
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 への接続が失われることが起こり、私の「スマート メカニズム」はそれを新しい認証情報を生成する信号として処理しました。
このスクリプトを運用環境で使用し始めて接続の問題が再び発生した場合、新しい認証情報でスタックが更新されます。 この特定のケースでは、悪いことは何も起こりません。 ただし、私はこのアプローチを放棄し、スタックの作成時に認証情報を XNUMX 回だけ提供する別のアプローチを使用し始めました。 その後、スタックを更新する必要があるときは、パラメーターのシークレット値を指定する代わりに、単純に次のようにします。 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 にデプロイするたびにこれを使用しています。
仕組み: あなたが指定します CloudWatch アラーム パラメータで --ロールバック構成変更セットを作成するとき。 その後、一連の変更を実行すると、aws は少なくとも XNUMX 分間アラームを監視します。 この間にアラームの状態が ALARM に変化すると、展開がロールバックされます。
以下はテンプレートの抜粋の例です 雲の形成私が作成するもの クラウドウォッチアラーム、クラウド ログ内のエラー数としてクラウド ユーザー メトリクスを追跡します (メトリクスは次の方法で生成されます) メトリックフィルター):
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: 車輪の再発明はしないでください
でデプロイしているように見えるかもしれません 雲の形成 - それは簡単です。 必要なのは、aws cli コマンドを実行する大量の bash スクリプトだけです。
4 年前、私は aws Cloudformation create-stack コマンドと呼ばれる単純なスクリプトから始めました。 すぐに脚本は単純ではなくなりました。 教訓を学ぶたびに、脚本はますます複雑になっていきました。 難しいだけでなく、バグも多かったです。
私は現在、小さな IT 部門で働いています。 経験によれば、各チームはクラウドフォーメーション スタックをデプロイする独自の方法を持っています。 そしてそれは悪いことです。 全員が同じアプローチを取ったほうが良いでしょう。 幸いなことに、cloudformation スタックのデプロイと構成に役立つツールが多数あります。
これらのレッスンは間違いを避けるのに役立ちます。
出所: habr.com