作って学ぶGithub Actions入門（初学者向け）

## 目的
本記事ではGithub Actionsのワークフロー学習のため取り組んだ内容を、備忘録的に記事にします。
初心者の私が実際に作ってみること、動かしてみること、そして公式ドキュメントを参考にワークフローの構文を1つずつ理解していくことを目的に取り組みました。

### スペシャルサンクス
ワークフローの内容は、下記2つの記事を参考にさせていただきました。
大変勉強になりました、ありがとうございます！

https://zenn.dev/nnabeyang/articles/05ce98c4955123

https://blog.g-gen.co.jp/entry/using-terraform-via-github-actions#%E6%A6%82%E8%A6%81-2


## 実行環境
```sh
$ terraform providers -version

Terraform v1.10.4
on linux_amd64
+ provider registry.terraform.io/hashicorp/google v6.16.0
+ provider registry.terraform.io/hashicorp/google-beta v6.16.0
```

## Cloud Runのコンテナイメージをデプロイする
![名称未設定ファイル.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3833399/6cbcf78f-0e05-0d8a-45b3-a3f63d0c1e2d.png)

まずはGoogle Cloudで利用頻度が高いであろうCloud Runとの連携です。
早速構築したワークフローをみていきます。

### `on:` トリガー
```yml
on:
  push:
    branches:
      - "master"
```

> on を使用してワークフローを実行する原因となるイベントを定義します

今回の例では、次の条件でワークフローが実行されます。
- master ブランチにコードが直接プッシュ/mergeされた場合

### `env:` 環境変数の設定

```yml
env:
  GCP_REGION: ${{ secrets.GCP_REGION_PRD }}
  IMAGE: ${{ secrets.GCP_REGION_PRD }}-docker.pkg.dev/${{ secrets.GCP_PROJECT_ID_PRD }}/${{ secrets.REPO_NAME }}/hello_cloudrun:${{ github.sha }}
  GOOGLE_IAM_WORKLOAD_IDENTITY_POOL_PROVIDER: ${{ secrets.GOOGLE_IAM_WORKLOAD_IDENTITY_POOL_PROVIDER }}
  SERVICE_ACCOUNT_EMAIL:  ${{ secrets.SERVICE_ACCOUNT_EMAIL }}
  ```
> 単一のワークフローにカスタム環境変数を設定するには、ワークフローファイル内の env キーを使用して環境変数を定義できます。 
> - ワークフロー全体 (ワークフロー ファイルの最上位レベルで env を使用)

ここでは、上記の通り、ワークフロー全体で利用可能な環境変数を`env`ブロックで定義しています。
また、※`secrets`を事前に定義しておき環境変数の値に利用しています。
> ※シークレットは、組織、リポジトリ、またはリポジトリ環境内に作成する変数です。

https://docs.github.com/ja/actions/security-for-github-actions/security-guides/using-secrets-in-github-actions?tool=webui

### `jobs`ブロック
```yml
jobs:
  build:
    runs-on: ubuntu-latest

    permissions:
      contents: 'read'
      id-token: 'write'
```

#### `jobs.<job_id>.runs-on`
> `jobs.<job_id>.runs-on`を使って、ジョブを実行するマシンの種類を定義します。

ここではubuntu OSの最新バージョンを指定しています。

#### `jobs.<job_id>.permissions`
> `jobs.<job_id>.permissions`を使用して GITHUB_TOKEN に付与された既定のアクセス許可を変更し、必要に応じてアクセスを追加または削除することで、必要最小限のアクセスのみを許可することができます。 

- `contents: 'read'`により、リポジトリの内容への読み取り権限が付与されています。

- `id-token: 'write'`により、GitHub Actionsがこの権限を持つことで、トークンを使った認証を可能にし、Google CloudがGitHub Actionsに対して必要なリソースへのアクセスを許可します。

### `steps`ブロック
```yml
    steps:
      - name: Checkout the repository
        uses: actions/checkout@v3

      - id: "auth"
        uses: "google-github-actions/auth@v2"
        with:
          workload_identity_provider: "${{ env.GOOGLE_IAM_WORKLOAD_IDENTITY_POOL_PROVIDER }}"
          service_account: "${{ env.SERVICE_ACCOUNT_EMAIL }}"

      - name: Set up Cloud SDK
        uses: google-github-actions/setup-gcloud@v2

      - name: Authorize Docker push
        run: gcloud auth configure-docker ${{ secrets.GCP_REGION_PRD }}-docker.pkg.dev

      - name: Build a docker image
        run: docker build -t ${{ env.IMAGE }} -f Dockerfile .

      - name: Push the docker image
        run: docker push ${{ env.IMAGE }}

      - name: Deploy to Cloud Run
        id: deploy
        uses: google-github-actions/deploy-cloudrun@v0
        with:
          service: XXX
          image: ${{ env.IMAGE }}
          region: ${{ env.GCP_REGION }}
```
####  `jobs.<job_id>.steps[*]`
> 1 つのジョブには、steps と呼ばれる一連のタスクがあります。 ステップでは、コマンドを実行する、設定タスクを実行する、あるいはリポジトリやパブリックリポジトリ、Dockerレジストリで公開されたアクションを実行することができます。 

- `jobs.<job_id>.steps[*].id`
    - 後続のステップでidを指定することで、当該コンテキストを参照可能となります。
- `jobs.<job_id>.steps[*].name`
    - GitHubで表示されるステップの名前を定義しています。
- `jobs.<job_id>.steps[*].uses`
    - アクションを定義しています。アクションとは再利用可能なコードの単位で、公開されているアクション、カスタムアクション、または Docker イメージをステップ内で利用することができます。
    - ここでは GitHub ActionのGoogle Cloudに対する認証や、Cloud Runへのデプロイアクションを利用しています。
- `jobs.<job_id>.steps[*].run`
    - シェルを使用して、21,000 文字を超えないコマンド ライン プログラムが実行可能です。
    - ここでは、`gcloud auth configure-docker`でDockerの認証を行い、さらに指定されたリポジトリへのアクセスを許可します。また`build`や`push`などの`docker`コマンドが実行されています。


## Terraformリソースの自動デプロイする
続いてはTerraformで作成したリソースのデプロイをワークフローで実現するケースです。
Cloud Runのワークフローでは見られなかった、特徴的なワークフロー構文に限定して内容を整理していきます。

![github_tf.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3833399/65aa7ac6-7e97-7ddd-ad3a-2af1391424a1.png)

### `on:` トリガー
```yml
on:
  push:
    branches:
      - master
  pull_request:
```
この例では、次の2つ条件でワークフローが実行されます。
- master ブランチにコードが直接プッシュ/mergeされた場合
- すべてのブランチで、pull requestが発生した場合

イベント発生条件を制御することで、CI／CDそれぞれで実行したいステップを分けて実装可能です。

### `steps`ブロック
イベント発生条件を制御した`on`トリガーの元で、次の`jobs.steps`を構成しています。
```yml
jobs:
  terraform-workflow:
    runs-on: ubuntu-latest
    steps:
        - name: Terraform fmt
          id: fmt
          run: terraform fmt -check -recursive
          continue-on-error: true
        ...
        # プルリクエスト発生時にのみ実行されるステップ
        - name: Comment Terraform Plan
          uses: actions/github-script@v6
          if: github.event_name == 'pull_request'
          env:
              PLAN: "terraform\n${{ steps.plan.outputs.stdout }}"
          with:
              github-token: ${{ secrets.GITHUB_TOKEN }}
              script: |
                const output = `#### Terraform Format and Style \`${{ steps.fmt.outcome }}\`
                <details><summary>Show Plan</summary>
                ${process.env.PLAN}
                </details>


        # main ブランチに pushされた場合にのみ実行されるステップ
        - name: Terraform Apply
        　if: github.ref == 'refs/heads/master' && github.event_name == 'push'
        　run: terraform apply -auto-approve -input=false
        　env: 
              TF_VAR_project: ${{ secrets.TF_VAR_project }}
```
#### `jobs.<job_id>.steps[*]`
- `jobs.<job_id>.steps[*].if`
    - 条件が満たされなければ、ステップを実行しないよう制御します。ここでは、イベントが`pull_request`の場合のみに実行されるステップ、そして`master`ブランチへの`push`イベントの場合のみに実行されるステップが定義されています。

    - これによりCIステップ、CDステップを分けることができ、安全なデプロイサイクルを回すことができます。

- `jobs.<job_id>.steps[*].with`
    - アクションの入力パラメータでキー：値ペアで定義されます。

- `jobs.<job_id>.steps[*].env`
    - `TF_VAR_project`を環境変数に登録しています。
    - この環境変数を利用するように`terraform`のソースが構成されています。

- `jobs.<job_id>.steps[*].continue-on-error`
    - `true`にしていることで、このステップが失敗してもジョブ全体を失敗としない設定が可能になります。


## 最後に
実際に作ってみて、そのワークフローをドキュメントと照合しながら学ぶGithub Actionsでした。
学びたいことはまだまだ尽きず、`on`トリガーの微細な制御や、`actions/github-script`を利用したリポジトリやプルリクエスト、Issueの操作などCI/CDに必要・便利な運用方法を学んでいきたいです。


## 公式ドキュメント
説明はかなりかりやすく、また直感的でよいUIだなと感じました！
https://docs.github.com/ja/actions/writing-workflows/workflow-syntax-for-github-actions