【Azure × GitHub】React コンテナアプリのCI/CD 環境を構築してみよう

# はじめに

Docker や Azure コンテナサービス関連の勉強していました。

成果物として、Azure と GitHub Action を利用した React コンテナアプリの CI/CD 環境が割と簡単に構築できるテンプレートリポジトリを作成しました。

学習したことも後々まとめていこうと思いますが、今回はテンプレートリポジトリの利用方法を共有してみようかと思います。

# 環境

- macOS: `15.0.1`
- Visual Studio Code:  `1.95.1`
    - Bicep(拡張機能):  `v0.30.23`

# 前提

### ローカル PC

- git がインストールされていること。
- vscode がインストールされていること。
    - Bicep(拡張機能) がインストールされていること

### Azure

- Azure アカウントを所有していること。
- 作業アカウントに、サブスクリプションスコープの所有者ロールが割り当てられていること

# テンプレートについて

下記リポジトリで公開しています。

https://github.com/nownaka/azure-container-apps-cicd-react-template

### ディレクトリ構造

```
.
├── .github
│   └── workflows
│       └── build_and_deploy.yaml
├── app
├── infra
│   ├── modules
│   │   ├── containerapps.bicep
│   │   ├── environment.bicep
│   │   ├── registries.bicep
│   │   ├── roleAssignments.json
│   │   ├── roleAssignmentsFromARM.bicep
│   │   ├── userAssignedIdentities.bicep
│   │   └── workspaces.bicep
│   ├── main.bicep
│   ├── main.bicepparam
├── .gitignore
├── docker-compose.yml
├── Dockerfile
└── README.md
```

## app : React アプリケーション

`npx create-react-app my-app --template typescript` で作成されるデフォルトの構成です。

## infra : Azure リソース

作成するリソースの Bicep テンプレートをまとめています。

- リソース一覧と役割：

| No | リソース名 | 説明 |
| --- | --- | --- |
| 1 | Log Analytics Workspace | **Azure Container Apps のログ格納・監視する** |
| 2 | Azure Container Registry | コンテナイメージを格納する |
| 3 | Azure Container Apps Environment | Azure Container Apps の管理、論理的ネットワーク空間 |
| 4 | User Assigned Managed Identity | イメージのプル、プッシュ、コンテナへのデプロイを行う |
| 5 | Azure Container Apps | コンテナアプリの実行環境 |
| 6 | Role Assignments | マネージド ID に必要な権限を付与 |
| 7 | Federated Identity Credentials | マネージド ID にフェデレーション資格情報を追加 |
- 依存関係：

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2513223/49735e1a-233a-7cc1-40d9-b75a79e8ae17.png)

# 利用方法

::: note warn
注意
Azure のコンテナサービス群を利用します。
利用状況によっては、コストが発生しますが、自己責任でお願いします。
:::

## STEP 1 : テンプレートリポジトリをフォークする

1. [リポジトリ](https://github.com/nownaka/azure-container-apps-cicd-react-template)を フォークする
2. フォークした リポジトリをクローンする。
3. クローンしたリポジトリを開く。

:::note info
フォークとクローンについて

- [リポジトリをフォークする](https://docs.github.com/ja/pull-requests/collaborating-with-pull-requests/working-with-forks/fork-a-repo)

- [リポジトリをクローンする](https://docs.github.com/ja/repositories/creating-and-managing-repositories/cloning-a-repository)
:::

## STEP 2 : Bicep を利用してインフラ環境を構築する

### 2-1 :  bicepparam の設定する

`main.bicepparam` を開き、必要なパラメータを設定します。

```zsh: main.bicepparam
using './main.bicep'

// リソースの名前は以下のようになります。
// {リソースの略語}-{アプリ名}-{サフィックス}
// Check: https://learn.microsoft.com/ja-jp/azure/cloud-adoption-framework/ready/azure-best-practices/resource-naming

param appName = '{your app name}' // require
param environment = '{your environment name}' // require
param suffix = '' // option

param federatedIdentityCredentialsConfig = { // require
  name: 'github_federation_for_azure_container_services'
  audiendes: ['api://AzureADTokenExchange']
  issuer: 'https://token.actions.githubusercontent.com'
  subjedt: 'repo:{github account name}/{github repository name}:environment:Production'
}

// federatedIdentityCredentialsConfig について
// github の場合、次の形式である必要があります。
// - name：
//    フェデレーテッド ID 資格情報名には、文字 (A ～ Z、a ～ z)、数字、ハイフン、ダッシュのみを含める必要があります。数字または文字で始める必要があります。
//    フェデレーション ID 認証情報の名前は 3 ～ 120 文字以内で、文字 (A ～ Z、a ～ z)、数字、ハイフン、ダッシュのみを含み、数字または文字で始まる必要があります。
// - audiendes:
//    ['api://AzureADTokenExchange'] である必要があります。
// - issuer:
//    'https://token.actions.githubusercontent.com' である必要があります。
// - subjedt:
//    repo:{github account name}/{github repository name}:{entity}
//    - entity：
//       環境 => environment:{environment name} <<<= 今回はこれ
//       ブランチ => ref:refs/heads/{branch name}

```

`suffix` はオプションとしていますが、リソースによっては グローバルでユニークにする必要があるため、お試しであれば日時を入れるなど被らない名前にすることをおすすめします。

### 2-2 : リソースをデプロイする

##### 1. `command` + `shift` + `p` でコマンドパレットを起動する。
##### 2. [ Bicep: Deploy Bicep File… ] を選択する。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2513223/c803bf48-1084-9b2a-008e-b1b921786c94.png)

##### 3. [ infra/main.bicep ] を選択する。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2513223/9bf4de7d-b440-8223-2577-a744b42d7a9a.png)

##### 4. [ デプロイ名(任意の値) ] を入力して、Enter を押す。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2513223/489eb44c-4a86-6519-2216-9684fcd2f23a.png)

##### 5. リソースグループ を選択、または新規作成する。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2513223/63080159-6f5b-4201-0330-8420ba5e4b63.png)

- 新規作成する場合：

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2513223/a519670f-2fe2-5af5-bae4-058eb59f6e24.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2513223/e7c66da6-0801-187b-b50e-68f0107329c0.png)

##### 6. [ infra/main.bicepparam ] を選択する。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2513223/fddb504f-65ce-65ce-4848-ef2e4f45e767.png)

### 2-3 : リソースを確認する

##### 1. vscode 上のターミナルにURL が表示されるので、アクセスしてデプロイ結果を確認する。
- ターミナル：

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2513223/e1b9f386-5470-8dec-f982-54a05684ce49.png)

- デプロイ結果：

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2513223/ba941e37-39fb-1d15-fc60-32f9d887352d.png)

##### 2. [ リソースグループに移動 ] を新規タブで開き、リソース一覧の中から、 [<コンテナアプリ>]  を選択する。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2513223/8babd3d7-8a92-dbb0-9154-d7ff52aed467.png)

##### 3. コンテナアプリの URL にアクセスし、下記画面が表示されることを確認する。
    
 ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2513223/ed27c3f7-dca2-f540-ddf8-9ab509d17dd7.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2513223/ecc2c5ba-089b-efac-93a7-ea2d28500e23.png)

## STEP 3 : GitHub Action 用に変数とシークレットを登録する

##### 1. デプロイ結果の[ 出力 ] を選択する。（[STEP : 2-3-1 の画面](https://qiita.com/drafts/718b980337d27e28a08b/edit#2-3--リソースを確認する)）
##### 2. 表示された値を GitHub リポジトリの [Actions secrets and variables] から、 `Production` 環境を作成し、変数とシークレットを登録する。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2513223/d23969df-8661-4bbc-4f14-4badb9a610ac.png)

:::note info
GitHub Action の変数とシークレットについて
- [GitHub Actions でのシークレットの使用](https://docs.github.com/ja/actions/security-for-github-actions/security-guides/using-secrets-in-github-actions)
- [変数に情報を格納する](https://docs.github.com/ja/actions/writing-workflows/choosing-what-your-workflow-does/store-information-in-variables)
:::

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2513223/feb5fba7-f4ae-702b-b194-b06d5176cb64.png)

| Type | 名前 | 説明 | 設定値 |
| :--- | :--- | :--- | :--- |
| secret | AZURE_CLIENT_ID | マネージド ID のクライアント ID | 環境依存 |
| secret | AZURE_TENANT_ID | テナント ID | 環境依存 |
| secret | AZURE_SUBSCRIPTION_ID | サブスクリプション ID | 環境依存 |
| variable | AZURE_RESOURCE_GROUP_NAME | リソースグループ名 | 環境依存 |
| variable | AZURE_CONTAINER_REGISTRY_NAME | Azure Container Registry のリソース名 | 環境依存 |
| variable | AZURE_CONTAINER_APP_NAME | Azure Container Apps のリソース名 | 環境依存 |
| variable | CONTAINER_NAME | コンテナ名 | app |

## STEP 4 : ワークフローを起動させてアプリをデプロイする

適当に変更を加えて `main` ブランチに push します。

または、GitHub Action のワークフローを手動でトリガーしてください。

:::note info
ワークフローの手動実行について
- [ワークフローの手動実行](https://docs.github.com/ja/actions/managing-workflow-runs-and-deployments/managing-workflow-runs/manually-running-a-workflow)
:::

## STEP 5 :  ワークフローとデプロイを確認する

GitHub Action のワークフローの結果とコンテナアプリにデプロイできていることを確認します。

- GitHub Action：

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2513223/94e2523e-2fb6-6843-4d78-7e7b12638731.png)


- コンテナアプリ：

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2513223/91d55ab1-7cef-f9c2-ef5c-25e16ed4b504.png)


以上です！

# さいごに

作成したテンプレートを利用して、Azure と GitHub Action を利用した React コンテナアプリの CI/CD 環境を構築する方法を説明しました。

今回コンテナ技術をはじめて触ったので、細かいところまでは理解できていませんが、一旦やりたいことができたのでよかったです。

本記事、テンプレートが誰かの役に立てば幸いです。

# 参考

https://techblog.ap-com.co.jp/entry/2022/09/01/120000

https://jasonhaley.com/2022/04/06/container-app-quickstart-bicep/

https://learn.microsoft.com/ja-jp/entra/workload-id/workload-identity-federation-create-trust-user-assigned-managed-identity?pivots=identity-wif-mi-methods-azcli

https://github.com/Azure/bicep/discussions/5805

https://qiita.com/kurokawa516/items/2be4d40a49bc06d14876