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


 はじめに

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

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

 サービスの変更

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

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

 CodePiplineの作成

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

 ソースステージ

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

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

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

 ビルドステージ

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

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

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

 デプロイステージ

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

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

 その他設定

buildspec.ymlの記述

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

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にログインする権限を付与します。

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

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

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

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

 参考文献