【AWS】CodePipelineを使用したCI/CD環境の作成

## 今回の意義・ゴール
・CI/CDの流れを理解する
→何となくで理解をしているが、はっきりと理解するために言葉の意味も交えながら記事にする。

・ローカルにあるDockerイメージをCICD環境を通じてECSに自動デプロイすることが今回のゴール

## 使用サービスおよび構成図
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3557022/46385468-8b4c-1287-c8ab-ab445afa0afb.png)

## 参考先
https://pages.awscloud.com/rs/112-TZM-766/images/AWS_CICD_ECS_Handson.pdf

## 使用サービス・環境
**【AWS】**
* CodeCommit
* CodePipeline
* CodeBulid
* CodeDeploy
* S3
* ECS
* ECR
* ALB
操作環境→vscode(AWS CLIインストール済み)

## 使用するファイル
**【CodeBulid】**
* bulidspec.yml　→ビルド処理の定義書

* Dockerfile　→Dockerを使用するための定義書

**【CodeDeploy】**
* appspec.yml →デプロイ処理用の定義書
* taskdef.json →タスク定義を作成する定義書
* imageDetail.json →ECS Blue/Greenrデプロイ時に必要な定義書


## CI/CDとは何なのか？
**CI/CD(継続的インテグレーションと継続的デリバリー/デプロイメント)**
一言でいえばソフトウェア開発と運用のプロセスを**自動化**して、効率的に開発と運用をするための手法やツールのセットのことを言う。

さらに深堀りしてみる。

### 継続的インテグレーション（CI: Continuous Integration）

#### 定義
CIは開発者が頻繁にコードをリポジトリに統合するプラクティスで、通常毎日または数回に分けて実行される。

#### 目的
統合に伴う問題を早期発見して修正すること。→統合作業に伴う負担が減り、ソフトウェアの品質が向上する。

#### プロセス
①開発者がコードを変更してリポジトリにコミット
②自動化されたビルドとテストが即座に実行される
③問題が発生された場合、開発者に通知が行く

#### 利点
①早期のバグ検出
②チーム全体の可視性の向上
③ソフトウェアの品質向上
④主導による統合作業の削減

### 継続的デリバリー/デプロイメント（CD: Continuous Delivery/Deployment）

#### 定義
**継続的デリバリー**はソフトウェアの変更がリリース可能な状態に**常に**保たれるプラクティス。
**継続的デプロイメント**は継続的デリバリーをさらに進めて、変更が**自動的に本番環境**にデプロイされることを指す。

#### 目的
新機能や修正を迅速かつ安全にユーザーに届けること。→ユーザーからのフィードバックを早期に得ることが可能に

#### プロセス
①CIのプロセスを通過したコードは、デリバリーパイプラインに入る
②自動テスト、ステージング環境でのデプロイなどの一連の手順が実行される
③デプロイメントの最終段階として本番環境へのデプロイが行われる(継続的デプロイメントであれば自動的に)

#### 利点
①リリースサイクルの短縮
②リスクの低減
③ユーザーからの迅速なフィードバック
④効率的なリリースプロセス

## 環境構築
上記構成図を作成する前にVPCや権限設定などを行うが、今回のメインはCI/CDパイプラインとECSへの自動デプロイの流れがメインとなるため省略
※参考先の72ページまでは省略
　また添付ファイルはサンプルコードから参照しつつ多少修正を加えるものとする

## 環境準備(Codecommit)
Codecommitでリポジトリを作成する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3557022/fd403cd5-6227-0216-5b1e-49cf5b895dcd.png)

リポジトリ名を設定して作成を押下
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3557022/dc470d84-1d45-cf8e-2810-6c1180140ee6.png)

URLのクローンを押下してURLを入手する
※今回はHTTPS
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3557022/046343d7-0953-c779-0ec8-edd145d6a4be.png)

CLI上で下記コマンドを実施してクローンする
```
$ Git clone https://git-codecommit.ap-northeast-1.amazonaws.com/v1/repos/php-sample
Cloning into 'php-sample'...
warning: You appear to have cloned an empty repository.
```
もしここでGitのアクセス認証ができない場合は下記で解決

https://docs.aws.amazon.com/ja_jp/codecommit/latest/userguide/setting-up-gc.html

## ファイルの準備
ファイルを準備
※参照先からダウンロードして下記のような構成に変更
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3557022/6a01a53a-c921-76a2-02ce-a192aa07cd75.png)

### buildspec.yml

**注意点**
・envで環境変数を指定
・URL隣の/にはコンテナ名を記載
・最終行にはDeploy時に使用するappspec.ymlを明記

```yml
version: 0.2

env:
  variables:
    REPOSITORY_URI: 223303915231.dkr.ecr.ap-northeast-1.amazonaws.com/cicd
    AWS_DEFAULT_REGION: ap-northeast-1

phases:
  pre_build:
    commands:
      - echo Logging in to Amazon ECR...
      - aws ecr get-login-password --region $AWS_DEFAULT_REGION | docker login --username AWS --password-stdin $REPOSITORY_URI
      - IMAGE_TAG=$(echo $CODEBUILD_RESOLVED_SOURCE_VERSION | cut -c 1-7)
  build:
    commands:
      - echo Build started on `date`
      - echo Building the Docker image...
      - docker build -t $REPOSITORY_URI:latest .
      - docker tag $REPOSITORY_URI:latest $REPOSITORY_URI:$IMAGE_TAG
  post_build:
    commands:
      - echo Build completed on `date`
      - echo Pushing the Docker image...
      - docker push $REPOSITORY_URI:latest
      - docker push $REPOSITORY_URI:$IMAGE_TAG
      - printf '{"Version":"1.0","ImageURI":"%s"}' $REPOSITORY_URI:$IMAGE_TAG > imageDetail.json

artifacts:
  files:
    - appspec.yml
```

### appspec.ymlファイル
**注意点**
・task定義にはARNを指定
・コンテナ名にはECSで稼働中の対象コンテナ名を記載
```yml
version: 0.0
Resources:
  - TargetService:
      Type: AWS::ECS::Service
      Properties:
        TaskDefinition: "arn:aws:ecs:ap-northeast-1:223303915231:task-definition/cicd-fargate:1"
        LoadBalancerInfo:
            ContainerName: "cicd" 
            ContainerPort: 80
```

### taskdef.json
ECSのリビジョンにてJSONをコピー
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3557022/e51ec10d-6cba-fb99-9d6e-962572a55d77.png)

→ローカルにあるtaskdef.jsonファイルへコピーする

### 補足
### Dockerfile
```Dockerfile
FROM php:7.4.0-apache
COPY src/ /var/www/html/
```
### index,html
```html
<!DOCTYPE html>
<html lang="ja">
  <head>
    <title>PHP Sample</title>
  </head>
  <body>
    <?php echo gethostname(); ?>
  </body>
</html>
```


#### ここからリポジトリへのPushを行う
```bash
#php-sampleディレクトリへの移動
cd php-sample

#全ファイルをadd
git add -A

#add→commitとコメント
git commit -m "my first commit"

#commit→push
git push origin master
```

## CodePipeline(build,Deploy含む)の作成
CodePipelineの作成過程でCodebuildとCodeDeployも作成出来るためパイプラインを作成する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3557022/03a8ddb3-5488-a1ea-a8a5-e4f1d455465a.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3557022/dca14488-786e-34ab-aac5-1e8bc67950c3.png)

プロジェクトの作成を押下
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3557022/b18666ca-f957-bf0c-e280-3bae8cdfe4ed.png)

下記設定でCodeBulidを作成する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3557022/35632e5f-f516-514c-85ea-d010076f66b0.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3557022/6561b646-88a4-1e58-3867-99e199511ec2.png)

続いてCodeDeployを設定
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3557022/ad6d940f-2b2d-936c-ee4f-86e9833d357f.png)

上記でパイプラインを作成する
→**Bulidのbulidspec.ymlファイル実行権取得のためIAMロールよりcodebuild-php-sample-build-service-roleを付与する→AmazonEC2ContainerRegistryPowerUserをアタッチ**


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3557022/6eec9279-6940-fa3f-b45c-bb62d86e57bd.png)

続いてCodePiplineの設定変更→編集を押下
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3557022/ed721a5d-ca30-1012-f291-657a2ce33ef8.png)

ステージを編集するを押下→デプロイステージを編集
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3557022/9b9746d8-750b-1bae-5dd4-fc516794c529.png)

入力アーティファクトにSourceArtfactへ変更
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3557022/fcbd1ea4-b6a4-3656-6876-9e41f4567585.png)

続いてCodeDeployの設定編集
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3557022/db23eade-8040-a954-7730-5f0b1d105576.png)


デプロイ設定を下記に変更
※今回は５分で設定
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3557022/9775d428-1736-029d-89e1-08c621b6b844.png)

改めてパイプラインを実行する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3557022/41f46b1f-5f77-217e-cf5a-ba445a0b292d.png)

下記のようなエラーが出たため調べたところCodeBuildのbulidspecファイルが見つからないというエラーが出た場合は下記を参照
```
[Container] 2024/06/12 12:21:57.224498 Running on CodeBuild On-demand
[Container] 2024/06/12 12:21:57.224517 Waiting for agent ping
[Container] 2024/06/12 12:21:57.426057 Waiting for DOWNLOAD_SOURCE
[Container] 2024/06/12 12:21:58.839623 Phase is DOWNLOAD_SOURCE
[Container] 2024/06/12 12:21:58.840508 CODEBUILD_SRC_DIR=/codebuild/output/src3662395164/src
[Container] 2024/06/12 12:21:58.844368 Phase complete: DOWNLOAD_SOURCE State: FAILED
[Container] 2024/06/12 12:21:58.844386 Phase context status code: YAML_FILE_ERROR Message: stat /codebuild/output/src3662395164/src/bulidspec.yml: no such file or directory
```



https://qiita.com/Ryo-0131/items/bde59b7c1dc67e0dce27


下記のようにCICD環境の作成に成功
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3557022/8d9f6f97-62ad-20aa-3603-c6fa152decca.png)

改めてローカルからGit pushしても新しいファイルの内容でのデプロイを確認

## トラブル(時間がかかったもの)
#### ①buildspec.ymlファイルが見つからないというエラー
→(解決策)
変数の指定を前に持ってくる
特にURLの部分を先にしてしたことでこのエラーが解消された

#### ②ECRへアクセスできない
→(解決策)
再度AWS CLIの情報を確認する。
筆者は別リージョンでaws configureを入力していたためログインができない場合は要チェック。

#### ③appspec.ymlファイルが見つからない
→(解決策)
buildspec.ymlのアーティファクトでbuildspec.ymlを指定することで解消

## やってみて
まずはCICDの基本的な流れを理解できたことが良かった。
(Github自体は使用したことがあったため割と理解はしやすかった)
特に両specファイルの中身がかなりエラーに直結していたため要注意のように感じた。
→最初だからかも？？