CI/CD 構築:フロントエンド自動デプロイ
実現したこと
手動で行っていた以下のフローを、main ブランチに push したらフロントが自動で本番反映されるように構築した。
コード修正
↓ 手動
npm run build
↓ 手動
AWS S3 コンソール画面より build ファイルをアップロード
↓ 手動
AWS CloudFront のコンソール画面よりキャッシュ削除
📚 CI/CD とは
| 略 | 名称 | 役割 |
|---|---|---|
| CI | Continuous Integration | コード変更のたび自動でチェック(typecheck / lint / build / test) |
| CD | Continuous Delivery / Deployment | CI が通ったら自動で本番反映 |
Step 1:AWS リソースの準備
Step 1-1 全体像の把握
| # | リソース | 役割 |
|---|---|---|
| ① | OIDC Provider | 「GitHub の発行する身分証を信頼するよ」と AWS に教える設定 |
| ② | IAM Role + Trust Policy | Trust Policy:IAM Role を GitHub Actions に貸す条件(特定リポジトリの main ブランチからの AssumeRole は許可) |
| ③ | 権限ポリシー | このロールに「何ができるか」を付与(S3 書き込み・CloudFront キャッシュ削除) |
| - | AssumeRole | GitHub Actions が実際に IAM Role の権限を一時的に取得する |
Step 1-2 OIDCプロバイダーの作成
OIDCについては、こちらの記事を参照

固定値
- プロバイダの URL:
https://token.actions.githubusercontent.com - 対象者 (Audience):
sts.amazonaws.com
Step 1-3 IAMロールの作成
- IAM コンソールから「ロールを作成」を選び、信頼されたエンティティタイプとして **「ウェブアイデンティティ」**を選択する。
入力項目
| 項目 | 値 |
|---|---|
| アイデンティティプロバイダー | token.actions.githubusercontent.com |
| Audience | sts.amazonaws.com |
| GitHub organization | your-org |
| GitHub repository(オプション) | your-repo |
| GitHub branch(オプション) | main |
Step 1-4 権限の追加(スキップ)
-
「何も選択せず」 に Next をクリック。
- 理由: 権限ポリシーは別途独立して作って、後からアタッチするため。
Step 1-5 Trust Policyの修正
ロール作成時に AWS が自動生成する Trust Policy
には、ウィザードの仕様で重複や冗長な記述が含まれる。最終的に以下の形に整える。
Before(自動生成)
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "sts:AssumeRoleWithWebIdentity",
"Principal": {
"Federated": "arn:aws:iam::123456789012:oidc-provider/token.actions.githubusercontent.com"
},
"Condition": {
"StringEquals": {
"token.actions.githubusercontent.com:aud": ["sts.amazonaws.com"]
},
"StringLike": {
"token.actions.githubusercontent.com:sub": [
"repo:your-org/your-repo:ref:refs/heads/main",
"repo:your-org/your-repo:ref:refs/heads/main"
]
}
}
}
]
}
After(最終形)
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Federated": "arn:aws:iam::123456789012:oidc-provider/token.actions.githubusercontent.com"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"token.actions.githubusercontent.com:aud": "sts.amazonaws.com",
"token.actions.githubusercontent.com:sub": "repo:your-org/your-repo:ref:refs/heads/main"
}
}
}
]
}
修正内容
| # | 修正 | 理由 |
|---|---|---|
| 1 |
sub の重複削除 |
同じ値が 2 回入っていても効果は同じ。冗長性排除 |
| 2 |
StringLike → StringEquals
|
sub の値にワイルドカードなし → 完全一致演算子で最小権限の原則を徹底 |
| 3 |
aud と sub を同じ StringEquals ブロックに統合 |
同じ演算子はまとめて可読性向上 |
Step 1-6 権限ポリシー作成(S3 + CloudFront)
次に「ポリシーの作成」から、このロールに付与する権限(何ができるか)をJSONで定義する。
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "S3SyncBucketLevel",
"Effect": "Allow",
"Action": ["s3:ListBucket"],
"Resource": "arn:aws:s3:::your-bucket-name"
},
{
"Sid": "S3SyncObjectLevel",
"Effect": "Allow",
"Action": [
"s3:GetObject",
"s3:PutObject",
"s3:DeleteObject"
],
"Resource": "arn:aws:s3:::your-bucket-name/*"
},
{
"Sid": "CloudFrontInvalidation",
"Effect": "Allow",
"Action": ["cloudfront:CreateInvalidation"],
"Resource": "arn:aws:cloudfront::123456789012:distribution/EXXXXXXXXXXXXX"
}
]
}
Step 1-7 作成したポリシーをRoleにアタッチ
作成した権限ポリシーを、Step 1-3 で作った IAM Role にアタッチする。
- IAM → Roles → 該当 Role を開く
- Permissions タブ → Add permissions → Attach policies
- ポリシー名で検索 → チェック → Add permissions
Step 2:GitHub Actions の設定
Step 2-1 GitHub Actions について
GitHub Actions を理解する - GitHub Docs
┌──────────────────────────────────────┐
│ Workflow(ワークフロー) │
│ = 1 つの yaml ファイル │
│ = 「何をきっかけに何をやるか」のまとまり │
│ │
│ ┌──────────────────────────────┐ │
│ │ Job(ジョブ) │ │
│ │ = 1 台の Runner で動く処理単位 │ │
│ │ = 並列実行可(複数 Job) │ │
│ │ │ │
│ │ ┌─────────────────────┐ │ │
│ │ │ Step(ステップ) │ │ │
│ │ │ = 1 コマンド │ │ │
│ │ │ = 直列実行 │ │ │
│ │ └─────────────────────┘ │ │
│ │ ┌─────────────────────┐ │ │
│ │ │ Step │ │ │
│ │ └─────────────────────┘ │ │
│ └──────────────────────────────┘ │
└──────────────────────────────────────┘
| 階層 | 役割 | 例 |
|---|---|---|
| Workflow | yaml ファイル 1 つ | deploy.yml |
| Job | 実行単位(VM 1 台分) | build-and-deploy |
| Step | コマンド or アクション 1 個 |
npm ci, npm run build
|
| Runner | 実際にコマンドを動かすマシン |
ubuntu-latest(GitHub 提供) |
Step 2-2 Workflow の分離方針
個人開発ですが、あえてチーム開発を想定した構成にする。
.github/workflows/
├── ci.yml ← PR 作成・更新時に発火(typecheck / lint / build)
└── deploy.yml ← main への push 時に発火(build + deploy)
開発フロー
- feature ブランチを切る (
git checkout -b feature/xxx) - 開発・commit・push (
git push origin feature/xxx) - GitHub で Pull Request 作成
-
ci.ymlが自動実行(typecheck / lint / build) - レビュー(セルフレビューでも OK)
- main へ Merge
-
deploy.ymlが自動実行(本番デプロイ) - 本番反映 🎉
Step 2-3 事前準備:GitHub Variables 登録
Workflow内で使用する変数を GitHub の Settings > Secrets and variables > Actions から登録する
Step 2-4 ci.yml の作成
.github/workflows/ci.yml
name: CI
on:
pull_request:
branches: [main]
jobs:
ci:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: "22"
cache: "npm"
- name: Install dependencies
run: npm ci
- name: Type check
run: npm run typecheck
- name: Lint
run: npm run lint
- name: Build
run: npm run build
env:
NEXT_PUBLIC_API_BASE_URL: ${{ vars.NEXT_PUBLIC_API_BASE_URL }}
Step 2-5 deploy.yml の作成
.github/workflows/deploy.yml
name: Deploy Frontend
on:
push:
branches: [main]
paths:
- "src/**"
- "public/**"
- "package*.json"
- "next.config.*"
- "tsconfig.json"
- ".github/workflows/deploy.yml"
workflow_dispatch:
permissions:
id-token: write
contents: read
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: "22"
cache: "npm"
- name: Install dependencies
run: npm ci
- name: Type check
run: npm run typecheck
- name: Lint
run: npm run lint
- name: Build
run: npm run build
env:
NEXT_PUBLIC_API_BASE_URL: ${{ vars.NEXT_PUBLIC_API_BASE_URL }}
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: ${{ vars.AWS_ROLE_ARN }}
aws-region: ${{ vars.AWS_REGION }}
- name: Deploy to S3
run: aws s3 sync ./out s3://${{ vars.S3_BUCKET }} --delete
- name: Invalidate CloudFront
run: |
aws cloudfront create-invalidation \
--distribution-id ${{ vars.CLOUDFRONT_DISTRIBUTION_ID }} \
--paths "/*"
Step 2-6 動作確認と Node.js バージョンの警告対応
実行時に以下のような警告が出た
Node.js 20 actions are deprecated. The following actions are running on Node.js 20...
- 強制移行: 2026/6/2
- Node 20 削除: 2026/9/16
これは、GitHub Actions のランナー上で Action 自体が動く Node.js のバージョン(≠ ビルドで使う Node 22)が、Node 20 → Node 24 に移行するという予告。
| Action | 状況 |
|---|---|
actions/checkout@v5 |
✅ Node 24 対応、警告消えた |
actions/setup-node@v5 |
✅ Node 24 対応、警告消えた |
aws-actions/configure-aws-credentials@v5 |
❌ まだ Node 20、警告残った |
aws-actions/configure-aws-credentials などは、メジャーバージョンを上げても内部のランタイム宣言が Node 20 のままである場合がある。
🛠 解決策:環境変数で Node 24 を強制する
両 workflow の jobs.X: 直下に環境変数を追加して対応する。
jobs:
deploy:
runs-on: ubuntu-latest
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true" # ← 追加
steps:
# ... 以降の処理
Step 2-7 ブランチ保護ルールの設計
- ブランチを切る
- 変更を commit
- PR 作成 →
ci.ymlが走る - PR をオープンのまま、GitHubリポジトリの Settings > Branches から保護ルール(Branch protection rules)を設定
- Require status checks to pass before merging を有効にし、ステータスチェック候補から
ciを登録 - PR を merge
-
deploy.ymlが main で発火 → 本番反映
本番反映確認
最後に、実際にデプロイされたURLにアクセスして反映を確認する
Discussion