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

現代のソフトウェア開発において、継続的インテグレーション(CI)と継続的デプロイメント(CD)は、開発効率と品質向上のために不可欠な手法となっています。GitHub Actions を使用することで、これらのプロセスを自動化し、チーム開発をより効率的に進めることができます。
この記事では、GitHub Actions を使って CI/CD パイプラインを一から構築する方法を、初心者の方にもわかりやすく解説いたします。実際の Node.js アプリケーションを例に、基本的な設定から本番環境への自動デプロイまで、段階的に学んでいきましょう。
背景
GitHub Actions とは何か
GitHub Actions は、GitHub が提供する CI/CD プラットフォームです。リポジトリ内で発生するイベント(プッシュ、プルリクエスト作成など)をトリガーとして、自動的にワークフローを実行できます。
従来の外部 CI/CD サービスとは異なり、GitHub 内で完結するため設定が簡単で、GitHub との統合も非常にスムーズです。無料プランでも月 2,000 分の実行時間が提供されており、個人開発や小規模チームには十分な容量となっています。
GitHub Actions の基本構成要素を図で確認してみましょう。
mermaidflowchart LR
event[イベント発生] -->|プッシュ/PR| workflow[ワークフロー実行]
workflow --> job1[Job1: テスト]
workflow --> job2[Job2: ビルド]
job1 --> step1[ステップ1]
job1 --> step2[ステップ2]
job2 --> step3[ステップ3]
step1 --> action1[アクション実行]
step2 --> action2[アクション実行]
step3 --> action3[アクション実行]
図で理解できる要点:
- イベントトリガーからワークフロー実行までの流れ
- 複数のジョブが並列実行される仕組み
- 各ジョブ内でステップとアクションが順次実行される構造
CI/CD パイプラインの重要性
CI/CD パイプラインは、開発からデプロイまでの一連のプロセスを自動化するシステムです。これにより以下のメリットが得られます。
項目 | メリット | 具体的効果 |
---|---|---|
1 | 品質向上 | 自動テストにより、バグの早期発見が可能 |
2 | 開発速度向上 | 手動作業の削減により、開発により集中できる |
3 | デプロイリスク軽減 | 自動化により、人的ミスを防止 |
4 | フィードバック高速化 | 問題の即座な検出と通知 |
継続的インテグレーション(CI)では、コードの変更を頻繁にメインブランチに統合し、自動テストを実行します。継続的デプロイメント(CD)では、テストに合格したコードを自動的に本番環境にデプロイします。
従来の手動デプロイの課題
多くの開発チームが経験する手動デプロイの問題を見てみましょう。開発者がローカル環境でテストを行い、手動でサーバーにデプロイする従来の方法では、様々な課題が発生します。
mermaidflowchart TD
dev[開発者] -->|手動アップロード| server[本番サーバー]
dev -->|ローカルテスト| local[ローカル環境]
server -->|エラー発生| error[緊急対応]
error -->|手動修正| server
local -->|環境差異| problem[予期しない問題]
problem -->|デバッグ作業| dev
手動デプロイでは環境差異や人的ミスにより、予期しない問題が発生しやすくなります。
課題
手動デプロイの問題点
手動でのデプロイ作業には、以下のような深刻な問題があります。
環境の不整合 開発環境と本番環境の差異により、「ローカルでは動作するが本番で動作しない」という問題が頻繁に発生します。Node.js のバージョンや依存関係の違いが主な原因となります。
人的ミス 手動作業では、ファイルのアップロード忘れやコマンドの入力ミスなどが起こりやすく、サービス停止につながる可能性があります。
作業の属人化 特定の担当者しかデプロイ方法を知らない状況では、その人が不在の際にリリースができなくなってしまいます。
品質保証の困難さ
手動プロセスでは、一貫した品質保証が困難です。
テストの実行忘れ リリース前のテスト実行が属人的になり、重要なテストケースが実行されないことがあります。
コードレビューの抜け漏れ 急ぎのリリースでコードレビューをスキップしてしまい、後でバグが発見されるケースが多発します。
リグレッションテストの負担 新機能追加時に既存機能への影響を手動で確認するのは、時間もかかり見落としも発生しやすくなります。
チーム開発での課題
複数人での開発では、さらに複雑な問題が発生します。
マージ競合の頻発 各開発者が独立して作業し、最後にマージする際に大きな競合が発生することがあります。
デプロイタイミングの調整 複数の機能が同時に完成した場合、どの順番でデプロイするかの調整が必要になります。
責任範囲の曖昧さ 問題が発生した際に、誰がどの部分を担当していたかが不明確になりがちです。
これらの課題を解決するために、GitHub Actions を活用した CI/CD パイプラインの構築が重要になります。
解決策
GitHub Actions の基本設定
GitHub Actions を使用して CI/CD パイプラインを構築するための基本的な設定方法を説明します。
リポジトリの準備 まず、GitHub 上にリポジトリを作成し、ローカルに複製します。
bashgit clone https://github.com/your-username/your-project.git
cd your-project
ディレクトリ構造の確認 プロジェクトのルートディレクトリに以下の構造を作成します。
cssyour-project/
├── .github/
│ └── workflows/
│ └── ci-cd.yml
├── src/
├── package.json
└── README.md
GitHub Actions の設定ファイルは、.github/workflows/
ディレクトリ内に YAML 形式で記述します。
ワークフロー(.github/workflows)の作成
ワークフローファイルの基本構造を理解しましょう。
基本的なワークフローファイルの作成
.github/workflows/ci-cd.yml
ファイルを作成し、以下の基本構造から始めます。
yaml# ワークフローの名前
name: CI/CD Pipeline
# トリガーとなるイベントを指定
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
イベントトリガーの設定 どのような場合にワークフローを実行するかを定義します。
yamlon:
# メインブランチへのプッシュ時
push:
branches: [main]
# プルリクエスト作成時
pull_request:
branches: [main]
# 手動実行を許可
workflow_dispatch:
# スケジュール実行(毎日午前2時)
schedule:
- cron: '0 2 * * *'
実行環境の指定 ワークフローが実行される仮想環境を指定します。
yamljobs:
build:
# Ubuntu最新版を使用
runs-on: ubuntu-latest
strategy:
matrix:
# 複数のNode.jsバージョンでテスト
node-version: [16.x, 18.x, 20.x]
基本的な CI/CD ステップの定義
CI/CD パイプラインの各ステップを段階的に定義していきます。
チェックアウトステップ まず、リポジトリのソースコードを取得します。
yamlsteps:
# ソースコードのチェックアウト
- name: Checkout code
uses: actions/checkout@v4
with:
# 全履歴を取得(バージョンタグ使用時に必要)
fetch-depth: 0
Node.js 環境のセットアップ 指定したバージョンの Node.js 環境を構築します。
yaml# Node.js環境のセットアップ
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
# パッケージマネージャーのキャッシュを有効化
cache: 'yarn'
依存関係のインストール プロジェクトの依存関係をインストールします。
yaml# 依存関係のインストール
- name: Install dependencies
run: yarn install --frozen-lockfile
--frozen-lockfile
オプションにより、yarn.lock ファイルを変更せずに正確な依存関係をインストールできます。
CI/CD パイプラインの全体的な流れを図で確認してみましょう。
mermaidflowchart TD
start[コード変更] --> push[Git Push]
push --> trigger[ワークフロー起動]
trigger --> checkout[コードチェックアウト]
checkout --> setup[環境セットアップ]
setup --> install[依存関係インストール]
install --> test[テスト実行]
test --> build[ビルド実行]
build --> deploy{デプロイ判定}
deploy -->|成功| prod[本番デプロイ]
deploy -->|失敗| notify[エラー通知]
prod --> complete[完了]
notify --> fix[修正作業]
図で理解できる要点:
- コード変更から本番デプロイまでの自動化された流れ
- 各ステップでの成功・失敗判定
- エラー時の通知とフィードバックループ
具体例
Node.js アプリケーションの CI 設定
実際の Node.js アプリケーションを例に、具体的な CI 設定を実装してみましょう。
プロジェクトの初期設定 まず、サンプルの Node.js プロジェクトを準備します。
json{
"name": "sample-node-app",
"version": "1.0.0",
"scripts": {
"start": "node src/index.js",
"test": "jest",
"lint": "eslint src/",
"build": "webpack --mode production"
},
"dependencies": {
"express": "^4.18.2"
},
"devDependencies": {
"jest": "^29.5.0",
"eslint": "^8.41.0",
"webpack": "^5.82.1"
}
}
基本的な Express アプリケーション シンプルな Web アプリケーションを作成します。
javascript// src/index.js
const express = require('express');
const app = express();
const port = process.env.PORT || 3000;
// ヘルスチェック用エンドポイント
app.get('/health', (req, res) => {
res.status(200).json({
status: 'OK',
timestamp: new Date().toISOString(),
});
});
// メインエンドポイント
app.get('/', (req, res) => {
res.json({
message: 'Hello, GitHub Actions!',
version: process.env.npm_package_version || '1.0.0',
});
});
app.listen(port, () => {
console.log(`Server is running on port ${port}`);
});
module.exports = app;
完全な CI ワークフロー設定
.github/workflows/ci.yml
ファイルを作成し、包括的な CI 設定を実装します。
yamlname: Continuous Integration
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [16.x, 18.x, 20.x]
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
cache: 'yarn'
- name: Install dependencies
run: yarn install --frozen-lockfile
- name: Run linter
run: yarn lint
- name: Run tests
run: yarn test --coverage
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v3
with:
file: ./coverage/lcov.info
このワークフローでは、複数の Node.js バージョンでテストを実行し、コードカバレッジも取得します。
テスト自動化の実装
品質保証のためのテスト自動化を詳しく実装します。
Jest テストの設定
jest.config.js
ファイルでテスト環境を設定します。
javascript// jest.config.js
module.exports = {
// テスト環境の指定
testEnvironment: 'node',
// カバレッジレポートの設定
collectCoverage: true,
coverageDirectory: 'coverage',
coverageReporters: ['text', 'lcov', 'html'],
// テストファイルのパターン
testMatch: [
'**/__tests__/**/*.js',
'**/?(*.)+(spec|test).js',
],
// カバレッジ対象ファイル
collectCoverageFrom: [
'src/**/*.js',
'!src/index.js', // エントリーポイントは除外
],
// カバレッジの閾値設定
coverageThreshold: {
global: {
branches: 80,
functions: 80,
lines: 80,
statements: 80,
},
},
};
ユニットテストの作成
src/__tests__/app.test.js
ファイルで API エンドポイントをテストします。
javascript// src/__tests__/app.test.js
const request = require('supertest');
const app = require('../index');
describe('API Endpoints', () => {
// ヘルスチェックエンドポイントのテスト
test('GET /health should return OK status', async () => {
const response = await request(app)
.get('/health')
.expect(200);
expect(response.body).toHaveProperty('status', 'OK');
expect(response.body).toHaveProperty('timestamp');
});
// メインエンドポイントのテスト
test('GET / should return welcome message', async () => {
const response = await request(app)
.get('/')
.expect(200);
expect(response.body).toHaveProperty(
'message',
'Hello, GitHub Actions!'
);
expect(response.body).toHaveProperty('version');
});
// 存在しないエンドポイントのテスト
test('GET /nonexistent should return 404', async () => {
await request(app).get('/nonexistent').expect(404);
});
});
統合テストの追加 より実際の使用状況に近い統合テストも実装できます。
javascript// src/__tests__/integration.test.js
const request = require('supertest');
const app = require('../index');
describe('Integration Tests', () => {
test('Application should start and respond correctly', async () => {
// 複数のエンドポイントを順次テスト
await request(app).get('/health').expect(200);
await request(app).get('/').expect(200);
// レスポンス時間のテスト(100ms以内)
const start = Date.now();
await request(app).get('/');
const responseTime = Date.now() - start;
expect(responseTime).toBeLessThan(100);
});
});
本番環境への自動デプロイ設定
テストに合格したコードを自動的に本番環境にデプロイする設定を実装します。
デプロイワークフローの作成
.github/workflows/deploy.yml
ファイルでデプロイプロセスを定義します。
yamlname: Deploy to Production
on:
push:
branches: [main]
workflow_run:
workflows: ['Continuous Integration']
types:
- completed
jobs:
deploy:
runs-on: ubuntu-latest
# CIワークフローが成功した場合のみ実行
if: ${{ github.event.workflow_run.conclusion == 'success' }}
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '18.x'
cache: 'yarn'
- name: Install dependencies
run: yarn install --frozen-lockfile
- name: Build application
run: yarn build
env:
NODE_ENV: production
AWS S3 へのデプロイ設定 静的サイトや SPA の場合、AWS S3 への自動デプロイを設定できます。
yaml- 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: ap-northeast-1
- name: Deploy to S3
run: |
aws s3 sync ./dist s3://${{ secrets.S3_BUCKET_NAME }} --delete
aws cloudfront create-invalidation --distribution-id ${{ secrets.CLOUDFRONT_DISTRIBUTION_ID }} --paths "/*"
Docker を使用したデプロイ コンテナ化されたアプリケーションのデプロイも可能です。
yaml- name: Build Docker image
run: |
docker build -t ${{ secrets.DOCKER_REGISTRY }}/my-app:${{ github.sha }} .
docker build -t ${{ secrets.DOCKER_REGISTRY }}/my-app:latest .
- name: Push to registry
run: |
echo ${{ secrets.DOCKER_PASSWORD }} | docker login -u ${{ secrets.DOCKER_USERNAME }} --password-stdin
docker push ${{ secrets.DOCKER_REGISTRY }}/my-app:${{ github.sha }}
docker push ${{ secrets.DOCKER_REGISTRY }}/my-app:latest
デプロイ後の動作確認 デプロイが完了した後、実際にサービスが正常に動作しているかを確認します。
yaml- name: Health check
run: |
# デプロイ完了を待つ
sleep 30
# ヘルスチェックエンドポイントを確認
curl -f ${{ secrets.PRODUCTION_URL }}/health || exit 1
# レスポンス内容の確認
response=$(curl -s ${{ secrets.PRODUCTION_URL }}/)
echo "Deployment successful: $response"
- name: Notify deployment success
if: success()
uses: 8398a7/action-slack@v3
with:
status: success
text: 'Production deployment completed successfully!'
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
デプロイプロセスの詳細な流れを図で確認してみましょう。
mermaidsequenceDiagram
participant Dev as 開発者
participant GitHub as GitHub
participant Actions as GitHub Actions
participant AWS as AWS S3/CloudFront
participant Slack as Slack通知
Dev->>GitHub: git push main
GitHub->>Actions: ワークフロー起動
Actions->>Actions: CI実行(テスト・ビルド)
Actions->>Actions: CI成功確認
Actions->>AWS: アプリケーションデプロイ
AWS->>Actions: デプロイ完了
Actions->>AWS: ヘルスチェック実行
AWS->>Actions: 正常レスポンス
Actions->>Slack: 成功通知送信
Slack->>Dev: デプロイ完了通知
図で理解できる要点:
- 開発者のコミットから本番反映までの自動化フロー
- 各ステップでの成功確認と次ステップへの進行
- デプロイ完了後の通知システム
これらの設定により、コードの変更から本番環境への反映まで、完全に自動化された CI/CD パイプラインが構築できます。
まとめ
GitHub Actions を使用した CI/CD パイプラインの構築について、基本的な概念から実際の実装まで詳しく解説してまいりました。
重要なポイントの再確認
自動化の効果 手動デプロイの課題を解決し、開発効率と品質の両方を大幅に向上させることができます。特に、人的ミスの削減と一貫した品質保証は、プロダクトの安定性向上に直結します。
段階的な導入 いきなり完全なパイプラインを構築するのではなく、まずは基本的なテスト自動化から始めて、段階的に機能を追加していくことが重要です。
チーム開発での価値 個人開発でも効果的ですが、複数人でのチーム開発においてその真価を発揮します。コードレビューの自動化、マージ競合の早期発見、責任範囲の明確化など、多くのメリットがあります。
CI/CD パイプライン構築のベストプラクティス
項目 | ベストプラクティス | 注意点 |
---|---|---|
1 | 小さく始める | 最初から完璧を目指さず、基本機能から開始 |
2 | テストファースト | デプロイ前に必ずテストを実行する設計 |
3 | セキュリティ重視 | Secrets や Environments を適切に使用 |
4 | 監視・通知 | 失敗時の迅速な検知と対応体制の構築 |
5 | 継続的改善 | 定期的な見直しと最適化の実施 |
次のステップ
基本的な CI/CD パイプラインが構築できたら、以下のような発展的な機能の実装を検討してみてください。
高度な機能
- 環境別デプロイ(staging、production)
- ブルーグリーンデプロイメント
- カナリアリリース
- 自動ロールバック機能
監視・運用
- パフォーマンスモニタリング
- エラー追跡とアラート
- ログ集約と分析
- メトリクス収集と可視化
セキュリティ強化
- 脆弱性スキャンの自動化
- 依存関係の定期更新
- セキュリティポリシーの適用
- コンプライアンスチェック
GitHub Actions の豊富な機能を活用することで、開発チームの生産性を大幅に向上させることができます。まずは小さな自動化から始めて、徐々に範囲を拡大していくことをおすすめいたします。
継続的な改善と学習により、より効率的で安定した開発プロセスを構築していきましょう。
関連リンク
公式ドキュメント
- GitHub Actions Documentation - GitHub Actions の公式ドキュメント
- GitHub Marketplace - 再利用可能なアクションの検索
- GitHub Actions の料金 - 使用量と料金の詳細
学習リソース
- GitHub Learning Lab - インタラクティブな学習コース
- Awesome GitHub Actions - 便利なアクションのまとめ
- GitHub Actions Examples - スターターワークフローのサンプル集
コミュニティ
- GitHub Community Forum - 質問と回答のコミュニティ
- GitHub Actions の議論 - 開発者同士の議論
- Stack Overflow - GitHub Actions 関連の Q&A
- article
GitHub Actions で CI/CD パイプラインを構築する方法
- article
Dify × GitHub Actions で DevOps 自動化
- article
GitHub Actions と Jenkins の違いを徹底比較
- article
GitHub Actions の YAML 書き方完全ガイド【初心者向け】
- article
GitHub Actions 入門:最初のワークフローを作成する手順
- article
GitHub Actions とは?自動化できることと基本の仕組みを徹底解説
- article
Python で始める自動化:ファイル操作・定期実行・スクレイピングの実践
- article
生成 AI 時代の新常識!GPT-5 のセキュリティ・倫理・安全設計の最新動向
- article
【実践】NestJS で REST API を構築する基本的な流れ
- article
TypeScript × GitHub Copilot:型情報を活かした高精度コーディング
- article
Motion(旧 Framer Motion)Variants 完全攻略:staggerChildren・when で複雑アニメを整理する
- article
JavaScript のオブジェクト操作まとめ:Object.keys/entries/values の使い方
- blog
Googleストアから訂正案内!Pixel 10ポイント有効期限「1年」表示は誤りだった
- blog
【2025年8月】Googleストア「ストアポイント」は1年表記はミス?2年ルールとの整合性を検証
- blog
Googleストアの注文キャンセルはなぜ起きる?Pixel 10購入前に知るべき注意点
- blog
Pixcel 10シリーズの発表!全モデル Pixcel 9 から進化したポイントを見やすく整理
- blog
フロントエンドエンジニアの成長戦略:コーチングで最速スキルアップする方法
- blog
失敗を称賛する文化はどう作る?アジャイルな組織へ生まれ変わるための第一歩
- review
今の自分に満足していますか?『持たざる者の逆襲 まだ何者でもない君へ』溝口勇児
- review
ついに語られた業界の裏側!『フジテレビの正体』堀江貴文が描くテレビ局の本当の姿
- review
愛する勇気を持てば人生が変わる!『幸せになる勇気』岸見一郎・古賀史健のアドラー実践編で真の幸福を手に入れる
- review
週末を変えれば年収も変わる!『世界の一流は「休日」に何をしているのか』越川慎司の一流週末メソッド
- review
新しい自分に会いに行こう!『自分の変え方』村岡大樹の認知科学コーチングで人生リセット
- review
科学革命から AI 時代へ!『サピエンス全史 下巻』ユヴァル・ノア・ハラリが予見する人類の未来