Fargateでの本番と開発環境のCI/CD構成

# はじめに
FargateでwordPressの本番環境を構築後、開発環境を作成する上で、Cl/CD構成について試行錯誤したため、まとめます。

# FargateでWordPressの構築方法
こちらの記事を順番どおり行うと、本番環境として構築できます。

https://qiita.com/holdout0521/items/bde67b8334f3362c8009

https://qiita.com/holdout0521/items/2a199770cf14b6289bca

https://qiita.com/holdout0521/items/b83f931e16e680e46391

https://qiita.com/holdout0521/items/3aeeb9c9f9e663778ed7

# 本番と開発環境のCI/CDの構成の要件
1. アプリケーションの品質を担保する観点から、開発環境でビルド・デプロイテストを行い、問題ないことを確認して、本番環境にデプロイしたい
→そのために、各環境にCodePipelineを構築する
　　

1. 開発効率の点から本番と開発環境のソースコードは同じにしたい
→そのためには、CodeBuildの環境変数や、ECSのタスク定義の環境変数で、環境ごとの差異を修正する

https://www.hacknotes.jp/blog/codebuild-setting-environment-variable/

https://dev.classmethod.jp/articles/codebuild_envset_pipeline/

# Fargateの本番と開発環境のCI/CDの構成図

![スクリーンショット 2022-01-30 12.43.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/988747/8999c868-5ecf-2320-987d-260b27eafc8b.png)


### 開発のCI/CD流れ

1. 開発ブランチ(develop)の ソースコードを修正し、CodeCommitにプッシュすると、開発環境用のCodePipelineが起動します。
- developの`buildspec.yml`ファイルのコードを元に、CodeBuildでDockerイメージを作成します。
- CodeDeploy(ECSタイプ)で、タスク定義の環境変数に開発用のRDSエンドポイントを指定し、タスクをデプロイする

### 本番のCI/CD流れ

1. デプロイされた開発環境のアプリケーションを確認し、問題ないことを確認する
- CodeCommitのdevelopブランチからmainにマージすると、本番用のCodePipelineが起動します。
- `buildspec.yml`ファイルが同じため、開発環境と同じイメージをECRに保存する。
- CodeDeploy(ECSタイプ)で、タスク定義の環境変数に本番用のRDSエンドポイントを指定し、タスクをデプロイする

### 本番と開発環境の差異
- CodeCommitの開発と本番環境は、同じリポジトリですが、開発と本番でブランチでわけています。（CodeCommitでなく、GitHubでも可）
    - buildspec.ymlファイルも共通で、同じイメージをECRから取得します。
- CodeBuild、CodeDeploy、RDSは、各環境ごとに作成します。
- ECSのクラスターは、各環境ごとに作成します
- ALBとターゲットグループは、各環境ごとに作成します。`本番と開発で同じALBを使用することはできませんでした。`

# 作業の流れ

1. 資産を本番と開発環境で同じにする
1. 開発環境用のcodebuildとcodepipelineとcodeDeploy(ECS)を作成


# 資産を本番と開発環境で同じにする
本番環境は、先程記載した記事通りにすると作成できます。
開発環境のソースコードは、本番環境のソースコードと差異がないようにする必要があります。
私の場合、WordPressだと以下のファイルを修正しました。

## 資産
FargateでWordPressを構築する際のソースコードは、こちらです。

```
.
├── Dockerfile
├── buildspec.yml
├── docker-compose.yml
├── html
├── php.ini
│   ├── wp-config.php
│   └── wp-content
│       ├── plugins
│       └── themes
└── imagedefinitions.json

特に指定がなければ、コンテナ内の/var/www/html配下に設置されます。
詳細は、Dockerfile,docker-compose.ymlに記載

リポジトリとコンテナ内のディレクトリ構造
	html         /var/www/html
	php.ini      /usr/local/etc/php/php.ini

CodeBuildで必要なファイル
	buildspec.yml
	imagedefinitions.json

Dockerで必要なファイル
	Dockerfile
	docker-compose.yml
```



# 開発環境用のcodebuildとcodepipelineとcodeDeploy(ECS)を作成
参考記事通りに作成します。

### ECS作成時、注意点①
Deploy時、本番環境と同じイメージを取得するため、タスク定義は、同じにします。
![スクリーンショット 2022-01-08 15.37.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/988747/6bd74547-e3f2-6d54-2ea2-d500aa1c9367.png)

### ECS作成時、注意点②
ECSのクラスターは、各環境ごとに作成します。

### ECS作成時、注意点③
ECSサービスは、新規でロードバランサーとターゲットグループを作成します。
本番と開発環境で同じロードバランサーは、使用できませんでした。


作成後、検証環境にpushすると、検証環境としてデプロイされます。
developブランチをmainにマージすると、本番環境としてデプロイされます！

# Fargateの本番と開発環境のCI/CDの構成図 環境ごとにイメージタグを分けるパターン
環境ごとにイメージタグを分けるパターンも紹介します。この場合、latestタグではなく、`prodタグ`と`devタグ`が必要になります。

![スクリーンショット 2022-01-30 12.21.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/988747/b64446dd-7278-68f7-7bbd-2367a89e8f28.png)

修正は3つ必要です。

1. buildspec.ymlにタグ付け
1. CodeBuildステージに環境変数を入れる
- ECSタスク定義のコンテナイメージのタグを修正


## buildspec.ymlにタグ付け

```yml:buildspec.yml
version: 0.2

env:
  #SSM parameter-store
  parameter-store:
    DOCKER_USER: dockerhub-user
    DOCKER_TOKEN: dockerhub-docker-token

phases:
  pre_build:
    commands:
      - echo Logging in to Amazon ECR...
      - aws ecr get-login-password --region ap-northeast-1 | docker login --username AWS --password-stdin ************.dkr.ecr.ap-northeast-1.amazonaws.com
      - echo $DOCKER_TOKEN | docker login -u $DOCKER_USER --password-stdin
  build:
    commands:
      - echo Build started on `date`
      - echo Building the Docker image...
      - docker build -t イメージ名:$IMAGE_TAG .
      - docker tag イメージ名:$IMAGE_TAG ************.dkr.ecr.ap-northeast-1.amazonaws.com/イメージ名:$IMAGE_TAG
  post_build:
    commands:
      - echo Pushing the Docker image...
      - docker push ************.dkr.ecr.ap-northeast-1.amazonaws.com/イメージ名:$IMAGE_TAG
      - echo Writing image definitions file...
      - printf '[{"name":"container name","imageUri":"%s"}]' ************dkr.ecr.us-east-1.amazonaws.com/イメージ名:$IMAGE_TAG > imagedefinitions.json
artifacts:
  files:
    - imagedefinitions.json
```

`$IMAGE_TAG`に`prod`タグや`dev`タグが入ります。

https://docs.aws.amazon.com/ja_jp/codebuild/latest/userguide/sample-docker.html#sample-docker-files

## CodeBuildステージに環境変数を入れる
buildspec.ymlに`$IMAGE_TAG`を入れましたので、各環境ごとのCodeBuildステージに環境変数として、`prod`と`dev`を入れます。

|名前  |値|入力|
|---|---|---|
| IMAGE_TAG	 | prod |プレーンテキスト|

![スクリーンショット 2022-01-30 12.35.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/988747/116973f4-9f84-6a59-0de0-a899d22eb818.png)

## ECSタスク定義のコンテナイメージのタグを修正
タスク定義のコンテナのイメージタグは、`:latest`になっているため、環境ごとに`prod`と`dev`に修正します。

タスク定義のコンテナのイメージを修正すると、最新のタスク定義が作成されます。
サービスのタスク定義のリビジョンを最新にしましょう。
`prod`と`dev`タグのイメージが作成できていませんので、強制デプロイはしないでください。

それでは、devブランチにプッシュすると、`dev`タグのイメージが作成され、問題なくデプロイされたことを確認し、mainにマージしましょう。

ECR内に、`prod`と`dev`それぞれタグ付けされたイメージが保存されたことが確認できます。

![スクリーンショット 2022-01-18 11.51.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/988747/64145240-e38e-b86a-def7-30a2d35b16bb.png)

# 参考

https://dev.classmethod.jp/articles/codebuild_envset_pipeline/#toc-6