AWS CloudFormation構成のAutoScalingインスタンスを式年遷宮みたいに入れ替える方法2つ
ども、大瀧です。
AutoScaling構成で「AMIを更新したい」、「新しい設定に変えたい」というときにEC2インスタンスを入れ替える方法としては、ローリング更新(Rolling Update)が一般的かと思います。
ローリング更新はその名の通り、AutoScalingグループのうち一部のインスタンスを順繰りに入れ替えていく方式です。入れ替え中もグループの何台かは稼働状態を維持できるため、サービス断なしでインスタンスを入れ替えられる優れた方式ですね。一方でグループの全台を入れ替えるまでのステップ数が多いので、EC2インスタンスのOSやアプリケーションレベルでクラスタを組んでいる場合、ステップごとにクラスタの状態をアップデートしたり、クラスタで受け持つジョブやデータを再配置する手間がかかります。
そこで本ブログでは、CloudFormationでAutoScalingグループを管理するきに、インスタンスを式年遷宮のようにまとめて半自動で入れ替える方法を2つご紹介します。
実装方針
前提として、今回検討するのは以下の機能を持つ方法とします。
- 元のグループと同等構成の新しいグループを追加し、新旧の切り替えによってサービス断なしでアップデートを行う
- 切り替え中の任意のタイミングでコマンド実行やAPIコールなどクラスタに関するオペレーションが行える
オンプレミスではコンピュータの台数が手軽に増やせないという制約から必然的にローリング更新を選ぶことが多かったわけですが、1.はオンデマンドにインスタンスが追加できるクラウドならではの考え方ですね。新しいグループの正常動作を確認するまで元のグループを残しておくことで、容易に切り戻しできるというメリットもあります。
序文で半自動と書いたのは、2.で示すようなオペレーションを指しています。クラウドの運用というとスクリプトを駆使した全自動の仕組みをイメージしがちですが、手順の一部を自動化する一方で手動の操作も敢えて残しておく方が、より適用しやすいこともあると思います。今回のインスタンスの入れ替えはそこまで頻度が高くなく、かつ局面に応じて柔軟な対応が求められるので、一部手動の操作を挟む今回の方針がよりマッチすると考えます。
では、2つの方法をそれぞれ見ていきましょう。
1. パラメータでAuto Scalingグループの容量を操作する
Auto Scalingグループリソースのインスタンス台数に関するプロパティのうちDesiredCapacity
およびMaxSize
をCloudFormationのパラメータとしてテンプレート内で定義、変更することでインスタンスの入れ替えを起こします。CloudFormation特有の機能は利用しない方法です。
Parameters: WebGroupDesiredCapacity: Type: String Default: '4' WebGroupMaxSize: Type: String Default: '4' : Resources: WebGroup: Type: "AWS::AutoScaling::AutoScalingGroup" Properties: MinSize: '1' DesiredCapacity: Ref: WebGroupDesiredCapacity MaxSize: Ref: WebGroupMaxSize :
以下の手順でインスタンスを入れ替えます。
- 新しいAMI IDなど変更を加えたテンプレートでCloudFormationスタックを更新する。そのときにパラメータ値を変更し、一旦
DesiredCapacity
を倍の台数に(必要に応じてMaxSize
も)増やす -
クラスタのオペレーションを実行する(例: Elasticsearch APIでインデックスのシャードやレプリカを変更)
-
再度CloudFormationを更新し、元の台数に戻す
今回の目的はインスタンスの入れ替えなので、台数を戻すときに古いインスタンスを確実に削除することが肝要です。Auto ScalingグループのTermination PolicyをOldestInstance
に設定できないか、検討するのが良いでしょう。デフォルトポリシーのままだと、DesiredCapacity
が配置するAvailability Zone数の倍数になっていないと、ゾーンの配置によっては古いインスタンスが残ることがあります。その場合は、手動で当該インスタンスを終了してしまうのも最後の手として使えるでしょう。
2. 置き換え更新とリソースシグナルで操作する
こちらは、Auto Scalingを操作するためのCloudFormation特有の機能である置き換え更新を利用します。置き換え更新は、CloudFormationからAutoScalingインスタンスをアップデートする3つのポリシーのうちのひとつ *1です。
以下のようにCloudFormationテンプレートでAutoScalingグループを定義します。
Resources: WebGroup: Type: "AWS::AutoScaling::AutoScalingGroup" UpdatePolicy: AutoScalingReplacingUpdate: WillReplace: true CreationPolicy: ResourceSignal: Count: 1 Timeout: PT1H :
- 4-7行目 : 置き換え更新を定義。AMI変更などグループを更新するときはCloudFormationが新しいAutoScalingグループを作成、リソースシグナルによる更新成功が通知されたら元のAutoScalingグループを削除します。更新失敗の場合は新しいグループが削除され、元のAutoScalingグループを維持します
- 8-11行目 : リソースシグナルによる更新結果通知の設定
Count
: グループの更新成功のために必要な成功シグナル数Timeout
: 成功シグナル数がCount
になる前に指定の時間が経過すると更新失敗
設定としては、リソースシグナル周りがポイントになります。リソースシグナルはAutoScalingグループの各インスタンスの起動時にヘルパースクリプトのcfn-init
から送信するよう、ユーザーデータなどで構成するのが一般的です。一方で、今回のような半自動な仕組みするのであれば敢えてユーザーデータなどの自動化の仕組みではなく、運用者の手元からリソースシグナルを明示的に送信するのも有効です。AWS CLIの以下のコマンドでリソースシグナルを送信できます。
$ aws cloudformation signal-resource \ —stack-name WebStack \ —logical-resource-id WebGroup \ —status SUCCESS \ —unique-id <EC2インスタンスID>
コマンドで送信するときの注意点をいくつか示します。
—unique-id
に指定するインスタンスIDはAutoScalingグループ内の実際のインスタンスID以外はエラーになるので、都度調べる必要があります- 成功シグナルを送信しないと更新は失敗しロールバックしてしまうので、手動でシグナルを送信する旨を運用ルールとして徹底する必要があります
- 送信した成功リソースシグナル数を取得するCloudFormation APIは見当たらないので、
Count
を1にしてシンプルにするのがオススメです
スタックを更新すると、以下の流れで更新作業を進めます。
- 新しいAMI IDなど変更を加えたテンプレートでCloudFormationスタックを更新する。
-
CloudFormationによって元のAutoScalingグループとは別の新しいグループが追加される。
-
AutoScalingグループのリソースは
UPDATE_IN_PROGRESS
の状態で停止するので、クラスタのオペレーションを実行する(例: Elasticsearch APIでのクラスタノードの追加/削除やインデックスのシャード/レプリカの変更) -
クラスタのオペレーションが完了したら、成功リソースシグナルを送信する。
-
CloudFormationによって元のAutoScalingグループが削除される。
なお、ELBは新旧グループを区別せず平等にリクエストを転送するので、クラスタのオペレーション前は新しいグループへの転送を抑止したい場合、別途の対応が必要です。少し複雑にはなりますが、AutoScalingのLifeCycleHook機能が有用かもしれません。
まとめ
CloudFormationでAutoScalingグループを管理するきに、インスタンスを式年遷宮のようにまとめて半自動で入れ替える方法を2つご紹介しました。いずれも少しトリッキーな管理手法にはなりますが、一気に全インスタンスを入れ替える方がやりやすいケースもそれなりにあると思うので、参考になれば幸いです。
参考URL
脚注
- もうひとつのポリシーがローリング更新です。 ↩