EC2を使うならCodeDeployも使わないともったいない

**CodeDeploy**は、AWSが提供している[デプロイ](https://www.weblio.jp/content/%E3%83%87%E3%83%97%E3%83%AD%E3%82%A4)用サービスです。

業務でデプロイ環境構築に使ってみたところ、結構便利で使いやすかったので、
布教のような記事を書いてみます。
（細かい設定方法なんかはここでは扱いません）

# CodeDeployの何が良いか

## 設定、準備が簡単

デプロイ対象のサーバー上でCodeDeployエージェントをインストール&起動する作業以外に、
サーバー上での作業は発生しません。
エージェントの作業もドキュメントに載っているコマンドを順番に叩くだけです。
その他の設定（デプロイ方法や通知先など）はだいたいAWSのGUI、もしくは、YAMLで書かれた設定ファイルで行います。
この設定ファイルも、一画面に収まるようなものです。
新しい言語を習得する必要も、長大な設定ファイルを用意する必要もありません。

## EC2対象ならタダ

AWSの料金体系って、複雑でちょっとわかりにくいところが多いですよね。私あれ苦手なんです。
しかしCodeDeployに関しては、デプロイ対象のサーバーがEC2のインスタンスであれば、
**なんと追加料金はかかりません。タダ！**
（EC2以外のサーバーにデプロイする場合は、1つのインスタンスに1回デプロイするのにいくら、と料金がかかるようです）

## オートスケールに対応

個人的に一番うれしい機能です。
CodeDeployでは、デプロイ対象にオートスケールグループを選択することもできます。
現在立ち上がっている全インスタンスに同じようにデプロイしてくれるのはもちろんのこと、
台数が増えた場合、**最後に成功したデプロイを増えたインスタンスに対して自動的に実行してくれます。**
やるべきことはオートスケールグループを選ぶだけ。楽ちんです。

# 不満点

概ね使用感には満足してますが、不満が無いこともありません。

## ログが見づらい

デプロイに失敗したら、その原因をログから調べたいところですが、
AWSのコンソールからは、CodeDeployが出力したログの最後の1行しか見ることができません。
インスタンスにSSHで入ればログを見られないこともないですが、
コンソールからすべてのログが見られればもっと便利なのになあ、と思います。
（実際、ほとんど直接EC2に入ってログを確認したことはありません）

# ハマりポイント

CodeDeployの設定方法は、本家AWSのドキュメントや他の方が書かれた素晴らしい記事に任せるとして、
ここでは実際に私が遭遇したハマりポイントをご紹介します。

## ロールの設定を忘れずに

デプロイ対象となるEC2のインスタンスには、特定の権限を設定したIAMロールを付与する必要があります。
今は、インスタンスにロールがついてなくても、後から付与する方法があるので楽になりましたが、
私がデプロイ環境を構築したころ（今年の初めくらいだったかな？）は、
インスタンスを生成するときにしかロールを付与できなかったので、非常に面倒でした。
（わざわざインスタンスを複製して新しく作り直さないといけなかった）

## CodeDeployエージェントの起動を忘れずに

デプロイが全然進まないのでなんでだろうと思って調べてみたら、対象のインスタンスでエージェントが起動していないってことが何回かありました。
原因は単純で、そのインスタンスにエージェントをインストールする作業自体を忘れていただけでした。
AWSのドキュメント通りインストールしていればほぼ起こらない現象ではあります。

## デプロイはすぐ終わらない

まあ、当然と言えば当然ですが、例えばオートスケールでインスタンスが立ち上がった際、
デプロイが開始されてからファイルが完全に反映しきるまで、少し時間がかかります。
cronで毎分何かを行わせるような設計になっていた場合、デプロイが完全に終わる前にコマンドが呼ばれてしまい、
エラーになってしまうという現象が発生する恐れがあります。
デプロイが完全に終わってからコマンドを呼ぶような設計を考える必要があります。
（最初はcrondの自動起動をoffにしておき、デプロイの最後にcrondを起動するようなスクリプトを用意するなど）

# Git/Jenkinsと連携させた自動化の例

最後に、CodeDeployとgit・jenkinsを連携させてデプロイを自動化させる場合の例を簡単にご紹介します。

## 1. gitにpush

プログラムファイル一式をサーバーに反映する準備ができたら、gitの特定のブランチに内容をpushします。
例えば`master`ブランチは開発環境、`staging`ブランチはステージング環境、って感じです。

## 2. gitからjenkinsにwebhook

gitはpushを受けたら、jenkinsサーバーに対してwebhookを飛ばします。

## 3. jenkinsがgitからのpushを受けてファイル一式をコンパイル

jenkinsは対象ブランチの更新を確認したら、ファイル一式をコンパイルします。
例えば`composer install`等ですね。

## 4. jenkinsがリビジョンをs3にアップ

**リビジョン**とは、CodeDeployの言葉で、反映するためのファイル一式をzip圧縮したもののことです。
jenkinsのCodeDeployプラグインを導入すると、このリビジョンの作成＆アップロードから、この先のCodeDeployへの通知まで自動でやってくれます。
また、もしgithubを使っている場合、s3にリビジョンをアップロードする必要はありません。
githubから直接ファイルを取得してくれるようです。
（私は使ってないので詳細はわかりません）

## 5. CodeDeployがデプロイを開始

前述のjenkinsのプラグインがAWSのAPIをたたき、CodeDeployのデプロイを開始してくれます。

## 6. CodeDeployがAmazonSNSを通じてslackに通知

CodeDeployでは、デプロイの開始や終了などのタイミングで、AmazonSNS（SimpleNotificationService）を使って通知を飛ばすことができます。
私の環境では、開始時・成功時・失敗時にそれぞれslackに通知を飛ばすようにしています。

---

以上の手順のうち、1以外の作業はすべて自動で行われるため、
一度設定してしまえば、あとはgitにpushするだけでデプロイが行われるようになります。
jenkinsのところでテストとか挟んでも良いと思います。

なお、開発とステージングは上記の通りgit pushだけで反映できるようになってますが、
本番環境だけは、特定のマシンでバッチファイルを叩かないとデプロイされないようにしています。
間違えて反映してしまう事故を防止するためです。

その場合も、ステージング用のリビジョンのうち最新のものを取得してCodeDeployに渡す作業はすべてバッチファイルの中で行われているので、
開発者は実行を開始したら後は待つだけです。

# 布教、終わり

以上、CodeDeployのご紹介でした。
capistrano等のデプロイツールをお使いの方は多いかと思いますが、もしEC2でサーバーを運用されていたら、
CodeDeployの利用も検討してみてください。**タダですし。**