- Authors
- Name
- はじめに
- Matrix Strategy:並列ビルドの力
- Cache:ビルド速度の最適化
- Self-hosted Runner:カスタム環境の構築
- 実践統合例:モノレポCI/CD
- セキュリティベストプラクティス
- まとめ
- クイズ

はじめに
GitHub Actionsは、今やCI/CDのデファクトスタンダードです。基本的なビルド/テストパイプラインは誰でも作れますが、Matrix Strategy、Cache、Self-hosted Runnerを適切に活用すれば、ビルド時間を半分以下に短縮し、コストも大幅に削減できます。
本記事では、実務ですぐに適用できる上級CI/CDパターンを解説します。
Matrix Strategy:並列ビルドの力
基本的なMatrix構成
Matrixを使用すると、複数の環境の組み合わせを自動的に並列実行します:
name: CI
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [18, 20, 22]
os: [ubuntu-latest, macos-latest]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
- run: npm ci
- run: npm test
この設定は3(Nodeバージョン)× 2(OS)= 6つの並列Jobを生成します。
上級Matrix:includeとexclude
特定の組み合わせのみを追加または除外できます:
strategy:
fail-fast: false # 1つが失敗しても残りは継続実行
max-parallel: 4 # 同時実行最大4つ
matrix:
node-version: [18, 20, 22]
os: [ubuntu-latest, macos-latest, windows-latest]
exclude:
# Node 18 + Windowsの組み合わせを除外
- node-version: 18
os: windows-latest
include:
# 特定の組み合わせにのみ追加変数を設定
- node-version: 22
os: ubuntu-latest
coverage: true
動的Matrix生成
ビルド時にMatrixを動的に決定するパターン:
jobs:
prepare:
runs-on: ubuntu-latest
outputs:
matrix: ${{ steps.set-matrix.outputs.matrix }}
steps:
- uses: actions/checkout@v4
- id: set-matrix
run: |
# 変更されたパッケージのみをビルド対象に設定
CHANGED=$(git diff --name-only HEAD~1 | grep "^packages/" | cut -d/ -f2 | sort -u | jq -R . | jq -s .)
echo "matrix={\"package\":$CHANGED}" >> $GITHUB_OUTPUT
build:
needs: prepare
runs-on: ubuntu-latest
strategy:
matrix: ${{ fromJson(needs.prepare.outputs.matrix) }}
steps:
- uses: actions/checkout@v4
- run: npm run build --workspace=packages/${{ matrix.package }}
Cache:ビルド速度の最適化
依存関係キャッシュの基本
- uses: actions/cache@v4
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-
setup-* アクションの組み込みキャッシュ
ほとんどのsetupアクションにはキャッシュが組み込まれています:
# Node.js - 組み込みキャッシュ
- uses: actions/setup-node@v4
with:
node-version: 22
cache: 'npm'
# Python - pipキャッシュ
- uses: actions/setup-python@v5
with:
python-version: '3.12'
cache: 'pip'
# Go - モジュールキャッシュ
- uses: actions/setup-go@v5
with:
go-version: '1.22'
cache: true
Dockerレイヤーキャッシュ
DockerビルドでGitHub Actions Cacheを活用すると、劇的な速度向上が可能です:
- uses: docker/build-push-action@v6
with:
context: .
push: true
tags: myapp:latest
cache-from: type=gha
cache-to: type=gha,mode=max
キャッシュ戦略の比較
| キャッシュ方式 | メリット | デメリット |
|---|---|---|
actions/cache | 汎用、あらゆるパスをキャッシュ可能 | 手動キー管理が必要 |
| setup-* 組み込みキャッシュ | 設定が簡単、自動キー生成 | 該当ツールのみ対応 |
| Docker GHAキャッシュ | レイヤー単位のキャッシュ、非常に高速 | Dockerビルド専用 |
Self-hosted Runner:カスタム環境の構築
なぜSelf-hosted Runnerなのか?
GitHub-hosted Runnerの制限事項:
- コスト:大規模プロジェクトでの分単位課金の負担
- スペック制限:最大7GB RAM、14GB SSD(Standard)
- ネットワーク:内部ネットワークへのアクセス不可
- GPU非対応:ML/AIワークロード不可
Runnerのインストールと登録
# LinuxにRunnerをインストール
mkdir actions-runner && cd actions-runner
curl -o actions-runner-linux-x64-2.321.0.tar.gz -L \
https://github.com/actions/runner/releases/download/v2.321.0/actions-runner-linux-x64-2.321.0.tar.gz
tar xzf ./actions-runner-linux-x64-2.321.0.tar.gz
# Runnerの登録
./config.sh --url https://github.com/YOUR_ORG/YOUR_REPO \
--token YOUR_TOKEN \
--labels gpu,linux,x64 \
--name my-gpu-runner
# systemdサービスとして登録
sudo ./svc.sh install
sudo ./svc.sh start
WorkflowでSelf-hosted Runnerを使用
jobs:
gpu-test:
runs-on: [self-hosted, gpu, linux]
steps:
- uses: actions/checkout@v4
- name: GPUテスト実行
run: |
nvidia-smi
python -m pytest tests/gpu/ -v
deploy:
runs-on: [self-hosted, linux]
needs: gpu-test
steps:
- name: 内部ネットワークへデプロイ
run: |
kubectl apply -f k8s/
kubectl rollout status deployment/myapp
RunnerをKubernetesで運用する
Actions Runner Controller(ARC)を使用すると、RunnerをPodとして自動スケーリングできます:
# ARCのインストール(Helm)
helm install arc \
--namespace arc-systems \
--create-namespace \
oci://ghcr.io/actions/actions-runner-controller-charts/gha-runner-scale-set-controller
# Runner Scale Setのデプロイ
helm install arc-runner-set \
--namespace arc-runners \
--create-namespace \
-f values.yaml \
oci://ghcr.io/actions/actions-runner-controller-charts/gha-runner-scale-set
values.yaml の例:
githubConfigUrl: 'https://github.com/YOUR_ORG'
githubConfigSecret:
github_token: 'ghp_xxxxx'
maxRunners: 10
minRunners: 1
template:
spec:
containers:
- name: runner
image: ghcr.io/actions/actions-runner:latest
resources:
requests:
cpu: '2'
memory: '4Gi'
limits:
cpu: '4'
memory: '8Gi'
実践統合例:モノレポCI/CD
すべての上級機能を組み合わせた実践パイプライン:
name: Monorepo CI/CD
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
detect-changes:
runs-on: ubuntu-latest
outputs:
services: ${{ steps.changes.outputs.services }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- id: changes
run: |
SERVICES=$(git diff --name-only ${{ github.event.before }} ${{ github.sha }} \
| grep "^services/" | cut -d/ -f2 | sort -u \
| jq -R . | jq -s .)
echo "services=$SERVICES" >> $GITHUB_OUTPUT
build-and-test:
needs: detect-changes
if: needs.detect-changes.outputs.services != '[]'
runs-on: [self-hosted, linux]
strategy:
fail-fast: false
matrix:
service: ${{ fromJson(needs.detect-changes.outputs.services) }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22
cache: 'npm'
- name: Install & Build
run: |
npm ci
npm run build -w services/${{ matrix.service }}
- name: Test
run: npm run test -w services/${{ matrix.service }}
- name: Docker Build & Push
if: github.ref == 'refs/heads/main'
uses: docker/build-push-action@v6
with:
context: ./services/${{ matrix.service }}
push: true
tags: |
ghcr.io/${{ github.repository }}/${{ matrix.service }}:${{ github.sha }}
ghcr.io/${{ github.repository }}/${{ matrix.service }}:latest
cache-from: type=gha,scope=${{ matrix.service }}
cache-to: type=gha,scope=${{ matrix.service }},mode=max
deploy:
needs: build-and-test
if: github.ref == 'refs/heads/main'
runs-on: [self-hosted, linux]
strategy:
max-parallel: 1 # 順次デプロイ
matrix:
service: ${{ fromJson(needs.detect-changes.outputs.services) }}
steps:
- uses: actions/checkout@v4
- name: Deploy to Kubernetes
run: |
kubectl set image deployment/${{ matrix.service }} \
app=ghcr.io/${{ github.repository }}/${{ matrix.service }}:${{ github.sha }}
kubectl rollout status deployment/${{ matrix.service }} --timeout=300s
セキュリティベストプラクティス
シークレット管理
# Environmentで分離
jobs:
deploy:
runs-on: ubuntu-latest
environment: production # 承認が必要な環境
steps:
- name: Deploy
env:
DB_PASSWORD: ${{ secrets.DB_PASSWORD }}
run: ./deploy.sh
OIDCによるクラウド認証(シークレット不要)
permissions:
id-token: write
contents: read
steps:
- uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::123456789:role/github-actions
aws-region: ap-northeast-2
まとめ
GitHub Actionsの上級機能を適切に活用すれば、CI/CDパイプラインの速度、コスト、柔軟性のすべてを改善できます。Matrixで並列ビルド、Cacheで速度最適化、Self-hosted Runnerでカスタム環境まで――この3つを組み合わせれば、エンタープライズグレードのパイプラインを構築できます。
クイズ
Q1:Matrix Strategyで3つのNodeバージョン × 2つのOSの組み合わせを設定すると、何個のJobが生成されますか?
6個。Matrixはすべての組み合わせのデカルト積を生成します。3 × 2 = 6つの並列Job。
Q2:Matrixでfail-fast: falseの意味は?
1つのJobが失敗しても、残りのJobを中断せずに継続実行します。デフォルトはtrueで、1つでも失敗すると全体がキャンセルされます。
Q3:actions/cacheのkeyにhashFilesを使用する理由は?
package-lock.jsonなどの依存関係ファイルのハッシュ値をキーとして使用することで、依存関係が変更された場合のみキャッシュを更新し、変更がなければ既存のキャッシュを再利用するためです。
Q4:Dockerビルドでcache-from: type=ghaは何を意味しますか?
GitHub Actionsのキャッシュバックエンドを、Dockerビルドレイヤーキャッシュとして使用するという意味です。別途レジストリなしでビルドキャッシュを保存・復元できます。
Q5:Self-hosted RunnerをKubernetesで自動スケーリングするにはどのツールを使用しますか?
Actions Runner Controller(ARC)。Helmでインストールし、RunnerをPodとして管理し、ワークロードに応じて自動スケーリングします。
Q6:動的Matrixを生成するにはどのパターンを使用しますか?
最初のJobでoutputsとしてJSON配列を出力し、2番目のJobでfromJson()でパースしてmatrixに渡すパターンです。
Q7:OIDCを使用したクラウド認証のメリットは?
長期シークレット(Access Key)を保存する必要がなく、GitHub Actionsが発行する一時トークンでクラウドに認証します。シークレット漏洩のリスクがなく、自動的に期限切れになります。
Q8:モノレポで変更されたサービスのみをビルドするための核心的な技法は?
git diffで変更されたファイルパスを分析して影響を受けるサービスのリストを抽出し、これを動的Matrixとして渡して該当サービスのみをビルドします。