AWS CodeDeploy と EC2 ASG でインスタンス起動無限ループに陥ったときは
陥って数時間溶かしたし、またやらかしそうなのでメモ
tl;dr
- CodeDeploy 側で対象の Deployment group の Environment configuration 内にある EC2 Auto scaling group (ASG) に関する設定を一度無効にする
- 対象の ASG で desired count を 1 以上にして、インスタンスを立てる
- 対象のインスタンスに適当なタグを設定して(もしくはすでについてる適当なタグを見つけて)、1 で変更した Environment configuration にある "Amazon EC2 instances" を有効にし Key-Value に設定/選んだタグを指定する
- デプロイしたいリビジョンを選び、対象の Deployment group にデプロイする
- デプロイが成功したのを確認して、1 の設定をもとに戻す
詳細
CodeDeploy がある EC2 Auto scaling group (ASG) に関連付けされている状況を考える。
起動中のインスタンスにはデプロイが成功するが、新規に立てたインスタンスでは(スクリプトが不十分だったりで)デプロイに失敗するということがある。この状態で ASG の desired count を 0 にしてしまうと、次回 N (N>0)にしたときに、新規に立ち上がったてきたインスタンスでデプロイが失敗する。デプロイが失敗するとそのインスタンスは破棄されるが、ASG で指定された desired count を満たしていないので、再度新たにインスタンスが立ち上がり、デプロイが失敗する。以下無限ループ。
AWS の公式ドキュメントにまさにこの状況になったときのワークアラウンドが説明されている: Instances in an Amazon EC2 Auto Scaling group are continuously provisioned and terminated before a revision can be deployed
これによれば、EC2 インスタンスをマニュアル(ASGを使わず)に立てて、対象の Deployment group と関連付けた後、エラーの無いリビジョンをデプロイすれば良いとある。ただ今回、ASG で立ち上がるインスタンスとほぼ同じ設定になるようにマニュアルでごにょって見たが、デプロイの途中でなにかの結果待ち(たぶんネットワーク)で止まってしまい、デプロイが完走しなかった。
その後、子供のお風呂など入れながら考えていたら、CodeDeploy 側をいじれば良いということに気がついて、上記の手順で解決できた。この記事を書きながら上のドキュメントを更に読んでいたら、デッドロック時の解決方法として別のトピックに似たような手順が書いてあることに気がついた: "The deployment failed because no instances were found for your deployment group" error
また、新規に立ち上がったインスタンスで「デプロイが失敗してもそのインスタンスを破棄しない」みたいな設定が ASG Lifecycle hook 側に無いか探したが、よくわからなかった(実際には Lifecycle hook の Default result を ABANDON から CONTINUE に変更してみたが、無限ループは止まらなかった)。