BitbucketでAWS CodeDeployを利用した自動デプロイ

Bitbucketでバージョン管理を行い、AWS上のインスタンスでアプリケーションを動かしているけど毎回本番サーバーに入ってpullしている。。自動化したいけどGitHubじゃないので困っている。。そんな人が対象です。

ここでは、Bitbucket Pipelinesを利用し、AWS CodeDeployを使ってEC2へ自動デプロイを行います。

# 最終的なデータフロー
<img width="1075" alt="スクリーンショット 2019-04-08 15.27.07.png" src="https://qiita-image-store.s3.amazonaws.com/0/191919/7e6c57ef-b2a2-8bfe-2966-f2d95d3f56b6.png">


# CodeDeploy用のIAMユーザーを作成する
はじめに、CodeDeploy用のユーザーを新規作成します。
![user.png](https://qiita-image-store.s3.amazonaws.com/0/191919/82354897-2019-b936-c718-0f915b59002c.png)

ここではCodeDeployerという名前で作成し、アクセス種類はプログラムによるアクセスを選択しました。
なお、作成後発行されるAccess key IDとSecret access keyはダウンロードして控えておきます。

## ポリシーのアタッチ
作成したユーザーに対し、ポリシーを設定します。
ここでは、AWSCodeDeployFullAccess, AmazonS3FullAccessの二つをアタッチすることで、CodeDeployとS3を利用できるように設定します。
![policy.png](https://qiita-image-store.s3.amazonaws.com/0/191919/a1d32ccf-6ef7-6b5d-1158-1f49fa480a88.png)


# CodeDeployロールの作成
次に、CodeDeploy用のロールを作成します。AWSサービス > CodeDeployを選択し、CodeDeployRoleAPIというロール名で作成しました。
ポリシーについては、ここではAmazonEC2FullAccess, AWSCodeDeployRoleを付与しています。
<img width="1070" alt="codedeployrole.png" src="https://qiita-image-store.s3.amazonaws.com/0/191919/20726988-a873-f9fc-c767-2bd842263759.png">

<img width="1032" alt="codedeployrole2.png" src="https://qiita-image-store.s3.amazonaws.com/0/191919/99ec0047-9909-4379-3e62-4ba22deb6704.png">

# S3 Bucketの作成
ソースコードのリビジョンを格納するバケットを作成します。ここではcodedeploy-bucketという名前で作成しました。
![s3.png](https://qiita-image-store.s3.amazonaws.com/0/191919/f63811e2-97eb-8027-5359-cc5f7e4d7831.png)

# デプロイしたいEC2インスタンスの設定
対象のEC2に、デプロイするインスタンスを識別するためのタグを付与します。
ここではキーをDeploy, 値をCodeDeployに設定しました。
![ec2tag.png](https://qiita-image-store.s3.amazonaws.com/0/191919/757b1ce7-02e1-649a-84a6-85a294ea4c9c.png)

## CodeDeploy AgentをEC2インスタンスにインストール
詳しくは[公式ドキュメント](https://docs.aws.amazon.com/ja_jp/codedeploy/latest/userguide/codedeploy-agent-operations-install.html)に書かれていますが、以下の手順でインストールすることができます。

```
$sudo yum update
$sudo yum install ruby
$sudo yum install wget
$cd /home/ec2-user
$wget https://aws-codedeploy-us-east-1.s3.amazonaws.com/latest/install
$chmod +x ./install
$sudo ./install auto
```

## EC2インスタンスのロールを作成
AWSサービスのエンティティを選択後、EC2サービスを選択します
具体的な手順については、[こちら](https://docs.aws.amazon.com/ja_jp/codedeploy/latest/userguide/getting-started-create-iam-instance-profile.html)に書かれています。

<img width="1025" alt="ec2role.png" src="https://qiita-image-store.s3.amazonaws.com/0/191919/513eecf1-f776-6897-a3b9-db0d981863b2.png">

手順通り、ポリシーをJSONで作成します。

```
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "s3:Get*",
                "s3:List*"
            ],
            "Resource": [
                "arn:aws:s3:::codedeploy-bucket/*",
                "arn:aws:s3:::aws-codedeploy-us-east-2/*",
                "arn:aws:s3:::aws-codedeploy-us-east-1/*",
                "arn:aws:s3:::aws-codedeploy-us-west-1/*",
                "arn:aws:s3:::aws-codedeploy-us-west-2/*",
                "arn:aws:s3:::aws-codedeploy-ca-central-1/*",
                "arn:aws:s3:::aws-codedeploy-eu-west-1/*",
                "arn:aws:s3:::aws-codedeploy-eu-west-2/*",
                "arn:aws:s3:::aws-codedeploy-eu-west-3/*",
                "arn:aws:s3:::aws-codedeploy-eu-central-1/*",
                "arn:aws:s3:::aws-codedeploy-ap-northeast-1/*",
                "arn:aws:s3:::aws-codedeploy-ap-northeast-2/*",
                "arn:aws:s3:::aws-codedeploy-ap-southeast-1/*",
                "arn:aws:s3:::aws-codedeploy-ap-southeast-2/*",
                "arn:aws:s3:::aws-codedeploy-ap-south-1/*",
                "arn:aws:s3:::aws-codedeploy-sa-east-1/*"
            ]
        }
    ]
}
```

このポリシーは、CodeDeploy-EC2-PermissionsAPIという名前で作成しました。
続いてロールの作成に移ります。
<img width="1019" alt="ec2role2.png" src="https://qiita-image-store.s3.amazonaws.com/0/191919/630eccab-b646-8be5-a8b8-c7cb3cf824a6.png">

<img width="1053" alt="ec2role3.png" src="https://qiita-image-store.s3.amazonaws.com/0/191919/ff48513e-b18d-cc2e-83f2-ab6a750a94ec.png">

このロールは、CodeDeploy-EC2-Instance-Profile-APIという名前で作成しました。

## 作成したCodeDeployのロールをEC2に割り当てる

インスタンスを選択し、アクション > インスタンスの設定から、IAMロールの割り当て/置換を選択します。

<img width="1062" alt="wariate.png" src="https://qiita-image-store.s3.amazonaws.com/0/191919/ccbd4b35-affe-71cb-cf4c-a2af51b79ce7.png">

ここで、[ロールを後からアタッチしたEC2の場合、CodeDeployに失敗することがある](https://qiita.com/futa/items/1e2d6f7abbc52f17ad5e)ことから、codedeploy-agentの再起動をかけておくと良いです。

```
$ sudo service codedeploy-agent restart
```

# CodeDeployの設定
AWS側の設定としては最後に、アプリケーションの作成を行います。
<img width="789" alt="スクリーンショット 2018-12-12 16.28.07.png" src="https://qiita-image-store.s3.amazonaws.com/0/191919/e07ef0bc-9824-bf3a-5cf4-b828e7beb236.png">

デプロイグループの作成を行います。
サービスロールについては先ほど作成したCodeDeployのロールを指定します。
環境設定についても、先ほどEC2に設定したタグを指定します。
<img width="753" alt="deploygroup.png" src="https://qiita-image-store.s3.amazonaws.com/0/191919/1a01d8b5-1c50-44a6-1a78-6cd57d3057ff.png">

<img width="743" alt="env.png" src="https://qiita-image-store.s3.amazonaws.com/0/191919/75fd8421-a97a-98ee-10f2-fe182b86ad3a.png">

今回、デプロイ設定はCodeDeployDefault.OneAtATimeに設定しました。
<img width="722" alt="スクリーンショット 2018-12-12 16.53.25.png" src="https://qiita-image-store.s3.amazonaws.com/0/191919/eeb75d07-3f1f-d86a-d7f0-78614131e0ce.png">


# Bitbucket Pipelinesの設定
前提条件として、Bitbucketにリポジトリがある状態としています。

## Pipelinesの有効化
リポジトリの設定 > PipelinesのSettingsから、Enable Piplinesのボタンを押すだけで、簡単に有効化できました。
![piplinesetting.png](https://qiita-image-store.s3.amazonaws.com/0/191919/280f56da-056c-6cd4-b8a3-3ad532bbcc30.png)

## 環境変数の設定
続いて環境変数の設定を行います。
リポジトリの設定 > PipelinesのRepositoly variblesから、以下の項目を設定します。
この環境変数については、次の手順で示すスクリプト内で利用されます。
なお、AWS_ACCESS_KEY_IDとAWS_SECRET_ACCESS_KEYは、デプロイ用のユーザーのものを設定します。

- AWS_SECRET_ACCESS_KEY
- AWS_ACCESS_KEY_ID
- AWS_DEFAULT_REGION
- APPLICATION_NAME
- DEPLOYMENT_CONFIG
- DEPLOYMENT_GROUP_NAME
- S3_BUCKET

<img width="1257" alt="envsetting.png" src="https://qiita-image-store.s3.amazonaws.com/0/191919/cd8f297d-2fc8-c7b1-79a9-4e6e4e063d51.png">

## CodeDeployをトリガーするパイプラインの構築
ここでは、[AWS LABで用意されているサンプルファイル](https://bitbucket.org/awslabs/aws-codedeploy-bitbucket-pipelines-python/src/master/)を利用します。

特に、bitbucket-pipelines.ymlから呼ばれるcodedeploy_deploy.pyについては、BitbucketのリビジョンをAWS S3に載せ、CodeDeployにデプロイを実行させる役割を担っています。
appspec.yml同様、これらのファイルはlocalプロジェクトのルートディレクトリに配置するようにします。

CodeDeployではデプロイグループのリビジョンを監視するため、初めてデプロイするファイルが既にデプロイ先にある場合、上書きできないようになっており、デプロイが失敗してしまうので注意が必要です。

### 各ファイルの修正
◼︎ bitbucket-pipelines.yml

- branchesがmasterを向いているので、必要に応じて修正が必要です。
- 具体的な書き方については、[こちら](https://ja.confluence.atlassian.com/bitbucket/configure-bitbucket-pipelines-yml-792298910.html)にまとまっています。
- また、[zipコマンド](https://bitbucket.org/awslabs/aws-codedeploy-bitbucket-pipelines-python/src/73b7c31b0a72a038ea0a9b46e457392c45ce76da/bitbucket-pipelines.yml#lines-11)が隠しファイルを対象外としているため、必要であれば`- zip -r /tmp/artifact.zip .`に修正する必要があります。

◼︎ appspec.ymlおよび各シェルファイル

- 本記事では省略しますが、[こちら](https://dev.classmethod.jp/cloud/aws/code-deploy-appspec/)の記事を参考に修正しました。

# おわり
上手く設定ができて入れば、エラーなくデプロイができるはずです。
エラーが出た場合はPiplinesまたは　AWSのCodeDeployのログから原因を突き止めます。

![fin.png](https://qiita-image-store.s3.amazonaws.com/0/191919/8ce467b7-9b4e-0fe9-6aad-648f9b69b6b5.png)

今回はBitbucket上の指定したbranchに更新があればpiplineが動き、AWS上のEC2へ自動デプロイを行う方法をまとめました。

一方、手動でボタン一つ手間はあるもののAWS CodeDeploy for Bitbucketを利用し、比較的簡単に自動デプロイを行う方法も見つけましたので共有します。

- [BitbucketとCodeDeployの連携を試してみた](https://dev.classmethod.jp/cloud/aws/codedeploy-with-bitbucket/)


# 参考記事

- [Bitbucket Pipelines で AWS CodeDeploy する](https://community.atlassian.com/t5/Bitbucket-articles/Bitbucket-Pipelines-%E3%81%A7-AWS-CodeDeploy-%E3%81%99%E3%82%8B/ba-p/620423)

- [Deploy to EC2 with AWS CodeDeploy from Bitbucket Pipelines](https://hackernoon.com/deploy-to-ec2-with-aws-codedeploy-from-bitbucket-pipelines-4f403e96d50c)

- [CodeDeploy Agentから知るCodeDeployの処理の流れ](https://dev.classmethod.jp/cloud/aws/codedeploy-deploy-process/)

- [AWS CodeDeploy の AppSpec を読み解く](https://dev.classmethod.jp/cloud/aws/code-deploy-appspec/)

- [AWS CodeDeploy を使って Rails アプリケーションをデプロイしてみた](https://dev.classmethod.jp/cloud/aws/codedeploy-ruby-on-rails/#toc-appspec-)