貧乏による貧乏のためのECS自動デプロイ戦略


#　はじめに

私は現役の貧乏大学生です。しかし、どうしても個人開発のアプリを稼働させているECSを手軽に更新できるようにCodePiplineを用いて自動デプロイを構築していきます。

＊<strong>今回はデプロイ時に古いコンテナを一時停止させて新しいコンテナを立ち上げるという方法を用いています。ダウンタイムが発生するのよろしくないので個人開発したいけどお金がない人向けです。ロードバランサを使えるほどのお金持ちの方はBlue/Greenデプロイをオススメします。</strong>

https://docs.aws.amazon.com/ja_jp/AmazonECS/latest/userguide/deployment-type-ecs.html

https://docs.aws.amazon.com/ja_jp/AmazonECS/latest/userguide/deployment-type-bluegreen.html


#　サービスの変更

##　ポートが既に使われている

instance xxxxxxxxxxxxxxxxxxxxxxxxx is already using a port required by your task. For more information, see the Troubleshooting section. といったエラーが出ます。
これは古いコンテナ起動中に新しいコンテナが立ち上がろうとしたが同じポートが既に使われているからです。これを防ぐにはサービスの最小ヘルス率と最大率を以下のようにしましょう最小ヘルス率が0でダウンタイムを許してあげると大丈夫です。

![スクリーンショット 2021-12-16 10.44.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1295942/490de441-5610-9fed-291d-4d8a84d289f1.png)

#　CodePiplineの作成

CodePiplineは主に3つのステージで成り立っており、GitHubの変更を検知するソースステージ。Dockerイメージを作成するビルドステージ。ECSにデプロイするデプロイステージがあります。では、パイプラインを以下のように作成します。

![スクリーンショット 2021-12-15 18.51.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1295942/17fe8fa6-b737-731e-72e6-ae37bd3822b9.png)

##　ソースステージ

ソースステージではCodeCommitを使うのが良いと思いますが手軽にGitHubと連携していきます。

![スクリーンショット 2021-12-16 10.54.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1295942/36522491-efdb-6297-fc18-189ddb16050f.png)

「GitHubに接続する」をクリックしてGitHubと連携しましょう。

![スクリーンショット 2021-12-16 11.00.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1295942/88a676ac-c040-525f-8287-66927b272ec5.png)


連携できたらトリガーとするリポジトリとそのブランチを選択します。

![スクリーンショット 2021-12-16 10.57.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1295942/024e8867-0cd6-e2a3-5d03-aa0119ab533a.png)


##　ビルドステージ

ビルドステージではCodeBuildを用いてDockerイメージを構築し、イメージをECRにプッシュします。

「プロジェクトを作成する」をクリックします。クリックすると別タブが開きビルドプロジェクトの作成になります。

![スクリーンショット 2021-12-16 11.03.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1295942/95471cc2-0ed9-8a42-f06d-2a2400a3cc54.png)

さまざまな項目が出てくると思いますが「環境」という項目だけ設定して他の項目はデフォルトでOKです。ビルドする環境を指定します。以下のように選択してください。設置できたら「CodePiplineに進む」をクリックしてください。

![スクリーンショット 2021-12-16 11.07.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1295942/a154f5c4-980f-3d06-3ad7-30066683707c.png)

##　デプロイステージ

デプロイステージではCodeDeployを用いてタスク定義を更新して新しくサービスを作成します。

![スクリーンショット 2021-12-16 11.14.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1295942/5276d3c0-29ca-9351-df88-9f6da1df1f75.png)

既に作成しているECSのクラスターとサービスを選択します。これでCodePiplineの作成は完了です。

![スクリーンショット 2021-12-16 11.16.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1295942/5ce4c6bf-4c3f-a5c9-f4db-8f61d467c220.png)

#　その他設定

## buildspec.ymlの記述

CodeBuild時にどのようにビルドを行うのか指定するためのファイルです。以下のように記述してプロジェクトの配下にbuildspec.ymlを置いておきましょう。

```yaml:buildspec.yml
# バージョン
version: 0.2

# 環境変数
env:
    variables:
        AWS_DEFAULT_REGION: 'ap-northeast-1'
        IMAGE_NAME: 'onlinecode_app'
        CONTAINER_NAME: 'code'

# ビルドの各段階で CodeBuild が実行するコマンドを表します
phases:
    pre_build:
        commands:
            # ECRにログインする
            - $(aws ecr get-login --no-include-email --region ${AWS_DEFAULT_REGION})
            # AWSのアカウントIDを取得
            - AWS_ACCOUNT_ID=$(aws sts get-caller-identity --query 'Account' --output text)
            # ECRのリポジトリURI
            - REPOSITORY_URI=${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_DEFAULT_REGION}.amazonaws.com/${IMAGE_NAME}
            # イメージタグ
            - IMAGE_TAG=${CODEBUILD_RESOLVED_SOURCE_VERSION}

    build:
        commands:
            # $IMAGE_TAGがTag名になる
            - docker build -t $REPOSITORY_URI:$IMAGE_TAG .
    post_build:
        commands:
            - docker push $REPOSITORY_URI:$IMAGE_TAG
            # imagedefinitions.jsonに出力する
            - printf '[{"name":"code","imageUri":"%s"}]' $REPOSITORY_URI:$IMAGE_TAG > imagedefinitions.json

# CodeBuildがビルド出力を見つけることができる場所に関する情報
artifacts:
    files: imagedefinitions.json
```

## AmazonEC2ContainerRegistryPowerUserのアタッチ

CodeBuild時に新しい環境を立ち上げbuildspec.ymlをもとにDockerイメージのビルドを行なって行くのですが生成したDockerイメージをECRにPushしなければなりません。そのためAmazonEC2ContainerRegistryPowerUserをアタッチしてCodeBuildがECRにログインする権限を付与します。

ブロジェクト詳細でビルドに利用しているサービスロールをクリック

![スクリーンショット 2021-12-11 23.46.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1295942/9bb657da-6fc9-50cd-5e99-5c5825516036.png)

「ポリシーをアタッチします」をクリック

![スクリーンショット 2021-12-16 2.15.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1295942/8f67b5ed-dc61-9927-41f8-e6a255640cb8.png)

「AmazonEC2ContainerRegistryPowerUser」をアタッチします。完了したら権限を付与することに成功です。

![スクリーンショット 2021-12-16 2.16.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1295942/91b6d096-1e63-8d42-fc62-75d3288dd254.png)

そしてmainブランチにマージしてみてください。以下のようになればデプロイ成功です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1295942/ae49128e-99ba-ae76-a2c9-4858ccdadfda.png)

#　参考文献

https://docs.aws.amazon.com/ja_jp/codepipeline/latest/userguide/ecs-cd-pipeline.html

https://docs.aws.amazon.com/ja_jp/codepipeline/latest/userguide/file-reference.html

https://docs.aws.amazon.com/ja_jp/codebuild/latest/userguide/build-spec-ref.html

https://qiita.com/shizen-shin/items/7ff485019e23cf3b9f6e

https://dev.classmethod.jp/articles/ecs-deploy-all/