🐳

【AWS】CodePipeline+ECSでコンテナアプリケーションのCI/CDしてみた

2023/09/16に公開

概要

会社で aws を触ることになり、基本から学んでいこうと思ったため備忘録として記事を書き始めました。
今回は CodePipeline と ECS に関する概要説明の後 これら を使用して自分の PC 内の Next アプリケーションを コンテナで Web 上に公開するまでの過程を CI/CD 化してみます 🌀
もし理解が違うよというところ等ありましたら優しく教えて頂けると幸いです 🙇‍♀️

CodePipeline とは

公式ドキュメント引用。
CodePipeline とは、最近流行りの CI/CD を実現するためのサービスです。
CI/CD とは書いたコードをテストして本番環境にデプロイする過程を自動化することを指します。
CodePipeline での CI/CD の一例を挙げると、旧来

  • 自分の PC でコードを書く
  • そのコードを手動でテスト
  • 本番環境へデプロイする

といったことを行っていたところ、この過程を CI/CD 化することで

  • 自分の PC でコードを書きリモートリポジトリへ push
  • リモートリポジトリのコードが push で変更されたことをトリガーに後続過程を全て自動で行う

といったことを実現します。

CodePipeline での CI/CD の流れ

CodePipeline での CI/CD の流れの一例を以下で図示しています。

黒い連番の数字で書かれているのは CI/CD の手順です。
以下手順が各数字と対応します。

  1. 自分の PC で書いたコードを CodeCommit 上のリポジトリに push
  2. CodePipeline が CodeCommit のリポジトリの変更を検知して S3 にリポジトリの zip ファイルを出力し、そのファイルから CodeBuild でコードのユニットテスト、ビルド等を行う
  3. ビルド終了後、CodePipeline が S3 にビルドさで出力されたリソースの情報を記載した zip ファイルを出力し、そのファイルから CodeDeploy での本番用サーバーへのデプロイを開始する
  4. CodeDeploy が本番用サーバーにビルドされたコードをデプロイする

CodeCommit、CodeBuild、CodeDeploy は AWS で提供される CI/CD を行う時に使用するサービスです。
上記手順で説明される役割を果たし、CodePipeline で CI/CD を構築する時に挙動を設定できる様になっています。

ECS とは

公式ドキュメント引用。
ECS とは、Amazon Elastic Container Service の略語です。
コンテナ化したアプリケーションを立ち上げるため EC2 や Fargate 上にデプロイしたり、立ち上がっているコンテナの設定を変更・削除したり、立ち上げるコンテナの数・配置を自動で配分してくれたりといった機能を提供しています。
こういったコンテナのデプロイ・管理・スケールの自動化を行うことをコンテナオーケストレーションと呼ぶため、ECS はコンテナオーケストレーションツールと言えます。

ECS での コンテナアプリケーション公開までの流れ

ECS でコンテナアプリケーションを公開するまでの流れの一例を以下で図示しています。

黒い連番の数字で書かれているのは公開の手順です。
以下手順が各数字と対応します。

  1. 自分の PC で書いたコードを コンテナの元となるイメージにして ECR に保存
    ECR はイメージの保存サービスです。
  2. タスク定義ファイルが保存された ECR のイメージを参照する
    タスク定義ファイルはコンテナアプリケーションを立ち上げる元となる設計書です。
  3. サービスがタスク定義ファイルを参照する
    タスク定義ファイルから立ち上がるコンテナアプリケーションをタスクと呼びます。
    サービスは一つのタスクが停止したとしても別タスクを立ち上げることで実行されているタスクの数を維持します。
    サービスは複数設定することができ、クラスターというグループで管理されます。
  4. サービスが Fargate 上にタスクを立ち上げる
    Fargate は EC2 とは異なり一つ一つの仮想マシンのスケーリング設定やネットワーク設定を行わずにコンテナを立ち上げられるサービスです。
  5. インターネットから立ち上げたタスクつまりコンテナアプリケーションが閲覧される

ECR、タスク、サービス、Fargate は ECS でコンテナアプリケーションの公開を行う際に必要になるサービスや概念です。
上記手順で説明される役割を果たし、ECS で コンテナアプリケーションの公開をする際に一部挙動を設定できる様になっています。

CodePipeline + ECS で Next アプリケーションを Web 上に公開してみる

では、Next アプリケーションをコンテナ化して ECS で Web 上に公開しつつその過程を CodePipeline で CI/CD 化するハンズオンを行ってみます。
このハンズオンでは

  • Next アプリケーション公開までの過程を CI/CD 化することで自分の PC でコードを書き換えて git での push を行うだけで Web 上へのアプリケーション公開が可能になる
  • コンテナ化してアプリケーションを立ち上げることでユーザー数に応じて複数の Next アプリケーションを素早く立ち上げるといったことが簡単にできる

といったことができるので一緒にやってみてもらえると嬉しいです 😌
ここでは、以下の様な構成の パイプライン[1]を組んでみます。

黒い連番の数字で書かれているのは CodePipeline で ECS でのコンテナアプリケーションを公開する手順[2]です。
以下手順が各数字と対応します。

  1. 自分の PC で作成した Next アプリケーションを CodeCommit 上のリポジトリに push
  2. CodePipeline が CodeCommit のリポジトリの変更を検知して S3 にリポジトリの zip ファイルを出力する
    その後、CodeBuild が zip 化されたリポジトリ内の buildspec.yml ファイルをもとに Next アプリケーションのイメージ化を行う
  3. CodeBuild が作成された Next アプリケーションのイメージを ECR に保存し、そのイメージのタグ付き URL を json ファイルに記載して zip 化し S3 に出力する
  4. タスク定義ファイルが ECR の指定した URI と json ファイルのタグ付き URL を元にコンテナ化するイメージを参照する
  5. サービスがイメージとタスク定義ファイルを参照する
  6. サービスがタスクを Fargate 上に複数立ち上げる
  7. インターネットから立ち上げたタスクつまりコンテナアプリケーション化された Next アプリケーションが閲覧できる

では、上記手順を以下から行っていきます。

  1. Fargate がコンテナを立ち上げるために必要な VPC 他ネットワークリソースを作成

まず、最終的にコンテナが立ち上がる環境を作成します。
マネジメントコンソールで VPC 画面を表示し、VPC を作成ボタンを押下してください。

VPC を作成画面で以下の様に入力して VPC を作成ボタンを押下してください。

次に VPC 内のインスタンスに付与するセキュリティグループを作成します。
VPC 画面でセキュリティ > セキュリティグループ画面からセキュリティグループを作成ボタンを押下します。

セキュリグループを作成画面で以下の様に入力してセキュリティグループを作成ボタンを押下します。

  1. ECR でイメージを保存するリポジトリを作成

マネジメントコンソールで ECR と検索し検索結果のリポジトリを押下してください。

リポジトリ画面でリポジトリを作成を押下してください。

リポジトリを作成画面で以下項目を入力してリポジトリを作成ボタンを押下してください。

  1. ECS 他コンテナ公開用リソース作成

タスクが ECR に保存されたイメージを扱えるようにタスクに定義するロールを作成します。
マネジメントコンソールで IAM を表示し、ロール画面からロールを作成ボタンを押下してください。

信頼されたエンティティを選択で以下項目を入力して次へボタンを押下してください。

許可を追加でポリシーを選択せず、次へボタンを押下してください。
名前、確認、および作成画面で以下項目を入力してロールを作成ボタンを押下してください。

同じように以下設定値で next-container-execute-task-role を作成してください。

項目名
ロール名 next-container-execute-task-role
信頼ポリシー 上と同じ
許可ポリシー AmazonECSTaskExecutionRolePolicy

ECS でタスクを作成します。
マネジメントコンソールで ECS 画面を表示し、タスク定義から新しいタスク定義の作成 > JSON を使用した新しいタスク定義の作成ボタンを押下してください。

タスクを以下の様に定義して作成ボタンを押下し、タスク定義を作成してください。

以下項目には指定した値を入力してください。

項目名
image ECR のリポジトリ next-container の URI
taskRoleArn IAM で作成した next-container-task-role の ARN
executionRoleArn next-container-task-execute-role の ARN

クラスター 画面を表示し、クラスターの作成ボタンを押下してください。

クラスターの作成画面で以下項目を入力し、作成ボタンを押下してください。

クラスター作成後、作成されたクラスターを押下しサービスの作成ボタンを押下してください。

作成画面で以下項目を入力し、作成ボタンを押下後、サービスを立ち上げてください。
CodePipeline でのパイプライン構築を行なった後実際にサービス内でタスクを立ち上げます。

  1. Next アプリケーションの作成、CodeCommit へ push する

パイプラインで必要になる CodeCommit 内のリポジトリを作成してアプリケーションを push します。
最初に、Next アプリケーションを作成して CodeCommit へ push します。
CodeCommit で以下記事のCodeCommitを使ってみるの章の手順CodeCommitからHTTPSのクローンのクローン URL をクリップボードにコピーするところまでを行ってください。
コピーしたクローン URL はメモしておき、まだクローンはしないでください。
途中でリポジトリを作成しますが、設定するリポジトリ名はnext-containerにしてください。

https://www.hacknotes.jp/blog/codecommit-guide/#codecommitを使ってみる

以下コマンド実行して Next アプリケーションを作成してください。
途中の質問には以下の様に答えてください。

$ npx create-next-app@13
...
Need to install the following packages:
  create-next-app
Ok to proceed? (y) y
✔ What is your project named? … next-container
✔ Would you like to use TypeScript with this project? … Yes
✔ Would you like to use ESLint with this project? … Yes
✔ Would you like to use Tailwind CSS with this project? … No
✔ Would you like to use `src/` directory with this project? … Yes
✔ Would you like to use experimental `app/` directory with this project? … No
✔ What import alias would you like configured? … @/*
...

アプリケーションが作成されるので、next-container のルートディレクトリにbuildspec.ymlファイルを配置し、以下の様に記載してください。

version: 0.2

phases:
  pre_build:
    commands:
      - aws ecr get-login-password --region $AWS_DEFAULT_REGION | docker login --username AWS --password-stdin [リポジトリURLのリポジトリ名を排除した文字列]
      - REPOSITORY_URI=[リポジトリURI]
      - COMMIT_HASH=$(echo $CODEBUILD_RESOLVED_SOURCE_VERSION | cut -c 1-7)
      - IMAGE_TAG=${COMMIT_HASH:=latest}
  build:
    commands:
      - docker build -t $REPOSITORY_URI:latest .
      - docker tag $REPOSITORY_URI:latest $REPOSITORY_URI:$IMAGE_TAG
  post_build:
    commands:
      - docker push $REPOSITORY_URI:latest
      - docker push $REPOSITORY_URI:$IMAGE_TAG
      - printf '[{"name":"next-container-task","imageUri":"%s"}]' $REPOSITORY_URI:latest > imagedefinitions.json
artifacts:
  files: imagedefinitions.json

このファイルが後に CodeBuild で読み込まれ、記載したコマンドが実行されます。
Docker で Next アプリケーションをイメージ化するために必要なDockerfileもルートディレクトリ配下に配置して、下の様に記載してください。

FROM node:latest

WORKDIR /usr/src

COPY . .

RUN npm install

RUN npm run build

CMD ["npm", "start"]

また、package.json の start コマンドも以下の様に修正してください。

"scripts": {
  "dev": "next dev",
  "build": "next build",
  "start": "next start -p 80",
  "lint": "next lint"
}

以下コマンドで CodeCommit 上のリポジトリにコードを push してください。
push 時にユーザー名とパスワードを求められた場合、上記記事を参考に入力してください。

$ git init
$ git remote add origin [next-containerのクローンURL]
$ git add .
$ git commit -m "Nextアプリケーション作成"
$ git push origin main
  1. CodePipeline でパイプラインを作成する

いよいよ CI/CD パイプラインを構成します。
マネジメントコンソールで CodePipeline 画面を表示し、パイプラインを作成するボタンを押下してください。

パイプラインの設定を選択するで以下項目を入力して次にボタンを押下してください。

ソースステージを追加するで以下項目を入力して次にボタンを押下してください。

ビルドステージを追加するで以下項目を入力してビルドプロジェクトを作成するボタンを押下してプロジェクトを作成してください。

ビルドプロジェクトを作成するで以下項目を入力して CodePipeline に進むを押下して先ほどの画面に戻り、次にボタンを押下してください。

デプロイステージを追加するで以下項目を入力して次へボタンを押下してください。

最後にパイプラインを作成するボタンを押下してパイプラインを作成してください。

パイプラインが作成されたら、CodeBuild に付与されているロールに ECR へのアクセス権限を付与します。

マネジメントコンソールで IAM のロール 画面を表示し、codebuild-next-container-build-serviceroleを押下してください。

許可を追加 > ポリシーをアタッチを押下してください。

AmazonEC2ContainerRegistryPowerUser を選択し、許可の追加ボタンを押下してください。

最後に、パイプラインが完成したので ECS でサービスのタスクを立ち上げます。
ECS の画面 > クラスター > NextContainerCluster > サービス > next-container-service を開き、サービスを更新ボタンを押下してください。

必要なタスクを 1 に修正し、更新ボタンを押下してください。

これでサービスが立ち上がりました。

  1. パイプラインを動かしてみる

最後に自分の PC の Next アプリケーションに変更を加えてその変更が自動で公開されているコンテナアプリケーションに反映されるか確認してみます。
自分の PC の Next アプリケーションの src > pages > index.tsx にお腹すいたの文字列を追加してみます。

...
<h1>お腹すいた</h1>
<p>
  Get started by editing&nbsp;
  <code className={styles.code}>src/pages/index.tsx</code>
</p>
...

その後、以下コマンドで修正を CodeCommit のリポジトリに反映させます。

$ git add .
$ git commit -m "お腹すいた"
$ git push origin main

これで修正が反映されたはずです。
CodePipeline > パイプライン > next-container で開いたパイプラインが以下の様に全ての段階が成功していたら完璧です 🙆
最後の Deploy でもお腹すいたのコメントが付与されたコミットがデプロイされていることがわかります。

ECS 画面からクラスター > NextContainerCluster > サービス > next-container-service > タスクタブを押下し、タスクを押下します。

設定 > パブリック IP で立ち上がっているコンテナアプリケーションのパブリック IP アドレスを確認し、ブラウザで検索します。

この様にお腹すいたの文字が反映されたコンテナアプリケーションを Web 上で閲覧できるはずです。
こちらの画面が表示されたら成功です 👍

終わりに

ハンズオンお疲れ様でした。
次回は このパイプラインに CodeDeploy を組み込んで Blue/Green デプロイを行ってみようと思います。
他にも aws に関して 日々記事を書いているので、よかったら読んでみてください。
https://zenn.dev/alichan/articles/03dc627e490f4d
https://zenn.dev/alichan/articles/f1b3aabeb96158
ここまで読んでいただき本当にありがとうございます 🙇‍♀️

参照

https://docs.aws.amazon.com/AmazonECS/latest/developerguide/Welcome.html
https://docs.aws.amazon.com/ja_jp/codepipeline/latest/userguide/welcome.html

脚注
  1. パイプラインとは、CodePipeline で作成される CI/CD を行う過程のことを指します。 ↩︎

  2. このハンズオンでは一旦 CodePipeline を使用してコンテナアプリケーションを立ち上げることを目的としているため、CodeDeploy を使用した Blue/Green デプロイは行いません。よって、CodeDeploy は使用せず直接 ECS にデプロイを行なっています。近日中には Blue/Green デプロイの記事も書いてみたいなと思っています! ↩︎

Discussion