CICDパイプラインとは

# CICDパイプラインとは
ソフトウェア開発で`コーディング`と`コミット`が終わったあとにする
`ビルド`、`テスト`、`デプロイ`の流れのことである。
(基本的には`ビルド`、`テスト`、`デプロイ`は自動化する)
## CICDパイプラインのサービス
CICDパイプラインのサービスは`GithubActions`が人気である。

https://docs.github.com/ja/actions

## GithubActionsの使い方
CICDパイプラインを使用したいアプリの中に`.github/workflows`を作成してその中にCICDパイプラインの設定をする`yml`ファイルを作成する。

`on`はどのコマンドでCICDパイプライン動作するのかを指定できる
`jobs`でどんな作業を実行するのかを指定できる(stepsの集まり)
`runs-on`は実行環境を指定する
`steps`はjobsの中でどんな作業を実行するのかを具体的に書く
`run`は実行するコマンドのこと

## 例の猫のことを出力する簡単なアプリの例

```yml:.github/workflows/cicd.yml
name: Neko_Introduction # このCICDの名前

on:
  push: # push の時にCICDパイプラインを動作させる

jobs:
  Neko_Japan: # job名
    runs-on: ubuntu-latest # 実行環境の指定
    steps:
      - name: Say something in Japanese #stepsの名
        run: |
          echo "neko_wakaii" #実行コマンド
          echo "neko_utukusii"

  Neko_English:
    runs-on: ubuntu-latest 
    steps:
      - name: Say something in English
        run: |
          echo "cat_cute"
          echo "cat_beautiful"
```

# DockerとAWSを使ったGitHubActionsのやり方
例のコード

```yml
name:  <CICDの名前>
on:
  push:
    paths:
      - '.github/workflows/**'
      - 'app/**'
env:
  AWS_REGION: <AWSのリージョン名>
  ECS_CLUSTER: <AWSのcluster名>
  ECS_SERVICE: <AWSのservice名>
  ECR_REPOSITORY: <AWSのrepository名>
  ECS_TASK_DEFINITION_API: <Task定義を行ったjsonファイルを指定する>

permissions:
  contents: read
  id-token: write

jobs:
  test-and-build:
    runs-on: ubuntu-latest
    defaults:
      run:
        working-directory: cicd-section/api
    steps:
      - uses: actions/checkout@v4
      - name: Run Tests and Build an Image
        run: docker image build -t temp_api_image:latest .
      - name: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@v4
        with:
          aws-region: ${{ env.AWS_REGION }}
          role-to-assume: ${{ secrets.AWS_ROLE_TO_ASSUME }}
      - name: Login to Amazon ECR
        id: login-ecr
        uses: aws-actions/amazon-ecr-login@v2

      - name: Push the image to Amazon ECR
        env:
          ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
        run: |
          docker image tag temp_api_image:latest $ECR_REGISTRY/$ECR_REPOSITORY:${{ github.sha }}
          docker image push $ECR_REGISTRY/$ECR_REPOSITORY:${{ github.sha }}
          echo $ECR_REGISTRY/$ECR_REPOSITORY:${{ github.sha }} > api-image-url.txt
      
      - name: Upload the image url file as an artifact
        uses: actions/upload-artifact@v4
        with:
          name: api-image-url
          path: cicd-section/api/api-image-url.txt

  deploy:
    runs-on: ubuntu-latest
    needs: [test-and-build]
    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@v4
        with:
          aws-region: ${{ env.AWS_REGION }}
          role-to-assume: ${{ secrets.AWS_ROLE_TO_ASSUME }}

      - name: Download the artifact
        uses: actions/download-artifact@v4
        with:
          name: api-image-url
          path: artifacts
    
      - name: Define the image URI
        run: |
          echo "API_IMAGE_URI=$(cat artifacts/api-image-url.txt)" >> $GITHUB_ENV
    
      - name: Fill in the new image URI in the amazon ECS task definition
        id: render-task-def
        uses: aws-actions/amazon-ecs-render-task-definition@v1
        with:
          task-definition: ${{ env.ECS_TASK_DEFINITION_API }}
          container-name: api
          image: ${{ env.API_IMAGE_URI }}
  
      - name: Deploy  ECS task
        uses: aws-actions/amazon-ecs-deploy-task-definition@v1
        with:
          task-definition: ${{ steps.render-task-def.outputs.task-definition }}
          service: ${{ env.ECS_SERVICE }}
          cluster: ${{ env.ECS_CLUSTER }}
          wait-for-service-stability: true
```
# 上のコードの説明
まず、CICDパイプラインの名前とどのコマンドのときにCICDパイプラインを動作させるのかを指定する。
```yml:.github/workflows/cicd.yml
name: <CICDの名前>
on:
  push:
    paths: #このパスの中のファイルに変更のあったときにだけCICDパイプラインが動作する
      - '.github/workflows/**'
      - 'app/**'
```
AWSの環境変数`ENV`を定義する
```yml
env:
  AWS_REGION: <AWSのリージョン名>
  ECS_CLUSTER: <AWSのcluster名>
  ECS_SERVICE: <AWSのservice名>
  ECR_REPOSITORY: <AWSのrepository名>
  ECS_TASK_DEFINITION_API: <Task定義を行ったjsonファイルを指定する>
```
GitHub Actions ワークフローがリポジトリに対して持つ権限を指定する。
```yml
permissions:
  contents: read
  id-token: write
```
実行環境と作業ディレクトリを指定する。
```yml
jobs:
  test-and-build:
    runs-on: ubuntu-latest #実行環境の指定
    defaults:
      run:
        working-directory: api #作業ディレクトリを指定
```
`uses: actions/checkout@v4`とはgithubはgithubにあげたコードをそのままでは参照できないため`checkout`を使用してgithubが参照できるようにする。
`uses`は誰かが作った`run`の集まりを参照するときに使う。


https://github.com/marketplace?type=actions


ここで`docker image`を作成する
```yml
    steps:
      - uses: actions/checkout@v4
      - name: Run Tests and Build an Image
        run: docker image build -t temp_api_image:latest .
```


`GitHub Actions`が`AWS`にログインし、権限を取得する
`secrets.AWS_ROLE_TO_ASSUME`の設定はとてもセキュアにしないといけないためこのファイルにENVでは書かずに、githubのページで設定する。
環境変数の参照は`${{}}`でくくる。

```yml
      - name: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@v4
        with:
          aws-region: ${{ env.AWS_REGION }}
          role-to-assume: ${{ secrets.AWS_ROLE_TO_ASSUME }}
```
`ECR`にログインする
```yml
      - name: Login to Amazon ECR
        id: login-ecr
        uses: aws-actions/amazon-ecr-login@v2
```

`steps.login-ecr.outputs.registry`にはidが`login-ecr`であるstepの出力値を参照している。

そして、`run`で`docker image`に`tag`を付けて、その`docker image`を`ECR`に`push`している。

そして、`echo`コマンドを使用して、`$ECR_REGISTRY/$ECR_REPOSITORY:${{ github.sha }}`を`api-image-url.txt`に保存している。

```yml
      - name: Push the image to Amazon ECR
        env:
          ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
        run: |
          docker image tag temp_api_image:latest $ECR_REGISTRY/$ECR_REPOSITORY:${{ github.sha }}
          docker image push $ECR_REGISTRY/$ECR_REPOSITORY:${{ github.sha }}
          echo $ECR_REGISTRY/$ECR_REPOSITORY:${{ github.sha }} > api-image-url.txt
```
下のコードは`github`のアーティファクトを用いて`docker image`の`URL`を`api-image-url.txt`というファイルに保存して、そのファイルを`GitHub Actions`内で使えるようにアップロードして保存している。

```yml
      - name: Upload the image url file as an artifact
        uses: actions/upload-artifact@v4
        with:
          name: api-image-url
          path: cicd-section/api/api-image-url.txt
```




































以下のコードで実行環境と`test-and-build`が終わった後に実行するように設定する。
そして、コードを`checkout`して`GitHub Actions`がコードを参照できるようにする。
```yml
  deploy:
    runs-on: ubuntu-latest
    needs: [test-and-build]
    steps:
      - name: Checkout
        uses: actions/checkout@v4
```
GitHub ActionsがAWSにログインし、権限を取得する
```yml
      - name: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@v4
        with:
          aws-region: ${{ env.AWS_REGION }}
          role-to-assume: ${{ secrets.AWS_ROLE_TO_ASSUME }}
```
アーティファクトにある`api-image-url.txt`をアップロードしてきて`docker image`名をGitHub Actionsで使えるようにしている。
```yml
      - name: Download the artifact
        uses: actions/download-artifact@v4
        with:
          name: api-image-url
          path: artifacts
```
`artifacts/api-image-url.txt`というファイルの中身を`API_IMAGE_URI`という環境変数に代入して、それを`$GITHUB`に書き込んでいる。
```yml
      - name: Define the image URI
        run: |
          echo "API_IMAGE_URI=$(cat artifacts/api-image-url.txt)" >> $GITHUB_ENV
```
ECS に、新しいコンテナイメージを使うように設定する準備をしている

```yml
      - name: Fill in the new image URI in the amazon ECS task definition
        id: render-task-def
        uses: aws-actions/amazon-ecs-render-task-definition@v1
        with:
          task-definition: ${{ env.ECS_TASK_DEFINITION_API }}
          container-name: api
          image: ${{ env.API_IMAGE_URI }}
```
新しいタスク定義を Amazon ECS に適用して、サービスをデプロイしている。
```yml
      - name: Deploy  ECS task
        uses: aws-actions/amazon-ecs-deploy-task-definition@v1
        with:
          task-definition: ${{ steps.render-task-def.outputs.task-definition }}
          service: ${{ env.ECS_SERVICE }}
          cluster: ${{ env.ECS_CLUSTER }}
          wait-for-service-stability: true
```