CodeDeployでデプロイに失敗した場合の挙動を確認する

CodeDeployが東京にキタ!

[AWS CodeDeployがアジア・パシフィック(東京)で利用可能になりました](http://aws.typepad.com/aws_japan/2015/08/codedeploy-tokyo.html)

早速使いたい!と思ったのですが、「そういえばデプロイの途中で失敗した場合、どんな挙動となるのか」についてよく分かってなかったので試してみた時のメモ。

具体的に失敗とはどういうことかということですが、今回の実験ではCodeDeployのフロー（下図)の最後に実施されるValidateServiceで失敗(終了ステータスコード1)とさせてみて検証。

![app_hooks.png](https://qiita-image-store.s3.amazonaws.com/0/20193/27809abd-28f2-4a86-4db8-95c6236daf2f.png "app_hooks.png")

# 結論

失敗した場合、CodeDeployは自動でロールバックしてくれる!とか思ってたのですが、 **そんなことはない** ので、失敗時の挙動はしっかり確認し、失敗した場合にどうするか、失敗しても大丈夫なように設定する方法を導入前に検討した方が良いです。

以下引用。確かにコンセプトとしてそういうことはやってないみたいですね。

>AWS CodeDeploy does not directly support the concept of an automatic rollback of a deployment

[Redeployments and Deployment Rollbacks](https://docs.aws.amazon.com/codedeploy/latest/userguide/deployment-steps.html#deployment-rollback)

# 条件

+ オートケールグループにELBが紐付いている
+ Amazon Linux AMI 2015.03 (HVM)
+ CodeDeployAegntの配置や設定などは実施済み

CodeDeploy設定の詳細は以前書いたものを参照ください。

[GitHubへのpush時にCodeDeployを使ってEC2にアプリケーションをデプロイする](http://qiita.com/toshihirock/items/4ab08afcab2a0e7628a8)

# 既存のオートスケールグループのインスタンス群にデプロイする時に失敗する場合

以下の手順で実施。

1. オートスケールグループで2つのインスタンスを作成
2. 成功するリビジョンのアプリをデプロイ(OK-app)
3. その後失敗するリビジョンのアプリをデプロイ(NG-app)

失敗した場合、ロールバックして対象インスタンスにはOK-appが正常リストアされるかと勝手に思っていたのですが、ロールバックはしませんし、失敗するまでの処理は実行されたままの状態となります。(図でいうApplicationStopやBeforeInstallなどの処理)

なお、DeploymentConfigurationの設定でどのようにデプロイするのかという設定があります。

+ AllAtOnce（一気に全部)
+ HalfAtTime（半分ずつ)
+ OneAtTime(一つずつ)

OneAtTimeでやってみると一つのインスタンスにデプロイして失敗した場合、以降のインスタンスでのデプロイはスキップされました。

![Screen Shot 2015-08-21 at 7.07.26 PM.png](https://qiita-image-store.s3.amazonaws.com/0/20193/773cca82-3014-fc0e-1c7f-4bc5b31e43e5.png "Screen Shot 2015-08-21 at 7.07.26 PM.png")

どこの処理で失敗したか、およびその時の具体的なログなどはマネージメントコンソールからも確認可能です。

![Screen Shot 2015-08-21 at 7.07.41 PM.png](https://qiita-image-store.s3.amazonaws.com/0/20193/21343587-0a3b-daa4-90d3-1fdb9365f3c7.png "Screen Shot 2015-08-21 at 7.07.41 PM.png")

![Screen Shot 2015-08-21 at 7.07.50 PM.png](https://qiita-image-store.s3.amazonaws.com/0/20193/39673236-319f-1944-9bd7-a4d88d1ad171.png "Screen Shot 2015-08-21 at 7.07.50 PM.png")

なのでデバッグや原因確認はsshログインしなくてもできそうです。

ただ、上記のようなNG-appにトラフィックが流れる状態に本番環境でなってしまうと **非常にまずい** のでオートスケール連携の場合、CodeDeployのフローのApplicationStopで一旦オートスケールからデタッチしてELBからのトラフィックを止めて、validatedで問題なければ再アタッチするみたいな事が必要そうかと思われます。（そうしないとNG-appにトラフィックが流れる）

なお、本件は[公式ドキュメント](https://docs.aws.amazon.com/codedeploy/latest/userguide/elastic-load-balancing-integ.html)にELBとの連携の話が書いてあり

> In your application revision's AppSpec File, instruct AWS CodeDeploy to run the register_with_elb.sh script during the ApplicationStart event and to run the deregister_from_elb.sh script during the ApplicationStop event.

となっていてデプロイの途中でELBから外す、終わったらアタッチするなどの処理をしてねというのがあったのでこういった対応が必要であるという認識が必要です。

なお、サンプルがGitHubにあったのでこれを参考にすれば良いかと思います。

[awslabs/aws-codedeploy-samples](https://github.com/awslabs/aws-codedeploy-samples/tree/master/load-balancing/elb)


リストアですが、デプロイしたアプリのリビジョンはCodeDeployで管理はされているので手動ではありますが、OK-appを再度デプロイすればその状態に戻すことはできます。

# 最新のデプロイが失敗した状態でオートスケールによってEC2が起動した場合

以下で実験。

1. オートスケールグループを作成
2. 成功するリビジョンのアプリをデプロイ(OK-app)
3. その後失敗するリビジョンのアプリをデプロイ(NG-app)
4. オートスケールグループのmin,max,desireインスタンス数を1増加

上記だと新規に起動するインスタンスにはNG-appが配布されるのでは?という恐れがあったのですが、実際にはOK-appが配布され、ELBのInServiceとなりました。なるほど。

ただ、上の章で書いたようにNG-appがデプロイされた状態で何もしないとオートスケールグループ内にOK-appとNG-appがあってこれはこれでカオスとなってしまうので未然の予防(上に書いたようにNG-appにトラフィックが流れないように)が必要そうです。

# オートスケール新規起動時に失敗した場合

以下で実験。

1. オートスケールグループを作成
2. 対象サーバーにsshログインして適当なファイルを作成する
3. 「2」で作成したファイルがある場合のみ成功するデプロイを行う(NG-app)
4. オートスケールグループのmin,max,desireインスタンス数を1増加

上記をすると・・

新規インスタンスが起動->CodeDeployに失敗->対象インスタンスはshutdownされて別のインスタンスが起動しようとする->・・・・ **無限ループ!**

まあこのケースはあんまりない気もしますが、ありえない訳ではないのでこういうこともあるという事をしっかり認識しておくと良いかと思います。

なお、オートスケール新規起動のCodeDeployはオートスケールのライフサイクルイベントでやるようなのでこの場合、デプロイに失敗したインスタンスへのトラフィックが流れる事はなさそうです。

+ [AWS CodeDeployでAuto Scaling Lifecycleを手軽に利用する #cmdevio](http://dev.classmethod.jp/cloud/sds-integrates-as-lifecycle/)
+ [【新機能】Auto Scalingのインスタンス起動/破棄時に初期処理/終了処理を追加 – LifeCycleHook機能のご紹介](http://dev.classmethod.jp/cloud/aws/autoscaling-lifecyclehook/)