GitHubActionsを使用してReactアプリをS3へ自動デプロイしてみたいと思います。
構築の流れ
- AWSでOIDCを作成する
- 対象のリポジトリでGitHubActionsのワークフローを定義する
- 動作確認
AWSでOIDCを作成
GitHubActions→AWSへアクセスできるよう下記記事を参考にOIDCを作成します
・AWSコンソールで作成する方
・Terraformで作成する方
OIDCが使用するロールのポリシーでs3:PutObjectを許可してください
私が使っているポリシーを一例として載せておきます
1 2 3 4 5 6 7 8 9 10 11 |
{ "Version": "2012-10-17", "Statement": [ { "Sid": "VisualEditor0", "Effect": "Allow", "Action": "s3:PutObject", "Resource": "arn:aws:s3:::<Reactアプリのアップロード先となるS3バケット名>/*" } ] } |
ワークフローを定義する
PR作成時に動作するワークフロー
ワークフローを定義しているYAMLファイル
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
name: ci on: pull_request: branches: - main jobs: ci: runs-on: ubuntu-latest steps: # チェックアウトするアクション - uses: actions/checkout@v2 # 特定バージョンのnodeを設定するアクション - name: Use NodeJS uses: actions/setup-node@v1 with: node-version: 18.16.0 # dependencyのキャッシュ - name: Cache node_modules uses: actions/cache@v1 with: #キャッシュしたファイルとキーを格納する場所(OSによって異なる) path: ~/.npm #キャッシュのリストアや保存をするためのキー key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }} #キャッシュをリストアするためのキーのリスト restore-keys: | ${{ runner.os }}-node- # dependencyのインストール - run: npm ci # テスト - run: npm test |
コード解説
まずは、いつ実行されるワークフローか定義します
CIのほうはmainブランチへのマージリクエストを作成した際に実行するよう定義。
1 2 3 4 |
on: pull_request: branches: - main |
実行する環境をUbuntuに指定します
1 |
runs-on: ubuntu-latest |
stepsにワークフローを定義していきます
まずは、リポジトリのチェックアウトとNode.jsをインストールします
1 2 3 4 5 6 7 |
# チェックアウトするアクション - uses: actions/checkout@v2 # 特定バージョンのnodeを設定するアクション - name: Use NodeJS uses: actions/setup-node@v1 with: node-version: 18.16.0 |
毎回、依存関係をインストールすると時間かかるので、node_mpodulesをキャッシュしておきます
1 2 3 4 5 6 7 8 9 10 11 |
# dependencyのキャッシュ - name: Cache node_modules uses: actions/cache@v1 with: #キャッシュしたファイルとキーを格納する場所(OSによって異なる) path: ~/.npm #キャッシュのリストアや保存をするためのキー key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }} #キャッシュをリストアするためのキーのリスト restore-keys: | ${{ runner.os }}-node- |
次に依存関係をインストールします
npm ci をつかうと、package-lock.jsonだけをみてインストールするため、
npm install よりも時間を短縮できます
1 2 |
# dependencyのインストール - run: npm ci |
今回はテストのみ実行します。
他にもフォーマットやバリデーションなどを行ってもいいと思います。
1 2 |
# テスト - run: npm test |
mainブランチへマージしたときに動作するワークフロー
ワークフローを定義しているYAMLファイル
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
name: Deploy to S3 on: push: branches: - main env: # GitHubActionsOIDCRole:作成したIAMロール名 AWS_ROLE_ARN: arn:aws:iam::<AWSアカウントID>:role/GitHubActionsOIDCRole permissions: id-token: write contents: read jobs: deploy: runs-on: ubuntu-latest steps: # チェックアウトするアクション - uses: actions/checkout@v2 # 特定バージョンのnodeを設定するアクション - name: Use NodeJS uses: actions/setup-node@v1 with: node-version: 18.16.0 # dependencyのキャッシュ - name: Cache node_modules uses: actions/cache@v1 with: #キャッシュしたファイルとキーを格納する場所(OSによって異なる) path: ~/.npm #キャッシュのリストアや保存をするためのキー key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }} #キャッシュをリストアするためのキーのリスト restore-keys: | ${{ runner.os }}-node- # dependencyのインストール - run: npm ci # ビルド - run: npm run build # awsへのアクセス情報を設定 - uses: aws-actions/configure-aws-credentials@v1 with: role-to-assume: ${{ env.AWS_ROLE_ARN }} aws-region: ap-northeast-1 # S3にビルドしたものをアップロード - run: aws s3 cp --recursive build s3://<アップロード先のS3バケット名>/ |
コード解説
CDのほうはmainブランチにpushされたときに実行されるようにします
Pull Requestをマージしたときだけでなく、
git push origin main でプッシュした際にも実行されるのでご注意ください!
1 2 3 4 |
on: push: branches: - main |
envに今回使用するOIDCのロールを指定します
1 2 3 |
env: # GitHubActionsOIDCRole:作成したIAMロール名 AWS_ROLE_ARN: arn:aws:iam::<AWSアカウントID>:role/GitHubActionsOIDCRole |
GitHubのIDトークンの取得とリポジトリへのアクセスを許可しておきます
1 2 3 |
permissions: id-token: write contents: read |
stepsでCIの時と違うのはビルドしてS3にアップロードするところぐらいです。
S3にアップロードするためにAWSへアクセスするときに先ほどのOIDCのロールを指定します。
1 2 3 4 5 6 7 8 9 |
# ビルド - run: npm run build # awsへのアクセス情報を設定 - uses: aws-actions/configure-aws-credentials@v1 with: role-to-assume: ${{ env.AWS_ROLE_ARN }} aws-region: ap-northeast-1 # S3にビルドしたものをアップロード - run: aws s3 cp --recursive build s3://<アップロード先のS3バケット名>/ |
動作確認
ワークフローをリモートブランチにpush
testブランチを作成し、ワークフローをコミット、プッシュしていきます
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
// testブランチを作成 $ git checkout -b test // testブランチが作成され、そのブランチにいることを確認 $ git branch // add $ git add . // 対象のYAMLファイルがaddされていることを確認 $ git status // addしたファイルをコミット $ git commit -m "commit workflow" // コミット履歴を確認 $ git log // リモートブランチへpush $ git push origin test |
PRを作成
pushできたら、GitHubへアクセスしPRを作成します。
pushしたリポジトリの画面に行くと↓の画像の赤枠のPR作るボタンを押下します
PR作成画面に遷移しますので、「Create pull request」を押下しPRを作成します。
PRの詳細画面に遷移し、PR作成時に動作するワークフローの実行結果を確認します。
青枠内のようにチェックが入っていればGitHubActionsは成功しています。
詳細な実行結果は Hide all checks > Details をクリックしてみることができます。
ワークフロー内の1つ1つの処理の実行結果を見ることができます
mainブランチへマージ
PR詳細画面に戻り、マージしていきます。Merge pull request をクリックします。
Confirm merge をクリックします
Delete branch でマージ元のブランチは消しておきます。
GithubActions の実行結果を見に行きます。Actions をクリックします。
Merge pull request #1 from ***/test というような名前のワークフローがあります
赤枠内が✓となっていれば成功、×となっていたら失敗しています。
また、クリックして詳細画面に遷移できるので、失敗している場合は確認してみてください
次に、S3を確認してみます
Reactアプリを保存しているS3バケット内の最終更新日時を見てみます。
GitHubActionsを実行した時間になっていればOKです!
これで、Reactアプリの自動デプロイを設定できました!
GitHubActionsででたエラー
mainブランチへマージときに実行されるワークフローで出たエラーをまとめます。
同じく遭遇した方はご参考ください
OIDCが使用するロールの信頼関係のリポジトリが正しくない
1 |
Error: Not authorized to perform sts:AssumeRoleWithWebIdentity |
こんなエラーが出た場合は、
OIDCが使用するロールの信頼関係で設定しているリポジトリが正しいか確認してください
下記のように設定されていればOKです
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
{ "Version": "2012-10-17", "Statement": [ { "Sid": "", "Effect": "Allow", "Principal": { "Federated": "arn:aws:iam::<AWSアカウントID>:oidc-provider/token.actions.githubusercontent.com" }, "Action": "sts:AssumeRoleWithWebIdentity", "Condition": { "StringLike": { "token.actions.githubusercontent.com:aud": "sts.amazonaws.com", "token.actions.githubusercontent.com:sub": "repo:<GitHubのユーザ名>/<リポジトリ名>:*" } } } ] } |
ワークフローにpermissionsを設定してない
1 |
Error: Credentials could not be loaded, please check your action inputs: Could not load credentials from any providers |
これはワークフロー内でpermissionsを設定していないことが原因かもしれません。
↓をワークフローを定義しているのYAMLファイルに追記してください
1 2 3 |
permissions: id-token: write contents: read |
GitHhubActionsのpermissionsってなんだ?と思った方は下記の記事を読んでみてください
ポリシーに権限が足りない
1 2 |
Run aws s3 cp --recursive build s3://<Reactアプリのアップロード先となるS3バケット名>/ upload failed: build/logo192.png to s3://<Reactアプリのアップロード先となるS3バケット名>/logo192.png An error occurred (AccessDenied) when calling the PutObject operation: Access Denied |
PutObject で Access Denied が出ています。
これは使用しているロールのポリシーでS3のPutObjectを許可しているか確認してください
参考記事
コメント