CodePipelineを使ってECSの自動デプロイを構築してみた

# はじめに
こんにちは。今回は、AWS CodePipeline を使って Amazon ECS に自動デプロイを構築する手順を紹介します。
手動でのデプロイ作業に煩わしさを感じていた方、CI/CDの導入に興味がある方に向けて、なるべくシンプルな構成でECSの自動デプロイ環境をお試しする手順になります。

## CodePipeline とは
そもそもAWSにはCI/CDを構成するための4つの主要サービスがあり、開発者の間ではこれらを **「Code4兄弟」** と呼ぶことがあります。

| サービス名        | 役割              |
| ------------ | --------------- |
| CodeCommit(2025年5月現在廃止済み)   | Gitリポジトリ（ソース管理） |
| CodeBuild    | ビルド処理           |
| CodeDeploy   | デプロイ処理          |
| CodePipeline | パイプライン管理        |

[CodePipeline](https://aws.amazon.com/jp/codepipeline/) はこの4兄弟の中の1つで、コードのビルド、テスト、デプロイといった一連の流れを自動化できるサービスです。
主に以下のような特徴を持っています：

* 複数のステージで構成されたパイプラインが定義できる
* GitHubやGitLabとの連携が簡単
* CodeBuildやECS、Lambdaなどとの統合がスムーズ

今回はCodePipelineのみを使って、変更があるたびにECSへ自動デプロイする仕組みを実現していきますが、
AWS上でCI/CDを構築する場合、これらのサービスを組み合わせるのが基本パターンなので、それぞれの役割を理解しておくと他の場面でも応用が利きます。

#  AWS構成
CloudShellを利用してECRに対してイメージをプッシュし、それをトリガーとしてCodePipelineを実行し、ECSへデプロイをする流れになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3799996/60ffba2e-7389-4912-833f-ec1cdef47c4e.png)

# 実際に構築していく
## 準備
### ECRの作成
アプリケーションのDockerイメージを格納するためのECRリポジトリを作成します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3799996/3162a593-ae88-4361-b055-953385a9a682.png)

### Dockerイメージのビルドとプッシュ(CloudShell)
私が以前担当したプロジェクトではGitLabパイプラインにECRへプッシュする仕組みを作りましたが、
簡易化のためCloudShellを利用していきます。
AWS CloudShellを使えば、ローカル環境を用意せずに、ブラウザ上で簡単にDocker操作が可能です。

#### フォルダ構成
多分これが一番簡単だと思います。
※フォルダ名をECRリポジトリ名と合わせておくと、後述のコマンドをそのまま使用できます。
```
codepipeline-sample
├── Dockerfile
└── index.html
```
* Dockerfile：Nginxをベースにした簡易Webサーバー用Dockerイメージ定義ファイル
* index.html：ブラウザに表示されるシンプルな静的ページ
#### Dockerfileの内容
```
# ベースイメージとしてNginxを使用
FROM nginx:alpine

# デフォルトのHTMLを削除
RUN rm -rf /usr/share/nginx/html/*

# カスタムHTMLをコピー
COPY index.html /usr/share/nginx/html/
```
#### index.htmlの内容
```html
<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <title>Hello from ECS!</title>
</head>
<body>
  <h1>Hello from ECS + CodePipeline!</h1>
</body>
</html>
```
CloudShellを開いて、ECRに表示されているコマンドを叩いていきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3799996/a3a3fd1a-8147-4664-8f01-c985f4273e3d.png)

### ECS(Fargate)環境の作成
#### ECSクラスター
起動タイプFargateでクラスターを作成します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3799996/3e4499b2-208d-41bd-9476-4c01833d3d2d.png)
#### タスク定義
コンテナ
利用するコンテナイメージを定義します。
それ以外の項目はそこまで意識しなくても大丈夫です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3799996/0cc2e9ac-1041-4a99-8465-e2298029ecb5.png)
#### ECSサービス
次にECSサービスを作成します。
ALBなどもここで作成することができますが、今回は直接ECSにアクセスするため不要です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3799996/b2fdfb4b-ece1-418b-9b74-024e77249608.png)

ここまでで準備完了です。
ECSタスクのIPアドレス(ECSのページから対象ECSタスクのパブリックIPから確認)にアクセスすると、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3799996/cb0c1dbe-3a3b-4c10-bae1-36260cbc6b75.png)
無事、ページが表示されました。

## 自動デプロイ構築
いよいよ自動デプロイを構築していきます。
### S3
まずはS3バケットを作成します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3799996/f78b5dee-58e9-47ef-ba2c-94c333935fb4.png)

次にパイプラインとコンテナを紐づけるための定義ファイルを作成します。
ECSサービスは、どのコンテナイメージを使用すべきかを明示的に受け取る必要があります。
そのため、imagedefinitions.json というJSON形式のファイルを使って、対象のイメージURIをパイプライン経由でECSに伝える必要があります。
#### imagedefinition.jsonの内容
```
[
    {
        "name":"sample",
        "imageUri":"{アカウントID}.dkr.ecr.ap-northeast-1.amazonaws.com/codepipeline-sample:latest"
    }
]
```
作成した定義ファイルをzip化し、先ほど作成したバケットにアップロードします。
これでS3側の準備は完了です。

### CodePipeline
まずはカテゴリーを選択します。
今回はカスタムパイプラインで作成していきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3799996/b28ed5c4-b63e-4515-b513-7f932338b350.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3799996/d5aba652-c79d-49dc-8bff-a82614e6356d.png)
ソースステージではトリガーとなるECRを選択していきます。
実際にトリガーを検知するEventBridgeも自動作成されるので、必ずチェックを付けるようにしてください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3799996/9c090597-83e4-4a94-947d-3765354cc688.png)
今回はビルドステージとテストステージは不要なのでスキップします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3799996/75e3f210-bf03-4749-ad81-eff946420836.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3799996/b6c6cb4b-45d7-403f-99cd-17819e5c1fe6.png)
デプロイステージでは、今までに構築したECSクラスター・サービス、イメージ定義ファイルを設定します。
ただし、今のままだとS3からイメージ定義ファイルを取得する設定になっていないので、この後設定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3799996/f8672e57-7cb7-4463-aaf3-592fb85a8b58.png)

以上でCodePipelineの作成が完了しました。
次に、作成したパイプラインを編集し、S3からイメージ定義ファイルを取得する設定を追加します。
ソースステージにアクションを追加し、以下の設定を行います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3799996/2af1c1b0-1092-4e0d-8176-2c1a1382ca42.png)
デプロイステージの入力アーティファクトも変更します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3799996/8a1c22e4-fd9c-47ca-8df0-4a3d15d341b8.png)

これで自動デプロイの準備は完了です。

# ECRにプッシュしてみる
```html
<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <title>Hello from ECS!</title>
</head>
<body>
  <h1>Hello from ECS + CodePipeline!</h1>
  <h1>自動デプロイ成功！</h1>
</body>
</html>
```

index.htmlを修正し、ECRにプッシュします。
すると、CodePipelineが作動するので処理完了まで待ちます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3799996/26832de8-e7ff-4bba-ad6f-b89395761966.png)
処理が完了し、ECSタスクのIPアドレスにアクセスすると、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3799996/a1deffe6-6eb9-49fb-b110-a1787a787638.png)
自動デプロイされ、静的ページの更新が確認できました。

# 最後に
今回は、CodePipelineを使ってAmazon ECSへ自動デプロイする環境を構築しました。CodeBuildやCodeDeployを使わず、あえてシンプルな構成にすることで、CI/CDの基本的な仕組みや流れをより明確に理解できたのではないでしょうか。
AWSのCodeシリーズ（通称：Code4兄弟）を組み合わせることで、複雑なCI/CDパイプラインも柔軟に設計できます。今回の構成はシンプルながら、実際の業務でも応用可能なベースになるはずです。
今後はビルドやテストステージの追加、GitHubとの連携、自動ロールバックなど、より高度な構成にもチャレンジしてみてください！