GitHub ActionsでCI/CDパイプラインを構築する

GitHub Actionsを使えば、コードのビルド・テスト・デプロイまでを自動化できるCI/CDパイプラインをわずか数分で構築できます。リポジトリに`.github/workflows/`ディレクトリを作成し、YAMLファイルを配置するだけで、プッシュやプルリクエストをトリガーに自動実行される仕組みを実現します。この記事では、実務で使える実践的なCI/CDパイプラインの設計から、具体的なワークフローの実装、セキュリティ設定、パフォーマンス最適化までを網羅的に解説します。
目次
- はじめに:CI/CDとGitHub Actionsの基礎
- GitHub Actionsの環境設定と基本概念
- 実践的なCI/CDパイプラインの設計手法
- 具体的なCI/CDパイプラインの実装例
- GitHub Actionsの高度な機能活用術
- セキュリティベストプラクティス
- トラブルシューティングとデバッグ
- まとめ:実務で使えるGitHub Actions活用術
はじめに:CI/CDとGitHub Actionsの基礎
CI/CD(Continuous Integration/Continuous Delivery)は、ソフトウェア開発の自動化を実現する手法です。GitHub Actionsは、GitHubリポジトリに統合されたCI/CDプラットフォームで、コードの変更をトリガーにビルド・テスト・デプロイを自動化できます。2023年のGitHub公式統計によると、GitHub Actionsを利用するリポジトリは月間1,000万件を超え、CI/CD市場シェアの30%を獲得しています。
GitHub Actionsの最大の特徴は、GitHubリポジトリとの緊密な統合です。プッシュやプルリクエスト、issueの作成など、GitHub上のあらゆるイベントをトリガーにワークフローを実行できます。また、GitHub Marketplaceから10,000以上のアクションを利用できるため、ゼロからコードを書かずとも、一般的なタスクを自動化できます。
本記事では、GitHub Actionsを使ったCI/CDパイプラインの構築方法を、実務で使えるレベルまで掘り下げて解説します。具体的には、以下のようなシナリオを想定しています。
- Node.js/Python/DockerプロジェクトのCI/CDパイプライン
- AWS(EC2/S3/Lambda)への自動デプロイ
- セキュリティ設定とベストプラクティス
- パフォーマンス最適化とトラブルシューティング
GitHub Actionsの環境設定と基本概念
GitHub Actionsの有効化
GitHub Actionsは、GitHubリポジトリで自動的に有効化されています。ただし、GitHub Enterprise Cloudを利用している場合は、管理者が有効化する必要があります。有効化されていない場合は、リポジトリの「Settings」→「Actions」→「General」から有効化できます。
GitHub Actionsの基本用語
GitHub Actionsには、以下のような基本用語があります。
| 用語 | 説明 |
|---|---|
| ワークフロー(Workflow) | YAMLファイルで定義された、一連のジョブとステップの集まり。`.github/workflows/`ディレクトリに配置します。 |
| ジョブ(Job) | ワークフロー内で実行される一連のステップ。複数のジョブを定義でき、依存関係を設定できます。 |
| ステップ(Step) | ジョブ内で実行される個々のタスク。コマンドの実行やアクションの呼び出しを行います。 |
| アクション(Action) | GitHub Marketplaceから利用できる、再利用可能なタスク。例えば、`actions/checkout`はリポジトリのコードをチェックアウトします。 |
| ランナー(Runner) | ワークフローを実行する仮想マシンまたはコンテナ。GitHub-hostedランナーとself-hostedランナーがあります。 |
| イベント(Event) | ワークフローをトリガーするGitHub上のイベント。例えば、`push`、`pull_request`、`issue_comment`などです。 |
ランナーの選択
GitHub Actionsは、GitHub-hostedランナーとself-hostedランナーを提供しています。GitHub-hostedランナーは、GitHubが管理する仮想マシンで、以下のようなOSが利用できます。
- Ubuntu(最新版、LTS版)
- Windows(Server 2022、2019)
- macOS(最新版)
GitHub-hostedランナーは、無料枠で月間2,000分(Linux/Windows)または500分(macOS)の実行時間が提供されています。self-hostedランナーは、独自のサーバーやクラウドインスタンスで実行でき、カスタムの環境を構築できます。
ランナーの選択は、以下のような要素を考慮して決定します。
- OSの互換性(例:Windows固有のソフトウェアを利用する場合)
- 実行時間の制限(GitHub-hostedランナーの無料枠を超える場合)
- セキュリティ要件(self-hostedランナーで専用のネットワークに配置する場合)
GitHub Actionsの料金体系
GitHub Actionsの料金は、GitHubのプランによって異なります。GitHub Freeプランでは、以下のような制限があります。
| リソース | GitHub Free | GitHub Pro | GitHub Team | GitHub Enterprise |
|---|---|---|---|---|
| 月間実行時間(Linux/Windows) | 2,000分 | 3,000分 | 3,000分 | 50,000分 |
| 月間実行時間(macOS) | 500分 | 500分 | 500分 | 50,000分 |
| ストレージ | 500MB | 1GB | 2GB | 50GB |
GitHub Actionsの料金は、GitHubのプランに含まれています。GitHub Freeプランでも、個人プロジェクトや小規模なチームであれば十分に利用できます。
実践的なCI/CDパイプラインの設計手法
基本的なワークフロー構造
GitHub Actionsのワークフローは、YAML形式で定義します。以下は、基本的なCI/CDパイプラインの構造です。
name: CI/CD Pipeline
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install dependencies
run: npm install
- name: Run tests
run: npm test
- name: Build
run: npm run build
deploy:
needs: build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Deploy to AWS S3
run: aws s3 sync dist/ s3://my-bucket
このワークフローは、以下のような流れで実行されます。
pushまたはpull_requestイベントが発生すると、ワークフローが実行されます。buildジョブが実行され、依存関係のインストール・テスト・ビルドが行われます。deployジョブがbuildジョブの完了後に実行され、ビルド成果物をAWS S3にデプロイします。
ジョブ間の依存関係と並列実行
GitHub Actionsでは、ジョブ間の依存関係をneedsキーワードで定義できます。これにより、ジョブの実行順序を制御できます。また、strategyキーワードを使うことで、ジョブを並列実行したり、異なる環境で実行したりできます。
以下は、ジョブの依存関係と並列実行の例です。
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [16.x, 18.x, 20.x]
steps:
- uses: actions/checkout@v4
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
- name: Install dependencies
run: npm install
- name: Run tests
run: npm test
deploy:
needs: test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Deploy to AWS S3
run: aws s3 sync dist/ s3://my-bucket
このワークフローでは、testジョブがNode.jsの異なるバージョン(16.x、18.x、20.x)で並列実行され、すべてのテストが完了した後にdeployジョブが実行されます。
条件分岐と環境変数
GitHub Actionsでは、ifキーワードを使って条件分岐を実装できます。また、envキーワードで環境変数を定義できます。
以下は、条件分岐と環境変数の例です。
jobs:
deploy:
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
env:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
steps:
- uses: actions/checkout@v4
- name: Deploy to AWS S3
run: aws s3 sync dist/ s3://my-bucket
このワークフローでは、deployジョブはmainブランチにプッシュされた場合にのみ実行されます。また、AWSの認証情報はGitHubのシークレットから取得されます。
具体的なCI/CDパイプラインの実装例
Node.jsプロジェクトのCI/CD
Node.jsプロジェクトのCI/CDパイプラインでは、以下のようなステップを実装します。
- 依存関係のインストール
- テストの実行
- ビルドの実行
- デプロイ(例:AWS S3、Vercel、Heroku)
以下は、Node.jsプロジェクトのCI/CDパイプラインの例です。
name: Node.js CI/CD Pipeline
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Use Node.js
uses: actions/setup-node@v4
with:
node-version: 20.x
- name: Install dependencies
run: npm install
- name: Run tests
run: npm test
build:
needs: test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Use Node.js
uses: actions/setup-node@v4
with:
node-version: 20.x
- name: Install dependencies
run: npm install
- name: Build
run: npm run build
deploy:
needs: build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Deploy to Vercel
run: npx vercel --prod --token ${{ secrets.VERCEL_TOKEN }}
このワークフローでは、以下のような流れで実行されます。
testジョブで依存関係のインストールとテストが実行されます。buildジョブでビルドが実行されます。deployジョブでVercelへのデプロイが実行されます。
PythonプロジェクトのCI/CD
PythonプロジェクトのCI/CDパイプラインでは、以下のようなステップを実装します。
- 依存関係のインストール(
pip install) - テストの実行(
pytest) - ビルドの実行(
python setup.py sdist) - デプロイ(例:PyPI、AWS Lambda)
以下は、PythonプロジェクトのCI/CDパイプラインの例です。
name: Python CI/CD Pipeline
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Install dependencies
run: pip install -r requirements.txt
- name: Run tests
run: pytest
build:
needs: test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Install dependencies
run: pip install -r requirements.txt
- name: Build package
run: python setup.py sdist
deploy:
needs: build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Install dependencies
run: pip install -r requirements.txt
- name: Deploy to PyPI
run: twine upload dist/*
env:
TWINE_USERNAME: ${{ secrets.PYPI_USERNAME }}
TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }}
このワークフローでは、以下のような流れで実行されます。
testジョブで依存関係のインストールとテストが実行されます。buildジョブでパッケージのビルドが実行されます。deployジョブでPyPIへのデプロイが実行されます。
Dockerイメージのビルドとデプロイ
Dockerイメージのビルドとデプロイでは、以下のようなステップを実装します。
- Dockerfileを使ったイメージのビルド
- Docker HubやAmazon ECRへのプッシュ
- KubernetesやECSへのデプロイ
以下は、Dockerイメージのビルドとデプロイの例です。
name: Docker CI/CD Pipeline
on:
push:
branches: [ main ]
jobs:
build-and-push:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Login to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_HUB_USERNAME }}
password: ${{ secrets.DOCKER_HUB_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v5
with:
push: true
tags: my-docker-username/my-repo:latest
このワークフローでは、以下のような流れで実行されます。
- Docker Hubへのログイン
- Dockerイメージのビルドとプッシュ
DockerイメージをKubernetesやECSにデプロイする場合は、以下のようなステップを追加します。
deploy:
needs: build-and-push
runs-on: ubuntu-latest
steps:
- name: Deploy to Kubernetes
run: kubectl apply -f k8s/deployment.yaml
env:
KUBE_CONFIG: ${{ secrets.KUBE_CONFIG }}
AWSへの自動デプロイ(EC2/S3/Lambda)
AWSへの自動デプロイでは、以下のようなサービスを対象にできます。
- EC2:インスタンスへのデプロイ
- S3:静的ファイルのアップロード
- Lambda:関数のデプロイ
- ECS/EKS:コンテナのデプロイ
以下は、AWS S3への自動デプロイの例です。
name: AWS S3 Deploy
on:
push:
branches: [ main ]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Configure AWS Credentials
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: us-east-1
- name: Deploy to S3
run: aws s3 sync dist/ s3://my-bucket
以下は、AWS Lambdaへの自動デプロイの例です。
name: AWS Lambda Deploy
on:
push:
branches: [ main ]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Configure AWS Credentials
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: us-east-1
- name: Deploy to Lambda
run: |
zip -r function.zip .
aws lambda update-function-code \
--function-name my-function \
--zip-file fileb://function.zip
GitHub Actionsの高度な機能活用術
再利用可能なワークフローとカスタムアクション
GitHub Actionsでは、再利用可能なワークフローとカスタムアクションを作成できます。再利用可能なワークフローは、複数のリポジトリで共通のワークフローを実行する場合に便利です。カスタムアクションは、独自のタスクを実行するための再利用可能なコンポーネントです。
再利用可能なワークフロー
再利用可能なワークフローは、workflow_callイベントを使って定義します。以下は、再利用可能なワークフローの例です。
name: Reusable Workflow
on:
workflow_call:
inputs:
node-version:
description: 'Node.js version'
required: true
type: string
secrets:
npm-token:
required: true
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Use Node.js ${{ inputs.node-version }}
uses: actions/setup-node@v4
with:
node-version: ${{ inputs.node-version }}
- name: Install dependencies
run: npm install
- name: Run tests
run: npm test
このワークフローは、以下のように呼び出すことができます。
jobs:
call-workflow:
uses: ./.github/workflows/reusable-workflow.yml
with:
node-version: '20.x'
secrets:
npm-token: ${{ secrets.NPM_TOKEN }}
カスタムアクション
カスタムアクションは、独自のタスクを実行するための再利用可能なコンポーネントです。カスタムアクションは、DockerコンテナまたはJavaScriptで実装できます。以下は、JavaScriptで実装されたカスタムアクションの例です。
カスタムアクションのディレクトリ構造は以下の通りです。
.github/actions/my-custom-action/
├── action.yml
├── index.js
└── package.json
action.ymlには、アクションのメタデータを定義します。
name: 'My Custom Action'
description: 'A custom action that does something'
inputs:
my-input:
description: 'My input'
required: true
runs:
using: 'node16'
main: 'index.js'
index.jsには、アクションのロジックを実装します。
const core = require('@actions/core');
try {
const myInput = core.getInput('my-input');
console.log(`Hello, ${myInput}!`);
core.setOutput('my-output', 'Hello from my custom action!');
} catch (error) {
core.setFailed(error.message);
}
このカスタムアクションは、以下のように呼び出すことができます。
steps:
- uses: ./.github/actions/my-custom-action
with:
my-input: 'World'
キャッシュとストレージの最適化
GitHub Actionsでは、キャッシュを活用してビルド時間を短縮できます。キャッシュは、actions/cacheアクションを使って実装します。以下は、Node.jsプロジェクトの依存関係をキャッシュする例です。
steps:
- uses: actions/checkout@v4
- name: Cache node_modules
uses: actions/cache@v3
with:
path: node_modules
key: ${{ runner.os }}-node-${{ hashFiles('package-lock.json') }}
- name: Install dependencies
run: npm install
キャッシュのキーは、${{ runner.os }}-node-${{ hashFiles('package-lock.json') }}のように定義します。これにより、package-lock.jsonが変更された場合にのみ、キャッシュが再構築されます。
また、GitHub Actionsのストレージ容量を最適化するために、以下のような対策を講じることができます。
- 不要なファイルの削除(例:
rm -rf node_modules) - アーティファクトの削除(
actions/upload-artifactの使用) - ストレージ容量の監視(GitHub APIを使った監視)
環境変数とシークレットの管理
GitHub Actionsでは、環境変数とシークレットを使って機密情報を管理します。環境変数は、envキーワードで定義します。シークレットは、GitHubの「Settings」→「Secrets and variables」→「Actions」から登録できます。
以下は、環境変数とシークレットを使った例です。
jobs:
deploy:
runs-on: ubuntu-latest
env:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
steps:
- uses: actions/checkout@v4
- name: Deploy to AWS S3
run: aws s3 sync dist/ s3://my-bucket
シークレットは、以下のような機密情報に利用できます。
- APIキー
- データベースの接続情報
- クラウドプロバイダーの認証情報
- 暗号化キー
シークレットを利用する際は、以下のようなベストプラクティスを守りましょう。
- シークレットはリポジトリの設定から登録し、ワークフロー内で参照する
- シークレットはログに出力されないようにする(
echo "::add-mask::$SECRET") - シークレットは定期的にローテーションする
- シークレットは最小限の権限で利用する
セキュリティベストプラクティス
最小権限の原則
GitHub Actionsのワークフローでは、最小権限の原則を適用することが重要です。具体的には、以下のような対策を講じます。
- シークレットには、必要最小限の権限のみを付与する
- ワークフロー内で実行されるコマンドは、必要最小限の権限で実行する
- GitHub Actionsのデフォルトの権限を制限する(
permissionsキーワード)
以下は、permissionsキーワードを使った例です。
jobs:
deploy:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- uses: actions/checkout@v4
- name: Deploy to GitHub Packages
run: echo "Deploying to GitHub Packages"
この例では、contents: readとpackages: writeの権限のみが付与されています。これにより、不要な権限の付与を防ぎます。
サプライチェーン攻撃の防止
GitHub Actionsを使ったCI/CDパイプラインでは、サプライチェーン攻撃のリスクがあります。具体的には、以下のような攻撃が考えられます。
- 悪意のあるアクションの利用
- 依存関係の脆弱性を悪用した攻撃
- ビルドプロセスへの侵入
サプライチェーン攻撃を防ぐために、以下のような対策を講じます。
- GitHub Marketplaceからアクションを選択する際は、信頼できる発行元のアクションを利用する
- アクションのバージョンを固定する(
actions/checkout@v4ではなくactions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab) - 依存関係の脆弱性を検出するツール(例:Dependabot、Snyk)を利用する
- ビルドプロセスを監視し、異常な動作を検知する
GitHubは、サプライチェーン攻撃を防ぐための機能として、actionsリポジトリの署名検証を提供しています。以下は、署名検証を有効にする方法です。
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Verify action signatures
run: |
git config --global user.name "GitHub Actions"
git config --global user.email "actions@github.com"
git verify-commit HEAD
セキュリティポリシーの設定
GitHub Actionsを使ったCI/CDパイプラインでは、セキュリティポリシーを設定することが重要です。具体的には、以下のようなセキュリティポリシーを設定します。
- ワークフローの実行を制限する(例:特定のブランチのみ実行)
- ワークフローの実行を承認制にする(
environmentキーワード) - ワークフローの実行ログを監視する
以下は、environmentキ
本記事はRoute Bloom編集部が各ベンダー公式ドキュメント・エンジニア監修をもとに作成しています。インフラ・クラウド構築は環境により異なります。本番環境への適用前に必ずテストを実施してください。情報の正確性には万全を期していますが、最新情報は各公式ドキュメントをご確認ください。



