CodeDeployについて理解するための覚書


東京リージョンにAWS CodeDeployがやって来たので使えそうか調べていました。個人的なまとめを書き記しておくことにします。新事実がわかったら追記したりします。

## 参考

 - [AWS CodeDeploy 公式](https://aws.amazon.com/jp/codedeploy/)
 - [ブラックベルトシリーズのスライド](http://www.slideshare.net/AmazonWebServicesJapan/aws-black-belt-tech-2015-aws-codecommit-aws-codepipeline-aws-codedeploy)
 - [[新サービス] AWS CodeDeployを触ってみた #reinvent 2014](http://dev.classmethod.jp/cloud/codedeploy-ataglance/)

## 仕組み

### ノード

ノードって用語は公式では使われてなさそうだけど。まあとりあえずの呼称。

* CodeDeployエージェントがインストールされたサーバはいわゆるノードとなる
* ノードはデプロイ対象となることができる
* ノードはIDとか認証情報は持たない

エージェントについて詳しくは [AWS CodeDeploy Agent Operations](http://docs.aws.amazon.com/codedeploy/latest/userguide/how-to-run-agent.html) を参照のこと。rubyで書かれてるんですねとか443でアウトバウンド通信するんですねとかがわかる。


### CodeDeploy サービスの動き

* CodeDeployサービスは以下のことを行う。
  - デプロイ開始のトリガーを受け取る
  - デプロイ対象となるノードを見つけ出す
  - 対象サーバでデプロイを実行する(対象にインストールされたエージェントが実際には行う)
* デプロイ元となるソースは東京において以下の二種類が利用できる
  - GitHub連携
  - S3にzipで固めてアップロード

CodePipelineとかの連携が早く東京リージョンにも来ればいいのに。

### デプロイの流れ

極めてシンプルなので最初「えっ」と思った。

CodeDeployサービスは以下の三つの処理を各ノードで実行する。

* 一時ディレクトリにファイルがダウンロードされる (DownloadBundleと呼ばれる)
* appspec.yml で定義されたファイルコピータスクが実行される
* appspec.yml で定義されたパーミッション変更タスクが実行される

これだけだ。1台ずつ・半分ずつ・全部一度と3パターンの実行方法が提供されている。

これ以外のことは全てフックで実行する必要がある。

[![スクリーンショット 2015-11-01 16.22.09.png](https://qiita-image-store.s3.amazonaws.com/0/17911/fdd9f833-0ff4-60d5-4980-6a5ebe9a3b6f.png "スクリーンショット 2015-11-01 16.22.09.png")
](http://docs.aws.amazon.com/codedeploy/latest/userguide/app-spec-ref.html)

[AWS CodeDeploy AppSpec File Reference](http://docs.aws.amazon.com/codedeploy/latest/userguide/app-spec-ref.html)


なお、フックスクリプトにデプロイプロセスが渡すことができる情報は、デプロイIDとアプリケーション名、デプロイグループ名のみである。いわゆるENV名みたいなやつとかをカスタム環境変数的に渡すことはできない。

しかたがないので、デプロイグループを staging-web とか production-cron とした上で、こんなことをして判別したりしている。

```
declare -r RAILS_ENV=${DEPLOYMENT_GROUP_NAME%%_*}
declare -r ROLE=${DEPLOYMENT_GROUP_NAME##*_}
```

フックスクリプトや各タスクが失敗した場合、そのサーバでのデプロイは失敗したとマークされる。「失敗した場合」とは 0 以外で終了した場合である。

1台ずつ/半分の台数ずつデプロイする場合、失敗したサーバがあるとそれ以降のデプロイプロセスは実行されない。ドキュメントに書いてあるけれど、その場合**一部のサーバでは正常にデプロイが完了している場合がある**ので注意しなければならない。

### オートスケールとの連携

おそらく現在の東京リージョンで CodeDeploy を利用する最大のメリットは AutoScale サービスとの連携であると思う。

* CodeDeployサービスでデプロイ対象としてAutoScaleグループ名を指定できる。
* AutoScaleがインスタンスを新しく起動するとき、ELBに組み込まれたりする前に CodeDeploy によって最後に成功したデプロイが実行される。

この辺、連携してるよってことがAutoScaleサービス側からはよくわからないのがやや気持ち悪いところ。

## イベントの通知

- 新機能 - AWS CodeDeploy イベントの通知](http://aws.typepad.com/sajp/2016/02/new-ws-codedeploy-notification-evnet.html)

2/17 に更新されて、コードデプロイの通知が可能になった。これでポーリングワールドから解放される!
デプロイグループに対して、Create Trigger というボタンが追加されており、任意のタイミングで通知を発行することができるようだ。

## 制限というかやってくれないこと

* 各サーバで実行されるフックスクリプトは他のサーバのことを知らない。
* GitHub連携では refspec を指定できない。
  - コミットIDのSHA1をフルで指定する必要があるようだ。タグ名やブランチ名を指定することはどうやらできない。
* CodePipeline、CodeCommit が東京でまだ使えない。
* ManagementConsoleが使いにくい。
* サービス側から任意の環境変数とか渡せない
* スタンドアロン動作ができない。CodeDeployサービスを通さずに同様のデプロイをローカルに打つことができない。
  - 具体的には「ブランチごとのテスト用サーバを気軽に立ち上げる」みたいな柔軟さはない。
* リージョンをまたいではデプロイできない。
* コードデプロイエージェントは勝手に自分自身をアップデートしようとするんだけど、オートスケールでインスタンス追加された際にアップデートが走ると実行中のデプロイが失敗するケースがあった。AMIにあらかじめコードデプロイのエージェントをインストールしておく場合は常に最新に保つ必要がある。(だから、初期起動時にCodeDeploy Agent のインストールからやった方がいいのかも)([ここにかいてあった](http://docs.aws.amazon.com/codedeploy/latest/userguide/auto-scaling-integ.html))
* 一つのオートスケールグループに複数のデプロイメントグループの適用はやめた方がよい。[とドキュメントに書かれている。](http://docs.aws.amazon.com/codedeploy/latest/userguide/troubleshooting.html#troubleshooting-multiple-depgroups)これができると「アプリケーションのセットアップと設定ファイルの配布」みたいなのを個別のCodeDeployで実現するとかできて夢広がるのだけど残念である。

## トラブルシュート

いちおう[公式ドキュメント](http://docs.aws.amazon.com/codedeploy/latest/userguide/troubleshooting.html)も割と充実している。

* とりあえずログを見る `tail -f  /var/log/aws/codedeploy-agent/codedeploy-agent.log` とはいえ、デフォルトだとあんまり細かいログが出ない。
* 設定ファイル `/etc/codedeploy-agent/conf/codedeployagent.yml` を編集して `verbose` を true に設定すると、それなりにマシなログが出るようになる。
* ApplicationStop のフックは「前回デプロイ成功した際のコードが呼ばれる」ので注意する。新しいコードのApplicationStopは次回のデプロイ時に呼ばれる。
* ApplicationStop が失敗する場合、普通にデプロイしても失敗してしまう。その時は慌てず以下のいずれかの手段を取る。
  - awscli から `--ignore-application-stop-failures` オプションを指定して新しいコードをデプロイする。
  - 対象ノードで `/opt/codedeploy-agent/deployment-root/` 以下の過去のデプロイされた資材を削除して  codedeploy-agent を再起動する。
* デプロイ失敗時のロールバック機構やELBからの自動切り離しなどは用意されていないので、トラブル起きたらまず各サーバの確認を。
  * Redeployments と RollBackについては解説が存在しているが、「以前のリビジョンをデプロイすることでそれに替えられるよ」というなんともいえないことが書いてあるだけだ。 #=> [Redeployments and Deployment Rollbacks](http://docs.aws.amazon.com/codedeploy/latest/userguide/deployment-steps.html#deployment-rollback)

# 今の時点ではどうか

割と十分使えそうというのが感想。

個人的には外部からsshする構成を取らなくて済む、あとは中央管理サーバを置かなくてよいのと、オートスケール環境との親和性が高いのが大きい。

~~開始と終了をトリガーにした処理ができないのはかなり設計上ストレスがたまるところだし、~~失敗時のリカバリとかも気を使うところだ。Web GUI画面が相当不便なのも地味にイライラすること請け合いである。とはいえ仕組みがシンプルで機能が限られている分、設計上迷うことは多くない。