GitHub ActionsとCI/CD - Git & GitHub コラボレーションマスター 第5編
GitHub Actions and CI/CD - Master Git & GitHub Collaboration Part 5
はじめに: なぜCI/CDが必要なのか?
プロジェクトを進めていると、コードを修正するたびにテストを実行し、ビルドし、デプロイするという過程を繰り返す必要があります。一人で開発する時はまだ大丈夫ですが、チームで作業するとこの過程がかなり面倒になります。「私のパソコンではうまくいくのに?」という言葉を一度でも言ったことがあるなら、おそらくCI/CDの必要性を感じているはずです。
今日はGit & GitHub コラボレーションマスターシリーズの第5編として、GitHub Actionsを活用したCI/CDについて深く掘り下げていきます。初めて触れる方も理解できるように基礎から始めて、実際にプロジェクトにすぐ適用できる実践的なワークフローまで一緒に作っていきましょう。
1. CI/CDとは
1.1 CI (Continuous Integration) - 継続的インテグレーション
CIは開発者がコード変更を頻繁に、そして定期的にメインブランチに統合する開発方式です。単にコードをマージするだけでなく、統合するたびに自動的にビルドしてテストを実行し、問題がないか確認します。
例を挙げてみましょう。3人の開発者がそれぞれ異なる機能を開発しているとします。CIがなければ、それぞれが数週間別々に開発した後、一度にまとめようとした時に莫大なコンフリクトが発生する可能性があります。しかしCIを適用すれば、毎日、いや1日に何度もコードを統合して自動的に検証するため、問題を早期に発見して解決できます。
1.2 CD (Continuous Delivery/Deployment) - 継続的デリバリー/デプロイ
CDは2つの意味で使用されます。Continuous Deliveryはコード変更が自動的にテストを経てデプロイ可能な状態に準備されることを指し、Continuous Deploymentはさらに一歩進んでプロダクション環境まで自動的にデプロイされることを意味します。
まとめるとこうなります:
- Continuous Delivery: コードがいつでもデプロイできる状態に自動準備される (デプロイボタンは人が押す)
- Continuous Deployment: すべてのテストに通過すれば自動的にプロダクションにデプロイされる
1.3 CI/CDの実際のメリット
私が実際にCI/CDを導入した時に感じた最大の変化は「デプロイへの恐怖がなくなった」ということです。以前は金曜日の午後にデプロイすることを避けていました。問題が起きれば週末に苦労しなければならないからです。しかし自動化されたテストとデプロイパイプラインが整備されると、いつでも自信を持ってデプロイできるようになりました。
2. GitHub Actions紹介
2.1 GitHub Actionsとは?
GitHub ActionsはGitHubが直接提供するCI/CDプラットフォームです。2019年に正式リリースされて以来、急速に成長し、今では最も人気のあるCI/CDツールの1つになりました。GitHubリポジトリと完璧に統合されているため、別途の外部サービス設定なしにすぐ使用できることが最大の利点です。
GitHub Actionsの核心的な特徴をまとめると:
- GitHubネイティブ: 別途のサービス連携なしにリポジトリですぐ使用可能
- YAMLベース設定: 理解しやすい宣言的構文
- マーケットプレイス: 数千個の既製アクションを再利用可能
- 無料使用量: パブリックリポジトリは無制限、プライベートも月2,000分無料
- 多様なランナー: Linux、Windows、macOS環境すべてサポート
2.2 他のCI/CDツールとの比較
Jenkins、CircleCI、Travis CIなど他のCI/CDツールもあります。それぞれ長所短所がありますが、GitHubを主に使用するならGitHub Actionsを選択することがほとんどの場合良い選択です。設定が簡単で、追加のインフラ構築が必要なく、GitHubのイベント(Push、PRなど)と自然に連携するからです。
3. Workflowファイル構造の理解
3.1 ワークフローファイルの場所
GitHub Actionsのワークフローファイルはリポジトリの .github/workflows/ ディレクトリに配置されます。このディレクトリにYAMLファイルを作成するとGitHubが自動的に認識して実行します。
my-project/
├── .github/
│ └── workflows/
│ ├── ci.yml
│ ├── deploy.yml
│ └── test.yml
├── src/
├── tests/
└── package.json
3.2 ワークフローの構成要素
ワークフローは次のような階層構造を持ちます:
- Workflow (ワークフロー): 自動化された全体プロセス、1つのYAMLファイルで定義
- Event (イベント): ワークフローを開始させるトリガー
- Job (ジョブ): 同じランナーで実行されるステップの集まり
- Step (ステップ): 個別の作業単位、シェルコマンドやアクションを実行
- Action (アクション): 再利用可能な作業単位
4. 基本構文マスター
4.1 name - ワークフロー名
ワークフローの名前を指定します。GitHub Actionsタブで表示される名前なので、わかりやすく記述してください。
name: CI Pipeline
4.2 on - イベントトリガー
ワークフローがいつ実行されるかを定義します。最もよく使用されるイベントを見てみましょう。
# Pushイベント
on:
push:
branches: [ main, develop ]
paths:
- 'src/**'
- '!src/**/*.md'
# Pull Requestイベント
on:
pull_request:
branches: [ main ]
types: [ opened, synchronize, reopened ]
# スケジュール (cron構文)
on:
schedule:
- cron: '0 9 * * 1' # 毎週月曜日午前9時 (UTC)
# 手動実行
on:
workflow_dispatch:
inputs:
environment:
description: 'デプロイ環境選択'
required: true
default: 'staging'
type: choice
options:
- staging
- production
4.3 jobs - ジョブ定義
実際に実行するジョブを定義します。複数のジョブを定義でき、デフォルトでは並列で実行されます。
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: コードチェックアウト
uses: actions/checkout@v4
- name: Node.js設定
uses: actions/setup-node@v4
with:
node-version: '20'
- name: 依存関係インストール
run: npm ci
- name: ビルド
run: npm run build
4.4 runs-on - ランナー環境指定
ジョブが実行される仮想環境を指定します。GitHubがホスティングするランナーを使用するか、セルフホスティングランナーを使用できます。
# GitHubホスティングランナー
runs-on: ubuntu-latest
runs-on: ubuntu-22.04
runs-on: windows-latest
runs-on: macos-latest
# セルフホスティングランナー
runs-on: self-hosted
4.5 usesとrun - ステップ実行
usesは既製のアクションを使用する時、runはシェルコマンドを直接実行する時に使用します。
steps:
# アクション使用
- name: コードチェックアウト
uses: actions/checkout@v4
# シェルコマンド実行
- name: テスト実行
run: npm test
# 複数行コマンド
- name: ビルドおよびデプロイ
run: |
npm run build
npm run deploy
5. よく使うアクション
5.1 actions/checkout
最も基本的なアクションで、リポジトリのコードをワークフロー環境にチェックアウトします。ほぼすべてのワークフローで最初のステップとして使用されます。
- uses: actions/checkout@v4
with:
fetch-depth: 0 # 全履歴を取得 (タグ、ブランチ情報が必要な場合)
ref: ${{ github.head_ref }} # 特定ブランチをチェックアウト
5.2 actions/setup-node
Node.js環境を設定します。バージョン指定とキャッシュ設定を同時に行えます。
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm' # 自動でnode_modulesをキャッシュ
registry-url: 'https://registry.npmjs.org' # npm公開時に必要
5.3 actions/cache
依存関係やビルド成果物をキャッシュしてワークフロー実行時間を短縮します。
- name: キャッシュ復元
uses: actions/cache@v4
with:
path: |
~/.npm
node_modules
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-
5.4 その他の便利なアクション
# Python設定
- uses: actions/setup-python@v5
with:
python-version: '3.11'
cache: 'pip'
# Java設定
- uses: actions/setup-java@v4
with:
distribution: 'temurin'
java-version: '17'
# Dockerビルドおよびプッシュ
- uses: docker/build-push-action@v5
with:
context: .
push: true
tags: user/app:latest
6. テスト自動化の実装
6.1 基本テストワークフロー
PRが作成または更新された時に自動的にテストを実行するワークフローです。
name: Test
on:
pull_request:
branches: [ main, develop ]
push:
branches: [ main ]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Node.js設定
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- name: 依存関係インストール
run: npm ci
- name: Lint検査
run: npm run lint
- name: 型検査
run: npm run type-check
- name: ユニットテスト
run: npm test -- --coverage
- name: テストカバレッジレポート
uses: codecov/codecov-action@v3
with:
files: ./coverage/lcov.info
6.2 テスト結果レポート
テスト結果をPRにコメントとして残すと、レビュアーが素早く確認できます。
- name: テスト結果レポート
uses: dorny/test-reporter@v1
if: success() || failure()
with:
name: Jest Tests
path: junit.xml
reporter: jest-junit
7. デプロイ自動化
7.1 GitHub Pagesデプロイ
静的サイトをGitHub Pagesに自動デプロイするワークフローです。
name: Deploy to GitHub Pages
on:
push:
branches: [ main ]
permissions:
contents: read
pages: write
id-token: write
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Node.js設定
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- name: ビルド
run: |
npm ci
npm run build
- name: Pagesアーティファクトアップロード
uses: actions/upload-pages-artifact@v3
with:
path: ./dist
deploy:
needs: build
runs-on: ubuntu-latest
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
steps:
- name: GitHub Pagesデプロイ
id: deployment
uses: actions/deploy-pages@v4
7.2 Vercelデプロイ
Vercelへの自動デプロイ設定です。PreviewとProduction環境を区別してデプロイできます。
name: Deploy to Vercel
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
env:
VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }}
VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }}
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Vercel CLIインストール
run: npm install -g vercel@latest
- name: Vercelプロジェクト情報取得
run: vercel pull --yes --environment=preview --token=${{ secrets.VERCEL_TOKEN }}
- name: ビルド
run: vercel build --token=${{ secrets.VERCEL_TOKEN }}
- name: プロダクションデプロイ
if: github.ref == 'refs/heads/main'
run: vercel deploy --prebuilt --prod --token=${{ secrets.VERCEL_TOKEN }}
7.3 AWS S3 + CloudFrontデプロイ
name: Deploy to AWS
on:
push:
branches: [ main ]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Node.js設定
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- name: ビルド
run: |
npm ci
npm run build
- name: AWS認証情報設定
uses: aws-actions/configure-aws-credentials@v4
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ap-northeast-2
- name: S3にアップロード
run: aws s3 sync ./dist s3://${{ secrets.S3_BUCKET }} --delete
- name: CloudFrontキャッシュ無効化
run: |
aws cloudfront create-invalidation \
--distribution-id ${{ secrets.CLOUDFRONT_DISTRIBUTION_ID }} \
--paths "/*"
8. Secrets管理
8.1 Secrets設定方法
APIキー、トークンなどの機密情報は絶対にコードに直接書いてはいけません。GitHub Secretsを使用して安全に管理してください。
設定方法:
- リポジトリSettingsに移動
- 左メニューから「Secrets and variables」 -> 「Actions」を選択
- 「New repository secret」をクリック
- 名前と値を入力して保存
8.2 Secrets使用例
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: デプロイ
env:
API_KEY: ${{ secrets.API_KEY }}
DATABASE_URL: ${{ secrets.DATABASE_URL }}
run: |
echo "APIキーが設定されました"
npm run deploy
8.3 環境別Secrets管理
Environments機能を活用すると、staging、productionなど環境別に異なるsecretsを管理できます。
jobs:
deploy-staging:
runs-on: ubuntu-latest
environment: staging
steps:
- name: ステージングデプロイ
run: deploy --env staging
env:
API_URL: ${{ secrets.API_URL }} # staging環境のAPI_URL
deploy-production:
needs: deploy-staging
runs-on: ubuntu-latest
environment: production
steps:
- name: プロダクションデプロイ
run: deploy --env production
env:
API_URL: ${{ secrets.API_URL }} # production環境のAPI_URL
9. Matrixビルド
9.1 Matrix戦略とは?
Matrixビルドを使用すると、複数の環境(OS、言語バージョンなど)で同時にテストを実行できます。例えばNode.js 18、20、22バージョンですべてテストしたい場合、それぞれ別のジョブを作成する必要なくmatrixで定義すればよいです。
name: Cross-version Test
on: [push, pull_request]
jobs:
test:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
node-version: [18, 20, 22]
exclude:
- os: windows-latest
node-version: 18
fail-fast: false # 1つが失敗しても残りは継続実行
steps:
- uses: actions/checkout@v4
- name: Node.js ${{ matrix.node-version }} 設定
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
- run: npm ci
- run: npm test
9.2 動的Matrix
JSONを活用して動的にmatrixを構成することもできます。
jobs:
setup:
runs-on: ubuntu-latest
outputs:
matrix: ${{ steps.set-matrix.outputs.matrix }}
steps:
- id: set-matrix
run: echo "matrix={\"include\":[{\"project\":\"api\"},{\"project\":\"web\"}]}" >> $GITHUB_OUTPUT
build:
needs: setup
runs-on: ubuntu-latest
strategy:
matrix: ${{ fromJSON(needs.setup.outputs.matrix) }}
steps:
- run: echo "Building ${{ matrix.project }}"
10. 実践ワークフロー例
10.1 完全なCIパイプライン
name: CI
on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main ]
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- run: npm ci
- run: npm run lint
type-check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- run: npm ci
- run: npm run type-check
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- run: npm ci
- run: npm test -- --coverage
- uses: codecov/codecov-action@v3
build:
needs: [lint, type-check, test]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- run: npm ci
- run: npm run build
- uses: actions/upload-artifact@v4
with:
name: build
path: dist/
10.2 自動リリースワークフロー
name: Release
on:
push:
tags:
- 'v*'
jobs:
release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: actions/setup-node@v4
with:
node-version: '20'
registry-url: 'https://registry.npmjs.org'
- run: npm ci
- run: npm run build
- run: npm publish
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
- name: リリースノート生成
uses: softprops/action-gh-release@v1
with:
generate_release_notes: true
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
10.3 PR自動ラベリング
name: PR Labeler
on:
pull_request:
types: [opened, synchronize]
jobs:
label:
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: write
steps:
- uses: actions/labeler@v5
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
10.4 スケジュールベースのセキュリティチェック
name: Security Check
on:
schedule:
- cron: '0 9 * * 1' # 毎週月曜日午前9時 (UTC)
workflow_dispatch:
jobs:
audit:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
- name: 依存関係セキュリティチェック
run: npm audit --audit-level=high
- name: 依存関係アップデート確認
run: npm outdated || true
- name: Snykセキュリティスキャン
uses: snyk/actions/node@master
env:
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
まとめ: CI/CDで開発生産性を高める
今回はGitHub Actionsを活用したCI/CDパイプライン構築について見てきました。最初は設定ファイルの作成が複雑に感じるかもしれませんが、一度構築しておけば、その後は自動化の恩恵を継続的に受けることができます。
重要なのは、最初から完璧なパイプラインを作ろうとしないことです。簡単なテスト自動化から始めて、徐々に拡張していきましょう。私も最初は単にnpm testだけを実行するワークフローから始めて、必要に応じてリント、型チェック、デプロイ自動化などを1つずつ追加していきました。
次の第6編ではオープンソースへの貢献について扱います。Fork、PRワークフロー、コントリビューションガイドラインなど、実際にオープンソースプロジェクトに貢献する方法を詳しく見ていきましょう。