GitHubへのpush時にCodeDeployを使ってEC2にアプリケーションをデプロイする

EC2へのアプリケーションのデプロイを考えた時に色んな候補があるかと思います。以下にまとまっていました。

[AWSでデプロイとスケーリングを自動化する方法まとめ](http://qiita.com/hiro_koba/items/eb438945d64c3d765e04)

最初、OpsWorksを検討したのですが、オートスケーリングに対応していないという点でボツとなりました。。。また、Jenkinsなどを使えば可能だと思いますが、その場合にはJenkinsをSPOFにならないように気をつけたり、AWSと連携するためにごにょごにょするのが面倒かなと思いました。

で、まだtokyoリージョンにはきていませんが、CodeDeployはオートスケーリングが対応しており、どうだろうということで色々試してみたたのでメモ。

今回の例ではGitHubへのpush時にCodeDeployを利用してEC2にWordPressのデプロイを行ってみました。

# CodeDeployとは

+ アプリケーションのデプロイを行うためのサービス。デプロイするプログラミング言語などに制限はない
+ アプリケーションにデプロイに特化した機能なので環境構築などに使うべきではない(やろうと思えばできるけどやらない方が良いと思う）環境構築もしたい場合、ElasticBeanstalkやOpsWorksを考えたほうが良い
+ **appspec.yml**というファイルにデプロイ時の詳細を記述。デプロイ時の独自のライフサイクルタイミングで任意のシェルスクリプトを実行できる
+ 特定のタグが付与されたEC2群もしくはオートスケーリングに紐づくEC2群にデプロイ可能
+ 特定のリビジョンに戻ることが可能
+ 現在はGitHubとS3と連携が可能(なぜCodeCommitがない??)
+ 実行するためにはCodeDeployAgentを対象EC2(にインストールする必要がある
+ 対象OSはAmazon Linux、Red Hat Enterprise Linux、Ubuntu Server、Microsoft Windows Server
+ CodeDeployエンドポイントと接続する必要があるため、プライベートサブネットの場合などにはNATが必要


# 前提

+ AWS CLIインストール済み
+ GitHubのアカウント取得済み
+ 2015/7/20現在CodeDeployはtokyoリージョンはないのでus-east1で確認

# 参考

+ [Using the AWS CodeDeploy Create Deployment Walkthrough](https://docs.aws.amazon.com/ja_jp/codedeploy/latest/userguide/getting-started-walkthrough.html)
+ [Automatically Deploy from GitHub Using AWS CodeDeploy](http://blogs.aws.amazon.com/application-management/post/Tx33XKAKURCCW83/Automatically-Deploy-from-GitHub-Using-AWS-CodeDeploy)


# CodeDeployが使うRoleの作成

[Create a Service Role for AWS CodeDeploy](https://docs.aws.amazon.com/ja_jp/codedeploy/latest/userguide/how-to-create-service-role.html)

CodeDeploy自体が利用するRoleの設定を行います。

まず、以下のファイルを作成します。

```lang:CodeDeployDemo-Trust.json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "",
      "Effect": "Allow",
      "Principal": {
        "Service": [
          "codedeploy.us-east-1.amazonaws.com", 
          "codedeploy.us-west-2.amazonaws.com",
          "codedeploy.eu-west-1.amazonaws.com",
          "codedeploy.ap-southeast-2.amazonaws.com"
        ]
      },
      "Action": "sts:AssumeRole"
    }
  ]
}
```

作成後、以下のコマンドを実行し、CodeDeployDemoというCodeDeploy用のロールを作成します。

```
$aws iam create-role --role-name CodeDeployDemo --assume-role-policy-document file://CodeDeployDemo-Trust.json
```

上記コマンド実行後、

"Arn": "arn:aws:iam::hogefuga:role/CodeDeployDemo"

というような形でこのロールのArnが表示されるのでメモしておきます。

また、以下のコマンドを実行し、先ほどのロールがCodeDeployで利用できるように設定します。

```
$aws iam attach-role-policy --role-name CodeDeployDemo --policy-arn arn:aws:iam::aws:policy/service-role/AWSCodeDeployRole
```

# RDSの作成

WordPressで利用するMySQLをRDSで作成します。
リージョンはus-east1で作成してください。また、次に作成するEC2からの3306ポートで接続できるようなSecurityGroupの設定をしてください。
作成時に設定したユーザー名、パスワード及び作成後のRDSの接続エンドポイントはメモしておいてください。


# EC2の起動

[Step 1: Launch an Amazon Linux or Red Hat Enterprise Linux Amazon EC2 Instance](https://docs.aws.amazon.com/ja_jp/codedeploy/latest/userguide/getting-started-set-up-instance.html)

+ OSはAmazonLinux
+ Auto-assign PublicIPを有効にする
+ SecurityGroupのInboundでSSHとHTTPを0.0.0.0/0で許可し、Outboundは制限しない
+ S3のread権限があるIAMロールを付与すること(CodeDeployAgentのインストールのため）
+ NameタグではCodeDeployDemoと設定すること
+ UserDataに以下の設定を行う。なお、CodeDeployAgent取得先バケット名はregionによって変わるので注意。また、SQL実行の箇所はユーザー名はroot、パスワードはpassword、RDSのエンドポイントはcodedeploy.cukvcqdui8ox.us-east-1.rds.amazonaws.com という場合の設定となるので適宜変更してください。

```
#!/bin/bash

# install CodeDeploy agent
yum -y update
yum install -y ruby
yum install -y aws-cli
cd /home/ec2-user
aws s3 cp s3://aws-codedeploy-us-east-1/latest/install . --region us-east-1
chmod +x ./install
./install auto

# install httpd
yum install -y httpd
chkconfig httpd on
service httpd start

# install application dependencies
yum install php php-mysql php-gd php-mbstring -y
yum install mysql -y

#exec sql
mysql -u root -ppassword -h codedeploy.cukvcqdui8ox.us-east-1.rds.amazonaws.com <<EOF
CREATE USER'wordpress-user'@'%' IDENTIFIED BY 'wordpress';
CREATE DATABASE \`wordpress\`;
GRANT ALL PRIVILEGES ON \`wordpress\`.*TO"wordpress-user"@"%";
FLUSH PRIVILEGES;
EOF
```

起動し、StatsuCheckがrunningになったら、ssh接続し、agentがインストールされているか確認します。

```
$sudo service codedeploy-agent status
The AWS CodeDeploy agent is running as PID 6975
```

必要に応じて`var/log/cloud-init-output.log`でのログ確認やその他ミドルウェアの設定も確認してください。

# GitHubにCodeDeploy用のWordPressをpushする

[Step 2: Configure your Source Content to Deploy to the Amazon Linux or Red Hat Enterprise Linux Amazon EC2 Instance](https://docs.aws.amazon.com/ja_jp/codedeploy/latest/userguide/getting-started-configure-repo.html)

以下より、ローカルPCで実施します。

WordPressのソースコードをgit cloneしてきます。

```
$mkdir -p /tmp/WordPress
$git clone https://github.com/WordPress/WordPress.git /tmp/WordPress
```

スクリプト配置用のフォルダ作成。

```
$mkdir -p /tmp/WordPress/scripts
```

httpdを止めるためのスクリプトを作ります。

```lang:/tmp/WordPress/scripts/stop_server.sh
#!/bin/bash
isExistApp=`pgrep httpd`
if [[ -n  \$isExistApp ]]; then
   service httpd stop
fi
```

httpdを開始するスクリプトも作ります。

```lang:/tmp/WordPress/scripts/start_server.sh
#!/bin/bash
service httpd start
```

パーミッションを変更するスクリプトを作成します。

```lang:/tmp/WordPress/scripts/change_permissions.sh 
#!/bin/bash
chown -R apache:apache /var/www/html/WordPress
chmod -R 744 /var/www/html/WordPress
```

作成したスクリプト群の権限を変更します。

```
$chmod +x /tmp/WordPress/scripts/*
```

次にどこにソースコードを配置するのか、またどのライフサイクルタイミングで何をするのかをappsec.ymlに記述します。

```lang:/tmp/WordPress/appspec.yml
version: 0.0
os: linux
files:
  - source: /
    destination: /var/www/html/WordPress
hooks:
  AfterInstall:
    - location: scripts/change_permissions.sh
      timeout: 300
      runas: root
  ApplicationStart:
    - location: scripts/start_server.sh
      timeout: 300
      runas: root
  ApplicationStop:
    - location: scripts/stop_server.sh
      timeout: 300
      runas: root
```

appsec.ymlの詳細は以下を参照のこと。

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

次にGithubでリポジトリを作成します。
今回の例ではブラウザから事前に **toshihirock/CodeDeployWordPress**というリポジトリを作成しました。

リポジトリ作成後、GitHubにコードをpushします。

```
$cd /tmp/WordPress
$git add .
$git commit -m "add codedeploy scripts"
$git remote rm origin
$git remote add origin https://github.com/toshihirock/CodeDeployWordPress.git
```

# CodeDeployの設定

まずCodeDeployでアプリケーションの作成を行います。以下のコマンドで **WordPress_App** というアプリケーションを作成します。

```
$aws deploy create-application --application-name WordPress_App --region us-east-1
```

次にデプロイメントグループを作成します。本設定ではどのEC2にデプロイするかを設定します。下記例ではEC2のタグでKey=Name、Value=CodeDeployDemoというEC2群にデプロイすることを示す **WordPress_DepGroup** というデプロイ面とグループを作成しました。

```
$aws deploy create-deployment-group \
  --region us-east-1 \
  --application-name WordPress_App \
  --deployment-group-name WordPress_DepGroup \
  --deployment-config-name CodeDeployDefault.OneAtATime \
  --ec2-tag-filters Key=Name,Value=CodeDeployDemo,Type=KEY_AND_VALUE \
  --service-role-arn arn:aws:iam::hogefuga:role/CodeDeployDemo
```

最後にソースコードをデプロイします。`--github-location`オプションは適宜自分のリポジトリ名、対象コミットIDに変更してください。

```
$aws deploy create-deployment \
  --region us-east-1 \
  --application-name WordPress_App \
  --deployment-config-name CodeDeployDefault.OneAtATime \
  --deployment-group-name WordPress_DepGroup \
  --github-location commitId=74e74ad4e0f80fb91a6034f3be58fce5b45d4a2c,repository=toshihirock/CodeDeployWordPress
```


デプロイが成功すればデプロイ対象のEC2のPublicIPアドレスを利用して以下のようなURLでアクセスが可能だと思います。

http://ec2-52-2-237-19.compute-1.amazonaws.com/WordPress/



# GitHubとの連携を行う

[Automatically Deploy from GitHub Using AWS CodeDeploy](http://blogs.aws.amazon.com/application-management/post/Tx33XKAKURCCW83/Automatically-Deploy-from-GitHub-Using-AWS-CodeDeploy)

まず、IAMでGitHubというユーザーを作成します。なお、ユーザー作成の際に表示されるAccess Key IDとSecret Access keyをメモしておいてください。

また、以下のポリシーを上記ユーザーにCustomPolicyとしてアタッチします。PolicyNameはCodeDeploy-Accessとしました。なお、123ACCOUNTIDという部分は自分のAWSアカウントIDに変更してください。

+ IAM->Users->GitHub->InlinePolicies->click here
+ Custom Policy

```
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "codedeploy:GetDeploymentConfig",
      "Resource": "arn:aws:codedeploy:us-east-1:123ACCOUNTID:deploymentconfig:*"
    },
    {
      "Effect": "Allow",
      "Action": "codedeploy:RegisterApplicationRevision",
      "Resource": "arn:aws:codedeploy:us-east-1:123ACCOUNTID:application:WordPress_App"
    },
    {
      "Effect": "Allow",
      "Action": "codedeploy:GetApplicationRevision",
      "Resource": "arn:aws:codedeploy:us-east-1:123ACCOUNTID:application:WordPress_App"
    },
    {
      "Effect": "Allow",
      "Action": "codedeploy:CreateDeployment",
      "Resource": "arn:aws:codedeploy:us-east-1:123ACCOUNTID:deploymentgroup:WordPress_App/WordPress_DepGroup"
    }
  ]
}
```

次にGitHub側の設定をします。AWS CodeDeploy用のサービスを追加します。

+ GitHubのページでリポジトリを選択(私の場合、toshihirock/CodeDeployWordPress)
+ Settings
+ Webhooks and Services
+ Add Services->AWS CodeDeploy

以下のように項目を追加します。

![Screen Shot 2015-07-20 at 6.56.36 AM.png](https://qiita-image-store.s3.amazonaws.com/0/20193/1b704058-a92d-92cc-dc67-725314584aa3.png "Screen Shot 2015-07-20 at 6.56.36 AM.png")


次にGitHubのアクセストークンを取得します。

[Personal access tokens](https://github.com/settings/tokens)を表示し、Generate a personal access token を選択し、以下のように設定します。

![Screen Shot 2015-07-20 at 7.03.50 AM.png](https://qiita-image-store.s3.amazonaws.com/0/20193/630b65d8-5a56-56cd-e544-b9a1e7ecb729.png "Screen Shot 2015-07-20 at 7.03.50 AM.png")

設定後、トークン情報が表示されるのでメモしておいてください。

先ほどCodeDeployのサービスを設定したページへ再度遷移し、GitHub Auto-Deploymentを追加します。

+ GitHubのページでリポジトリを選択(私の場合、toshihirock/CodeDeployWordPress)
+ Settings
+ Webhooks and Services
+ Add Services->GitHub Auto-Deployment


![Screen Shot 2015-07-20 at 7.57.00 AM.png](https://qiita-image-store.s3.amazonaws.com/0/20193/a23fb3f9-b328-2b39-61c4-ca5c723d239b.png "Screen Shot 2015-07-20 at 7.57.00 AM.png")

作成後、以下のように2つのサービスが設定された形となっているかと思います。

![Screen Shot 2015-07-20 at 9.23.48 AM.png](https://qiita-image-store.s3.amazonaws.com/0/20193/4e48ac64-fe92-3f9a-7546-f227a996ee2e.png "Screen Shot 2015-07-20 at 9.23.48 AM.png")


準備ができたので試しにWordPressリポジトリにからコミットをしてみます。

```
$cd /tmp/WordPress
$git commit --allow-empty -m "test CodeDeploy"
$git push origin master
$git log -1
commit b74c07c54a747fd9a44be09031bcd272ae749bed
```

上記実施後、CodeDeployの画面を確認すると先ほどのコミットIDのリビジョンのソースコードがデプロイされたのが分かります。

![Screen Shot 2015-07-20 at 8.03.23 AM.png](https://qiita-image-store.s3.amazonaws.com/0/20193/ae8a99c1-1770-b317-f84e-69c07dc0c532.png "Screen Shot 2015-07-20 at 8.03.23 AM.png")

# 最後に

今回CodeDeployを試してみましたが、GitHubへのHook時にデプロイできるのは非常に便利に感じました。そしてCodeDeploy自体の管理をしなくて良いというのは非常に楽ですね。

はやくCodeCommitとの連携ができて、VPCエンドポイントにCodeDeployとCodeCommitが出来てプライベートサブネットからも利用できるようになるととても嬉しいです。