メインコンテンツにスキップ

🚀 CI/CDとは?

📖 定義

CI/CDはContinuous Integration(継続的インテグレーション)とContinuous Deployment(継続的デプロイ)の略で、コードの変更を自動的にテストしてデプロイする開発方法論です。CIはコードをマージするたびに自動的にビルドしてテストし、CDはテストに合格したコードを自動的にプロダクション環境にデプロイします。これにより、バグを素早く発見し、デプロイサイクルを短縮できます。

🎯 比喩で理解する

工場自動化ライン

従来の開発 (手動)
開発者1 → コード作成
開発者2 → コード作成
開発者3 → コード作成

1週間後

リーダーが手動でマージ

コンフリクト発生! 😱

手動でテスト

バグ発見! 😱

手動でデプロイ

デプロイ失敗! 😱

CI/CD (自動化)
開発者1 → コードプッシュ → 自動テスト ✅ → 自動デプロイ 🚀
開発者2 → コードプッシュ → 自動テスト ✅ → 自動デプロイ 🚀
開発者3 → コードプッシュ → 自動テスト ❌ → 即座に通知!
(問題をすぐに発見して修正)

食品配達

手動デプロイ = 直接配達
1. 食品作り (開発)
2. 梱包確認 (テスト)
3. 住所確認 (設定)
4. 直接運転して配達 (デプロイ)
5. 顧客確認 (検証)
→ 時間がかかり、ミスが起こりやすい

CI/CD = 自動配達システム
1. 食品作り (開発)
2. 自動梱包 (自動ビルド)
3. 自動品質検査 (自動テスト)
4. ロボットが自動配達 (自動デプロイ)
5. リアルタイム追跡 (モニタリング)
→ 速く正確

⚙️ 動作原理

1. CI/CDパイプライン

コードプッシュ (Push)

┌─────────────────────────────┐
│ CI: 継続的インテグレーション │
│ │
│ 1. コードチェックアウト │
│ 2. 依存関係のインストール │
│ 3. リント検査 │
│ 4. ビルド │
│ 5. ユニットテスト │
│ 6. 統合テスト │
│ │
│ ✅ すべて成功 │
│ ❌ 1つでも失敗 → 中断 │
└─────────────────────────────┘

┌─────────────────────────────┐
│ CD: 継続的デプロイ │
│ │
│ 1. ステージング環境デプロイ │
│ 2. E2Eテスト │
│ 3. プロダクションデプロイ │
│ 4. ヘルスチェック │
│ 5. 通知送信 │
└─────────────────────────────┘

🎉 デプロイ完了!

2. 従来の方式 vs CI/CD

従来の方式
┌─────────────────────────────────────┐
│ 月曜日 │
│ - 開発者A: 機能1開発 │
│ - 開発者B: 機能2開発 │
│ - 開発者C: バグ修正 │
├─────────────────────────────────────┤
│ 火~木曜日 │
│ - 各自開発継続 │
│ - コンフリクトの可能性が増加 😰 │
├─────────────────────────────────────┤
│ 金曜日 (統合の日) │
│ - すべてのコードをマージ │
│ - コンフリクト解決に1日かかる 😱 │
│ - テスト実行 → 多くのバグ発見 │
│ - 週末まで残業 😭 │
└─────────────────────────────────────┘

CI/CD方式
┌─────────────────────────────────────┐
│ 毎日、毎コミット │
│ │
│ 開発者A: コードプッシュ │
│ → 自動テスト ✅ │
│ → 自動デプロイ 🚀 │
│ → 3分後にプロダクション反映 │
│ │
│ 開発者B: コードプッシュ │
│ → 自動テスト ❌ │
│ → 即座に通知 │
│ → すぐに修正 (5分) │
│ │
│ - コンフリクト最小化 │
│ - バグの早期発見 │
│ - 定時退勤 😊 │
└─────────────────────────────────────┘

3. CI/CD構成要素

┌──────────────────────────────────────┐
│ Version Control (バージョン管理) │
│ Git, GitHub, GitLab │
└───────────────┬──────────────────────┘
↓ Push
┌──────────────────────────────────────┐
│ CI Server (継続的インテグレーションサーバー) │
│ GitHub Actions, Jenkins, CircleCI │
│ - コードチェックアウト │
│ - 自動ビルド │
│ - 自動テスト │
└───────────────┬──────────────────────┘
↓ Pass
┌──────────────────────────────────────┐
│ Artifact Repository (ビルド保存庫) │
│ Docker Hub, npm Registry │
└───────────────┬──────────────────────┘
↓ Deploy
┌──────────────────────────────────────┐
│ Deployment (デプロイ) │
│ AWS, Heroku, Vercel, Netlify │
└───────────────┬──────────────────────┘
↓ Monitor
┌──────────────────────────────────────┐
│ Monitoring (モニタリング) │
│ Sentry, DataDog, CloudWatch │
└──────────────────────────────────────┘

💡 実例

GitHub Actions基本例

# .github/workflows/ci.yml
# Node.jsプロジェクト CI/CDパイプライン

name: CI/CD Pipeline

# トリガー: mainブランチにプッシュされたときまたはPRが作成されたとき
on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main ]

# 環境変数
env:
NODE_VERSION: '18'

# ジョブ定義
jobs:
# ========== Job 1: テスト ==========
test:
name: テストとリント
runs-on: ubuntu-latest # Ubuntu環境で実行

steps:
# 1. コードチェックアウト
- name: コードチェックアウト
uses: actions/checkout@v3

# 2. Node.js設定
- name: Node.js設定
uses: actions/setup-node@v3
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'npm' # npmキャッシュ使用

# 3. 依存関係のインストール
- name: 依存関係のインストール
run: npm ci # npm installより速く安定

# 4. リント検査
- name: リント実行
run: npm run lint

# 5. ユニットテスト
- name: テスト実行
run: npm test

# 6. コードカバレッジ
- name: カバレッジアップロード
uses: codecov/codecov-action@v3
with:
token: ${{ secrets.CODECOV_TOKEN }}

# ========== Job 2: ビルド ==========
build:
name: ビルド
needs: test # testジョブが成功したら実行
runs-on: ubuntu-latest

steps:
- name: コードチェックアウト
uses: actions/checkout@v3

- name: Node.js設定
uses: actions/setup-node@v3
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'npm'

- name: 依存関係のインストール
run: npm ci

# プロダクションビルド
- name: プロダクションビルド
run: npm run build
env:
NODE_ENV: production

# ビルド成果物アップロード
- name: ビルド成果物アップロード
uses: actions/upload-artifact@v3
with:
name: build-files
path: dist/
retention-days: 7

# ========== Job 3: デプロイ ==========
deploy:
name: プロダクションデプロイ
needs: build # buildジョブが成功したら実行
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main' # mainブランチのみデプロイ

steps:
- name: コードチェックアウト
uses: actions/checkout@v3

# ビルド成果物ダウンロード
- name: ビルド成果物ダウンロード
uses: actions/download-artifact@v3
with:
name: build-files
path: dist/

# Vercelにデプロイ
- name: Vercelデプロイ
uses: amondnet/vercel-action@v25
with:
vercel-token: ${{ secrets.VERCEL_TOKEN }}
vercel-org-id: ${{ secrets.VERCEL_ORG_ID }}
vercel-project-id: ${{ secrets.VERCEL_PROJECT_ID }}
vercel-args: '--prod'

# Slack通知
- name: Slack通知
if: always() # 成功/失敗に関わらず実行
uses: 8398a7/action-slack@v3
with:
status: ${{ job.status }}
text: 'デプロイが${{ job.status }}しました!'
webhook_url: ${{ secrets.SLACK_WEBHOOK }}

Dockerビルドとデプロイ

# .github/workflows/docker.yml
# Dockerイメージのビルドとデプロイ

name: Docker CI/CD

on:
push:
branches: [ main ]
tags:
- 'v*' # v1.0.0のようなタグがプッシュされたら実行

env:
DOCKER_IMAGE: myapp
DOCKER_REGISTRY: docker.io

jobs:
docker:
name: Dockerビルドとプッシュ
runs-on: ubuntu-latest

steps:
- name: コードチェックアウト
uses: actions/checkout@v3

# Dockerメタデータ設定
- name: Dockerメタデータ抽出
id: meta
uses: docker/metadata-action@v4
with:
images: ${{ env.DOCKER_REGISTRY }}/${{ env.DOCKER_IMAGE }}
tags: |
type=ref,event=branch
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=sha

# Docker Buildx設定 (マルチプラットフォームビルド)
- name: Docker Buildx設定
uses: docker/setup-buildx-action@v2

# Docker Hubログイン
- name: Docker Hubログイン
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}

# Dockerイメージビルドとプッシュ
- name: Dockerイメージビルドとプッシュ
uses: docker/build-push-action@v4
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha # GitHub Actionsキャッシュ使用
cache-to: type=gha,mode=max
platforms: linux/amd64,linux/arm64 # マルチプラットフォーム

# デプロイ (SSHでサーバーに接続してコンテナ再起動)
- name: サーバーデプロイ
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.SERVER_HOST }}
username: ${{ secrets.SERVER_USERNAME }}
key: ${{ secrets.SERVER_SSH_KEY }}
script: |
docker pull ${{ env.DOCKER_REGISTRY }}/${{ env.DOCKER_IMAGE }}:latest
docker stop myapp || true
docker rm myapp || true
docker run -d \
--name myapp \
-p 3000:3000 \
--restart unless-stopped \
${{ env.DOCKER_REGISTRY }}/${{ env.DOCKER_IMAGE }}:latest
docker system prune -af

プルリクエスト自動検証

# .github/workflows/pr.yml
# PR作成時に自動検証

name: Pull Request Check

on:
pull_request:
types: [ opened, synchronize, reopened ]

jobs:
# ========== コード品質検査 ==========
lint:
name: リントとフォーマット検査
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v3

- name: Node.js設定
uses: actions/setup-node@v3
with:
node-version: '18'
cache: 'npm'

- name: 依存関係のインストール
run: npm ci

# ESLint
- name: ESLint実行
run: npm run lint

# Prettier
- name: Prettier検査
run: npm run format:check

# TypeScript型チェック
- name: TypeScript型チェック
run: npm run type-check

# ========== テスト ==========
test:
name: テスト
runs-on: ubuntu-latest

strategy:
matrix:
node-version: [16, 18, 20] # 複数のNodeバージョンでテスト

steps:
- uses: actions/checkout@v3

- name: Node.js ${{ matrix.node-version }}設定
uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node-version }}
cache: 'npm'

- name: 依存関係のインストール
run: npm ci

- name: テスト実行
run: npm test -- --coverage

- name: テスト結果アップロード
uses: actions/upload-artifact@v3
if: always()
with:
name: test-results-${{ matrix.node-version }}
path: coverage/

# ========== セキュリティ検査 ==========
security:
name: セキュリティ検査
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v3

- name: Node.js設定
uses: actions/setup-node@v3
with:
node-version: '18'

# npm audit
- name: npmセキュリティ検査
run: npm audit --audit-level=moderate

# Snykセキュリティスキャン
- name: Snykセキュリティスキャン
uses: snyk/actions/node@master
env:
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}

# ========== パフォーマンステスト ==========
performance:
name: パフォーマンステスト
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v3

- name: Node.js設定
uses: actions/setup-node@v3
with:
node-version: '18'
cache: 'npm'

- name: 依存関係のインストール
run: npm ci

- name: ビルド
run: npm run build

# Lighthouse CI
- name: Lighthouse CI
uses: treosh/lighthouse-ci-action@v9
with:
urls: |
http://localhost:3000
uploadArtifacts: true

# ========== PRコメント ==========
comment:
name: PRコメント
needs: [lint, test, security]
runs-on: ubuntu-latest
if: always()

steps:
- name: PRコメント作成
uses: actions/github-script@v6
with:
script: |
const statuses = {
lint: '${{ needs.lint.result }}',
test: '${{ needs.test.result }}',
security: '${{ needs.security.result }}'
};

let message = '## 🤖 CI検査結果\n\n';

for (const [job, status] of Object.entries(statuses)) {
const emoji = status === 'success' ? '✅' : '❌';
message += `${emoji} **${job}**: ${status}\n`;
}

github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: message
});

スケジュールベースのタスク

# .github/workflows/scheduled.yml
# 定期的に実行されるタスク

name: Scheduled Tasks

on:
schedule:
# 毎日午前9時 (UTC 0時)
- cron: '0 0 * * *'
workflow_dispatch: # 手動実行も可能

jobs:
# ========== 依存関係更新確認 ==========
dependency-check:
name: 依存関係更新確認
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v3

- name: Node.js設定
uses: actions/setup-node@v3
with:
node-version: '18'

# npm outdated確認
- name: 古いパッケージ確認
run: npm outdated || true

# Dependabot代替
- name: 更新可能なパッケージ確認
run: |
npx npm-check-updates

# ========== バックアップ ==========
backup:
name: データベースバックアップ
runs-on: ubuntu-latest

steps:
- name: データベースバックアップ
run: |
# 実際にはデータベースバックアップスクリプトを実行
echo "データベースバックアップ中..."

# S3にアップロード
- name: S3にバックアップアップロード
uses: aws-actions/configure-aws-credentials@v2
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 cp backup.sql s3://my-backups/$(date +%Y%m%d).sql

# ========== パフォーマンスモニタリング ==========
performance-monitor:
name: パフォーマンスモニタリング
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v3

- name: Lighthouse実行
uses: treosh/lighthouse-ci-action@v9
with:
urls: |
https://myapp.com
uploadArtifacts: true

# パフォーマンス低下時のSlack通知
- name: パフォーマンス低下アラート
if: failure()
uses: 8398a7/action-slack@v3
with:
status: failure
text: '⚠️ ウェブサイトのパフォーマンスが低下しました!'
webhook_url: ${{ secrets.SLACK_WEBHOOK }}

マルチ環境デプロイ

# .github/workflows/multi-env.yml
# 開発、ステージング、プロダクション環境別デプロイ

name: Multi-Environment Deployment

on:
push:
branches:
- develop # 開発環境
- staging # ステージング環境
- main # プロダクション環境

jobs:
deploy:
name: デプロイ
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v3

- name: Node.js設定
uses: actions/setup-node@v3
with:
node-version: '18'
cache: 'npm'

- name: 依存関係のインストール
run: npm ci

# 環境別ビルド
- name: ビルド
run: npm run build
env:
NODE_ENV: ${{
github.ref == 'refs/heads/main' && 'production' ||
github.ref == 'refs/heads/staging' && 'staging' ||
'development'
}}

# 開発環境デプロイ
- name: 開発環境デプロイ
if: github.ref == 'refs/heads/develop'
run: |
echo "開発環境にデプロイ中..."
# 開発サーバーデプロイコマンド
env:
API_URL: https://api-dev.myapp.com

# ステージング環境デプロイ
- name: ステージング環境デプロイ
if: github.ref == 'refs/heads/staging'
run: |
echo "ステージング環境にデプロイ中..."
# ステージングサーバーデプロイコマンド
env:
API_URL: https://api-staging.myapp.com

# プロダクション環境デプロイ
- name: プロダクション環境デプロイ
if: github.ref == 'refs/heads/main'
uses: aws-actions/amazon-ecs-deploy-task-definition@v1
with:
task-definition: task-definition.json
service: myapp-service
cluster: production-cluster
wait-for-service-stability: true
env:
API_URL: https://api.myapp.com

# デプロイ後のヘルスチェック
- name: ヘルスチェック
run: |
sleep 30 # 30秒待機

URL=${{
github.ref == 'refs/heads/main' && 'https://myapp.com' ||
github.ref == 'refs/heads/staging' && 'https://staging.myapp.com' ||
'https://dev.myapp.com'
}}

STATUS=$(curl -s -o /dev/null -w "%{http_code}" $URL/health)

if [ $STATUS -eq 200 ]; then
echo "✅ ヘルスチェック成功"
else
echo "❌ ヘルスチェック失敗: $STATUS"
exit 1
fi

# デプロイ成功通知
- name: デプロイ通知
if: success()
uses: 8398a7/action-slack@v3
with:
status: success
text: |
🚀 デプロイ完了!
環境: ${{ github.ref_name }}
コミット: ${{ github.sha }}
webhook_url: ${{ secrets.SLACK_WEBHOOK }}

🤔 よくある質問

Q1. CI/CDを導入するとどんなメリットがありますか?

A:

✅ 主なメリット:

1. バグの早期発見
従来: 1週間後の統合時に発見
CI/CD: コミット後5分以内に発見
→ 修正コスト90%削減

2. デプロイ時間の短縮
従来: 手動デプロイに2時間
CI/CD: 自動デプロイに5分
→ 1日に複数回デプロイ可能

3. コード品質の向上
- 自動リント、テスト
- コードレビューの自動化
- バグ削減

4. 開発者生産性の向上
- 手動作業の削減
- 反復作業の自動化
- 開発にのみ集中

5. 安定性の向上
- 自動テスト
- 自動ロールバック
- 一貫したデプロイプロセス

6. コラボレーションの改善
- コードコンフリクトの最小化
- 迅速なフィードバック
- 透明なプロセス

実例:
A社: CI/CD導入前
- デプロイ: 月1回
- デプロイ時間: 4時間
- デプロイ失敗率: 30%
- バグ発見時間: 平均3日

A社: CI/CD導入後
- デプロイ: 1日10回
- デプロイ時間: 5分
- デプロイ失敗率: 5%
- バグ発見時間: 平均10分

Q2. GitHub Actions vs Jenkins vs CircleCI?

A:

// ========== GitHub Actions ==========
長所:
- GitHubと完璧な統合
- 無料 (公開リポジトリ、月2000分無料)
- 簡単な設定 (YAMLファイル)
- Marketplaceに様々なアクション

短所:
- GitHubに依存的
- 複雑なワークフローは制限的

適している場合:
- GitHub使用中
- シンプルなCI/CD
- 素早いスタートが必要

:
name: CI
on: [push]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- run: npm test

// ========== Jenkins ==========
長所:
- 最も古く成熟している
- プラグインエコシステムが豊富
- 完全なカスタマイズ
- セルフホスティング (無料)

短所:
- 複雑な設定
- UIが古い
- メンテナンスが必要
- 学習曲線が高い

適している場合:
- オンプレミス環境
- 複雑なパイプライン
- レガシーシステム統合

// ========== CircleCI ==========
長所:
- 速いビルド速度
- Docker対応が優秀
- 並列処理が強力
- UIが直感的

短所:
- 有料 (無料ティアが制限的)
- GitHub/GitLabのみサポート

適している場合:
- パフォーマンスが重要
- Dockerを多用
- 並列テストが必要

// ========== 比較表 ==========
特徴 | GitHub Actions | Jenkins | CircleCI
--------------|----------------|---------|----------
価格 | 無料(制限的) | 無料 | 有料
設定難易度 | 簡単 | 難しい | 普通
パフォーマンス | 普通 | 高い | 高い
統合性 | GitHub完璧 | 汎用 | 汎用
メンテナンス | 不要 | 必要 | 不要
Docker対応 | 普通 | 良い | 非常に良い

推奨:
- 小規模チーム、GitHub使用 → GitHub Actions
- 大規模チーム、複雑な要件 → Jenkins
- パフォーマンス重要、予算あり → CircleCI

Q3. シークレットキー(Secrets)はどう管理しますか?

A:

# ========== GitHub Secrets設定 ==========
# Repository → Settings → Secrets and variables → Actions

# 使用方法
- name: デプロイ
env:
API_KEY: ${{ secrets.API_KEY }}
DATABASE_URL: ${{ secrets.DATABASE_URL }}
run: npm run deploy

# ========== 環境別Secrets ==========
# Repository → Settings → Environments

# プロダクション環境
environment: production
env:
API_URL: ${{ secrets.PROD_API_URL }}

# ステージング環境
environment: staging
env:
API_URL: ${{ secrets.STAGING_API_URL }}

# ========== セキュリティベストプラクティス ==========

# ✅ 良い例
- name: デプロイ
env:
# Secretsから取得
AWS_ACCESS_KEY: ${{ secrets.AWS_ACCESS_KEY }}
AWS_SECRET_KEY: ${{ secrets.AWS_SECRET_KEY }}
run: |
# 環境変数を使用
aws s3 sync dist/ s3://my-bucket

# ❌ 悪い例
- name: デプロイ
run: |
# コードにハードコーディング (絶対禁止!)
export AWS_ACCESS_KEY="AKIAIOSFODNN7EXAMPLE"
export AWS_SECRET_KEY="wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"

# ========== .envファイル生成 ==========
- name: .envファイル生成
run: |
cat << EOF > .env
API_URL=${{ secrets.API_URL }}
DATABASE_URL=${{ secrets.DATABASE_URL }}
JWT_SECRET=${{ secrets.JWT_SECRET }}
EOF

# ========== Docker Secrets ==========
- name: Dockerビルド
env:
DOCKER_BUILDKIT: 1
run: |
docker build \
--secret id=api_key,env=API_KEY \
--secret id=db_url,env=DATABASE_URL \
-t myapp .

# Dockerfile
# syntax=docker/dockerfile:1
FROM node:18
RUN --mount=type=secret,id=api_key \
API_KEY=$(cat /run/secrets/api_key) npm install

# ========== Vault使用 (高度) ==========
- name: HashiCorp VaultからSecrets取得
uses: hashicorp/vault-action@v2
with:
url: https://vault.mycompany.com
token: ${{ secrets.VAULT_TOKEN }}
secrets: |
secret/data/production api_key | API_KEY ;
secret/data/production db_url | DATABASE_URL

Q4. テストが失敗するとどうなりますか?

A:

# ========== 基本動作: パイプライン中断 ==========
jobs:
test:
runs-on: ubuntu-latest
steps:
- name: テスト実行
run: npm test
# テスト失敗 → ここで中断
# 以降のステップは実行されない

deploy:
needs: test # testが成功してから実行
runs-on: ubuntu-latest
steps:
- name: デプロイ
run: npm run deploy
# test失敗時はこのステップは実行されない ✅

# ========== 失敗しても続行 ==========
- name: テスト実行
run: npm test
continue-on-error: true # 失敗しても続行
# ⚠️ 推奨されない

# ========== 条件付き実行 ==========
- name: 失敗時通知
if: failure() # 前のステップが失敗した場合のみ
uses: 8398a7/action-slack@v3
with:
status: failure
text: '❌ テスト失敗!'
webhook_url: ${{ secrets.SLACK_WEBHOOK }}

- name: 成功時デプロイ
if: success() # すべてのステップが成功した場合のみ
run: npm run deploy

- name: 常に実行
if: always() # 成功/失敗に関わらず
run: npm run cleanup

# ========== 再試行 ==========
- name: 不安定なテスト (再試行)
uses: nick-invision/retry@v2
with:
timeout_minutes: 10
max_attempts: 3
command: npm run test:e2e

# ========== 失敗処理例 ==========
- name: テスト
id: test
run: npm test

- name: テスト失敗時イシュー作成
if: failure() && steps.test.outcome == 'failure'
uses: actions/github-script@v6
with:
script: |
github.rest.issues.create({
owner: context.repo.owner,
repo: context.repo.repo,
title: '❌ テスト失敗',
body: 'テストが失敗しました。確認が必要です。',
labels: ['bug', 'ci']
});

# ========== ロールバック ==========
- name: デプロイ
id: deploy
run: npm run deploy

- name: デプロイ失敗時ロールバック
if: failure() && steps.deploy.outcome == 'failure'
run: |
echo "デプロイ失敗! 前のバージョンにロールバック中..."
npm run rollback

Q5. コストを削減するには?

A:

# ========== キャッシング活用 ==========
- name: Node.js設定
uses: actions/setup-node@v3
with:
node-version: '18'
cache: 'npm' # npmキャッシング (ビルド時間50%短縮)

- name: 依存関係キャッシング
uses: actions/cache@v3
with:
path: |
~/.npm
node_modules
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-

# ========== 条件付き実行 ==========
on:
push:
branches: [ main ]
paths: # 特定ファイル変更時のみ実行
- 'src/**'
- 'package.json'
# README.md変更時は実行しない → コスト削減

# ========== 同時実行制限 ==========
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true # 前の実行をキャンセル
# → 不要な重複実行を防止

# ========== Self-hosted Runner ==========
# 自社サーバー使用 (無料)
jobs:
build:
runs-on: self-hosted # GitHub Actions無料分を使用しない
steps:
- run: npm run build

# ========== 短いタスクのみ実行 ==========
- name: 変更ファイル確認
id: changes
uses: dorny/paths-filter@v2
with:
filters: |
frontend:
- 'frontend/**'
backend:
- 'backend/**'

- name: フロントエンドテスト
if: steps.changes.outputs.frontend == 'true'
run: npm run test:frontend
# フロントエンド変更時のみ実行 → 時間節約

- name: バックエンドテスト
if: steps.changes.outputs.backend == 'true'
run: npm run test:backend

# ========== コスト例 ==========
# GitHub Actions無料ティア:
# - 公開リポジトリ: 無制限
# - 非公開リポジトリ: 月2000分

# 最適化前:
# - 毎コミットで全体テスト (20分)
# - 1日10回プッシュ
# - 月使用量: 10 × 20 × 30 = 6000分
# - 超過料金: (6000 - 2000) × $0.008 = $32

# 最適化後:
# - キャッシングで10分短縮
# - 変更部分のみテスト
# - 平均ビルド時間5分
# - 月使用量: 10 × 5 × 30 = 1500分
# - 費用: $0 (無料ティア内)
# → 月$32節約!

🎓 次のステップ

CI/CDを理解したら、次を学習してみましょう:

  1. Gitとは? (文書作成予定) - バージョン管理の基礎
  2. Dockerとは? (文書作成予定) - コンテナ化デプロイ
  3. TDDとは? (文書作成予定) - テスト駆動開発

実践してみよう

# ========== 1. GitHub Actionsを始める ==========

# 1) リポジトリにワークフローファイル作成
mkdir -p .github/workflows
cat > .github/workflows/ci.yml << 'EOF'
name: CI
on: [push]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Node.js設定
uses: actions/setup-node@v3
with:
node-version: '18'
- run: npm ci
- run: npm test
EOF

# 2) コミットとプッシュ
git add .github/workflows/ci.yml
git commit -m "Add CI workflow"
git push

# 3) GitHubでActionsタブを確認
# → 自動実行されるワークフローを確認!

# ========== 2. ローカルでテスト (act) ==========
# actを使用するとローカルでGitHub Actionsをテスト可能

# actインストール (macOS)
brew install act

# ワークフロー実行
act push

# 特定jobのみ実行
act -j test

# ========== 3. デプロイ自動化例 ==========

# Vercelデプロイ
npm install -g vercel
vercel login
vercel --prod

# Netlifyデプロイ
npm install -g netlify-cli
netlify login
netlify deploy --prod

# Herokuデプロイ
heroku login
git push heroku main

🎬 まとめ

CI/CDは現代開発の必須ツールです:

  • CI: コード変更を自動的にテストして統合
  • CD: テストに合格したコードを自動的にデプロイ
  • メリット: 迅速なフィードバック、安定性向上、生産性増加
  • ツール: GitHub Actions、Jenkins、CircleCIなど

自動化で開発にのみ集中して、より速くデプロイしましょう! 🚀