🆕 New Guides Added: - GitHub Actions complete guide (CI/CD automation) - GitHub Security comprehensive guide (enterprise security) - GitHub Pages detailed guide (website publishing) 🔗 Navigation Improvements: - Updated index.md with all 7 guides - Added cross-navigation between all guides - Enhanced learning paths for different user types - Comprehensive learning flow diagrams 📚 Content Highlights: - Jenkins/CircleCI migration strategies - Enterprise security best practices - WordPress to GitHub Pages migration - Advanced automation workflows - Complete external tool replacements 🎯 User Experience: - Role-based learning recommendations - Consistent navigation structure - Progressive learning paths - Cross-reference linking 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
1681 lines
No EOL
45 KiB
Markdown
1681 lines
No EOL
45 KiB
Markdown
---
|
||
layout: default
|
||
title: "GitHub Actions完全ガイド"
|
||
description: "Jenkins・CircleCI代替のCI/CD自動化とGitHub Actions完全活用法"
|
||
---
|
||
|
||
# ⚡ GitHub Actions - 完全なCI/CD自動化
|
||
|
||
GitHub Actionsを活用して、Jenkins・CircleCI・GitLab CI・Azure DevOpsなどの外部CI/CDツールに依存しない、統合された自動化環境を構築する完全ガイド。コードのビルド・テスト・デプロイから、複雑なワークフロー自動化まで網羅します。
|
||
|
||
## 🎯 学習目標
|
||
|
||
- GitHub Actions の全機能理解と実践的活用
|
||
- 外部CI/CDツールからの完全移行戦略
|
||
- セキュアで効率的なワークフロー設計
|
||
- 高度な自動化とDevOps実践
|
||
- コスト最適化と運用効率向上
|
||
|
||
## 📚 目次
|
||
|
||
1. [GitHub Actions 基本概念](#1-github-actions-基本概念)
|
||
2. [CI/CDパイプライン構築](#2-cicdパイプライン構築)
|
||
3. [高度なワークフロー設計](#3-高度なワークフロー設計)
|
||
4. [セキュリティ・シークレット管理](#4-セキュリティシークレット管理)
|
||
5. [外部ツールからの移行](#5-外部ツールからの移行)
|
||
6. [運用最適化・監視](#6-運用最適化監視)
|
||
|
||
---
|
||
|
||
## 1. GitHub Actions 基本概念
|
||
|
||
### 🏗️ アーキテクチャ理解
|
||
|
||
#### 核心コンポーネント
|
||
```yaml
|
||
# GitHub Actions の基本構造
|
||
Workflow (ワークフロー)
|
||
├── Events (イベント) - トリガー条件
|
||
├── Jobs (ジョブ) - 実行単位
|
||
│ ├── Steps (ステップ) - 個別タスク
|
||
│ │ ├── Actions (アクション) - 再利用可能な処理
|
||
│ │ └── Commands (コマンド) - シェル実行
|
||
│ └── Runner (ランナー) - 実行環境
|
||
├── Secrets (シークレット) - 機密情報
|
||
└── Environment (環境) - デプロイメント設定
|
||
```
|
||
|
||
#### 基本ワークフロー例
|
||
```yaml
|
||
# .github/workflows/basic-ci.yml
|
||
name: Basic CI Pipeline
|
||
|
||
# イベント定義
|
||
on:
|
||
push:
|
||
branches: [main, develop]
|
||
pull_request:
|
||
branches: [main]
|
||
schedule:
|
||
- cron: '0 2 * * 1' # 毎週月曜 2時
|
||
|
||
# グローバル環境変数
|
||
env:
|
||
NODE_VERSION: '18'
|
||
CACHE_KEY: node-modules
|
||
|
||
jobs:
|
||
# ジョブ1: コード品質チェック
|
||
quality-check:
|
||
name: Code Quality
|
||
runs-on: ubuntu-latest
|
||
|
||
steps:
|
||
- name: Checkout code
|
||
uses: actions/checkout@v4
|
||
with:
|
||
fetch-depth: 0
|
||
|
||
- name: Setup Node.js
|
||
uses: actions/setup-node@v4
|
||
with:
|
||
node-version: ${{ env.NODE_VERSION }}
|
||
cache: 'npm'
|
||
|
||
- name: Install dependencies
|
||
run: npm ci
|
||
|
||
- name: Lint check
|
||
run: npm run lint
|
||
|
||
- name: Type check
|
||
run: npm run type-check
|
||
|
||
- name: Security audit
|
||
run: npm audit --audit-level high
|
||
|
||
# ジョブ2: テスト実行
|
||
test:
|
||
name: Test Suite
|
||
runs-on: ubuntu-latest
|
||
needs: quality-check
|
||
|
||
strategy:
|
||
matrix:
|
||
node-version: [16, 18, 20]
|
||
os: [ubuntu-latest, windows-latest, macos-latest]
|
||
|
||
steps:
|
||
- uses: actions/checkout@v4
|
||
|
||
- name: Setup Node.js ${{ matrix.node-version }}
|
||
uses: actions/setup-node@v4
|
||
with:
|
||
node-version: ${{ matrix.node-version }}
|
||
cache: 'npm'
|
||
|
||
- name: Install dependencies
|
||
run: npm ci
|
||
|
||
- name: Run tests
|
||
run: npm run test:coverage
|
||
env:
|
||
CI: true
|
||
|
||
- name: Upload coverage
|
||
uses: codecov/codecov-action@v3
|
||
if: matrix.node-version == 18 && matrix.os == 'ubuntu-latest'
|
||
with:
|
||
token: ${{ secrets.CODECOV_TOKEN }}
|
||
```
|
||
|
||
### 🎛️ イベントトリガーの活用
|
||
|
||
#### 包括的なトリガー設定
|
||
```yaml
|
||
# 高度なイベント設定例
|
||
on:
|
||
# プッシュイベント
|
||
push:
|
||
branches:
|
||
- main
|
||
- 'release/**'
|
||
- 'hotfix/**'
|
||
paths:
|
||
- 'src/**'
|
||
- 'package.json'
|
||
- '.github/workflows/**'
|
||
tags:
|
||
- 'v*'
|
||
|
||
# プルリクエストイベント
|
||
pull_request:
|
||
types: [opened, synchronize, reopened, ready_for_review]
|
||
branches: [main, develop]
|
||
paths-ignore:
|
||
- 'docs/**'
|
||
- '*.md'
|
||
|
||
# Issue イベント
|
||
issues:
|
||
types: [opened, labeled, assigned]
|
||
|
||
# リリースイベント
|
||
release:
|
||
types: [published, prereleased]
|
||
|
||
# スケジュール実行
|
||
schedule:
|
||
- cron: '0 2 * * 1-5' # 平日 2時
|
||
- cron: '0 10 * * 6' # 土曜 10時
|
||
|
||
# 手動実行
|
||
workflow_dispatch:
|
||
inputs:
|
||
environment:
|
||
description: 'Deployment environment'
|
||
required: true
|
||
default: 'staging'
|
||
type: choice
|
||
options:
|
||
- staging
|
||
- production
|
||
debug:
|
||
description: 'Enable debug logging'
|
||
required: false
|
||
default: false
|
||
type: boolean
|
||
version:
|
||
description: 'Version to deploy'
|
||
required: false
|
||
type: string
|
||
|
||
# 他のワークフローからの呼び出し
|
||
workflow_call:
|
||
inputs:
|
||
config-path:
|
||
required: true
|
||
type: string
|
||
secrets:
|
||
api-key:
|
||
required: true
|
||
```
|
||
|
||
---
|
||
|
||
## 2. CI/CDパイプライン構築
|
||
|
||
### 🔄 フルスタックCI/CDパイプライン
|
||
|
||
#### Node.js アプリケーション用
|
||
```yaml
|
||
# .github/workflows/nodejs-cicd.yml
|
||
name: Node.js CI/CD Pipeline
|
||
|
||
on:
|
||
push:
|
||
branches: [main, develop]
|
||
pull_request:
|
||
branches: [main]
|
||
|
||
env:
|
||
REGISTRY: ghcr.io
|
||
IMAGE_NAME: ${{ github.repository }}
|
||
|
||
jobs:
|
||
# ステージ1: ビルド・テスト
|
||
build-and-test:
|
||
name: Build and Test
|
||
runs-on: ubuntu-latest
|
||
|
||
outputs:
|
||
version: ${{ steps.version.outputs.version }}
|
||
image-digest: ${{ steps.build.outputs.digest }}
|
||
|
||
steps:
|
||
- name: Checkout
|
||
uses: actions/checkout@v4
|
||
with:
|
||
fetch-depth: 0
|
||
|
||
- name: Setup Node.js
|
||
uses: actions/setup-node@v4
|
||
with:
|
||
node-version: '18'
|
||
cache: 'npm'
|
||
|
||
- name: Generate version
|
||
id: version
|
||
run: |
|
||
if [[ $GITHUB_REF == refs/tags/* ]]; then
|
||
VERSION=${GITHUB_REF#refs/tags/}
|
||
else
|
||
VERSION=$(git describe --tags --always --dirty)
|
||
fi
|
||
echo "version=$VERSION" >> $GITHUB_OUTPUT
|
||
|
||
- name: Install dependencies
|
||
run: npm ci
|
||
|
||
- name: Run linting
|
||
run: npm run lint
|
||
|
||
- name: Run type checking
|
||
run: npm run type-check
|
||
|
||
- name: Run unit tests
|
||
run: npm run test:unit -- --coverage
|
||
|
||
- name: Run integration tests
|
||
run: npm run test:integration
|
||
env:
|
||
DATABASE_URL: postgresql://postgres:postgres@localhost:5432/test
|
||
|
||
- name: Build application
|
||
run: npm run build
|
||
env:
|
||
NODE_ENV: production
|
||
VERSION: ${{ steps.version.outputs.version }}
|
||
|
||
- name: Upload build artifacts
|
||
uses: actions/upload-artifact@v3
|
||
with:
|
||
name: build-artifacts
|
||
path: |
|
||
dist/
|
||
package.json
|
||
package-lock.json
|
||
retention-days: 7
|
||
|
||
# ステージ2: セキュリティスキャン
|
||
security-scan:
|
||
name: Security Scanning
|
||
runs-on: ubuntu-latest
|
||
needs: build-and-test
|
||
|
||
permissions:
|
||
security-events: write
|
||
|
||
steps:
|
||
- uses: actions/checkout@v4
|
||
|
||
- name: Download artifacts
|
||
uses: actions/download-artifact@v3
|
||
with:
|
||
name: build-artifacts
|
||
|
||
- name: Run Trivy vulnerability scanner
|
||
uses: aquasecurity/trivy-action@master
|
||
with:
|
||
scan-type: 'fs'
|
||
scan-ref: '.'
|
||
format: 'sarif'
|
||
output: 'trivy-results.sarif'
|
||
|
||
- name: Upload Trivy results
|
||
uses: github/codeql-action/upload-sarif@v2
|
||
with:
|
||
sarif_file: 'trivy-results.sarif'
|
||
|
||
- name: OWASP Dependency Check
|
||
uses: dependency-check/Dependency-Check_Action@main
|
||
with:
|
||
project: 'my-project'
|
||
path: '.'
|
||
format: 'SARIF'
|
||
args: >
|
||
--enableRetired
|
||
--enableExperimental
|
||
--failOnCVSS 7
|
||
|
||
# ステージ3: E2Eテスト
|
||
e2e-tests:
|
||
name: E2E Tests
|
||
runs-on: ubuntu-latest
|
||
needs: build-and-test
|
||
|
||
services:
|
||
postgres:
|
||
image: postgres:15
|
||
env:
|
||
POSTGRES_PASSWORD: postgres
|
||
POSTGRES_DB: testdb
|
||
options: >-
|
||
--health-cmd pg_isready
|
||
--health-interval 10s
|
||
--health-timeout 5s
|
||
--health-retries 5
|
||
ports:
|
||
- 5432:5432
|
||
|
||
redis:
|
||
image: redis:7
|
||
options: >-
|
||
--health-cmd "redis-cli ping"
|
||
--health-interval 10s
|
||
--health-timeout 5s
|
||
--health-retries 5
|
||
ports:
|
||
- 6379:6379
|
||
|
||
steps:
|
||
- uses: actions/checkout@v4
|
||
|
||
- name: Download artifacts
|
||
uses: actions/download-artifact@v3
|
||
with:
|
||
name: build-artifacts
|
||
|
||
- name: Setup Node.js
|
||
uses: actions/setup-node@v4
|
||
with:
|
||
node-version: '18'
|
||
cache: 'npm'
|
||
|
||
- name: Install dependencies
|
||
run: npm ci
|
||
|
||
- name: Setup test database
|
||
run: |
|
||
npm run db:migrate
|
||
npm run db:seed
|
||
env:
|
||
DATABASE_URL: postgresql://postgres:postgres@localhost:5432/testdb
|
||
|
||
- name: Install Playwright
|
||
run: npx playwright install --with-deps
|
||
|
||
- name: Start application
|
||
run: |
|
||
npm start &
|
||
npx wait-on http://localhost:3000 --timeout 60000
|
||
env:
|
||
NODE_ENV: test
|
||
DATABASE_URL: postgresql://postgres:postgres@localhost:5432/testdb
|
||
REDIS_URL: redis://localhost:6379
|
||
|
||
- name: Run E2E tests
|
||
run: npm run test:e2e
|
||
env:
|
||
BASE_URL: http://localhost:3000
|
||
|
||
- name: Upload test results
|
||
uses: actions/upload-artifact@v3
|
||
if: failure()
|
||
with:
|
||
name: e2e-results
|
||
path: |
|
||
test-results/
|
||
playwright-report/
|
||
|
||
# ステージ4: Dockerイメージビルド
|
||
build-image:
|
||
name: Build Docker Image
|
||
runs-on: ubuntu-latest
|
||
needs: [build-and-test, security-scan]
|
||
if: github.event_name == 'push'
|
||
|
||
permissions:
|
||
contents: read
|
||
packages: write
|
||
|
||
outputs:
|
||
image: ${{ steps.image.outputs.image }}
|
||
digest: ${{ steps.build.outputs.digest }}
|
||
|
||
steps:
|
||
- name: Checkout
|
||
uses: actions/checkout@v4
|
||
|
||
- name: Download artifacts
|
||
uses: actions/download-artifact@v3
|
||
with:
|
||
name: build-artifacts
|
||
|
||
- name: Set up Docker Buildx
|
||
uses: docker/setup-buildx-action@v3
|
||
|
||
- name: Log in to Container Registry
|
||
uses: docker/login-action@v3
|
||
with:
|
||
registry: ${{ env.REGISTRY }}
|
||
username: ${{ github.actor }}
|
||
password: ${{ secrets.GITHUB_TOKEN }}
|
||
|
||
- name: Extract metadata
|
||
id: meta
|
||
uses: docker/metadata-action@v5
|
||
with:
|
||
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
|
||
tags: |
|
||
type=ref,event=branch
|
||
type=ref,event=pr
|
||
type=semver,pattern={{version}}
|
||
type=semver,pattern={{major}}.{{minor}}
|
||
type=sha,prefix={{branch}}-
|
||
|
||
- name: Build and push image
|
||
id: build
|
||
uses: docker/build-push-action@v5
|
||
with:
|
||
context: .
|
||
push: true
|
||
tags: ${{ steps.meta.outputs.tags }}
|
||
labels: ${{ steps.meta.outputs.labels }}
|
||
cache-from: type=gha
|
||
cache-to: type=gha,mode=max
|
||
build-args: |
|
||
VERSION=${{ needs.build-and-test.outputs.version }}
|
||
|
||
- name: Output image
|
||
id: image
|
||
run: echo "image=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ needs.build-and-test.outputs.version }}" >> $GITHUB_OUTPUT
|
||
|
||
# ステージ5: ステージング環境デプロイ
|
||
deploy-staging:
|
||
name: Deploy to Staging
|
||
runs-on: ubuntu-latest
|
||
needs: [build-image, e2e-tests]
|
||
if: github.ref == 'refs/heads/develop'
|
||
|
||
environment:
|
||
name: staging
|
||
url: https://staging.example.com
|
||
|
||
steps:
|
||
- name: Deploy to staging
|
||
uses: azure/webapps-deploy@v2
|
||
with:
|
||
app-name: 'my-app-staging'
|
||
publish-profile: ${{ secrets.AZURE_WEBAPP_PUBLISH_PROFILE_STAGING }}
|
||
images: ${{ needs.build-image.outputs.image }}
|
||
|
||
- name: Run smoke tests
|
||
run: |
|
||
curl -f https://staging.example.com/health || exit 1
|
||
curl -f https://staging.example.com/api/status || exit 1
|
||
|
||
# ステージ6: 本番環境デプロイ
|
||
deploy-production:
|
||
name: Deploy to Production
|
||
runs-on: ubuntu-latest
|
||
needs: [build-image, deploy-staging]
|
||
if: github.ref == 'refs/heads/main'
|
||
|
||
environment:
|
||
name: production
|
||
url: https://example.com
|
||
|
||
steps:
|
||
- name: Deploy to production
|
||
uses: azure/webapps-deploy@v2
|
||
with:
|
||
app-name: 'my-app-production'
|
||
publish-profile: ${{ secrets.AZURE_WEBAPP_PUBLISH_PROFILE_PRODUCTION }}
|
||
images: ${{ needs.build-image.outputs.image }}
|
||
|
||
- name: Run production smoke tests
|
||
run: |
|
||
curl -f https://example.com/health || exit 1
|
||
curl -f https://example.com/api/status || exit 1
|
||
|
||
- name: Notify deployment
|
||
uses: 8398a7/action-slack@v3
|
||
with:
|
||
status: ${{ job.status }}
|
||
channel: '#deployments'
|
||
webhook_url: ${{ secrets.SLACK_WEBHOOK }}
|
||
if: always()
|
||
```
|
||
|
||
### 🐍 Python アプリケーション用
|
||
```yaml
|
||
# .github/workflows/python-cicd.yml
|
||
name: Python CI/CD Pipeline
|
||
|
||
on:
|
||
push:
|
||
branches: [main, develop]
|
||
pull_request:
|
||
branches: [main]
|
||
|
||
jobs:
|
||
test:
|
||
name: Test Suite
|
||
runs-on: ubuntu-latest
|
||
|
||
strategy:
|
||
matrix:
|
||
python-version: ['3.8', '3.9', '3.10', '3.11']
|
||
|
||
services:
|
||
postgres:
|
||
image: postgres:15
|
||
env:
|
||
POSTGRES_PASSWORD: postgres
|
||
POSTGRES_DB: testdb
|
||
options: >-
|
||
--health-cmd pg_isready
|
||
--health-interval 10s
|
||
--health-timeout 5s
|
||
--health-retries 5
|
||
ports:
|
||
- 5432:5432
|
||
|
||
steps:
|
||
- uses: actions/checkout@v4
|
||
|
||
- name: Set up Python ${{ matrix.python-version }}
|
||
uses: actions/setup-python@v4
|
||
with:
|
||
python-version: ${{ matrix.python-version }}
|
||
|
||
- name: Cache dependencies
|
||
uses: actions/cache@v3
|
||
with:
|
||
path: ~/.cache/pip
|
||
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
|
||
restore-keys: |
|
||
${{ runner.os }}-pip-
|
||
|
||
- name: Install dependencies
|
||
run: |
|
||
python -m pip install --upgrade pip
|
||
pip install -r requirements.txt
|
||
pip install -r requirements-dev.txt
|
||
|
||
- name: Lint with flake8
|
||
run: |
|
||
flake8 src/ tests/ --count --select=E9,F63,F7,F82 --show-source --statistics
|
||
flake8 src/ tests/ --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics
|
||
|
||
- name: Type check with mypy
|
||
run: mypy src/
|
||
|
||
- name: Test with pytest
|
||
run: |
|
||
pytest tests/ --cov=src/ --cov-report=xml --cov-report=html
|
||
env:
|
||
DATABASE_URL: postgresql://postgres:postgres@localhost:5432/testdb
|
||
|
||
- name: Upload coverage to Codecov
|
||
uses: codecov/codecov-action@v3
|
||
with:
|
||
file: ./coverage.xml
|
||
flags: unittests
|
||
name: codecov-umbrella
|
||
|
||
security:
|
||
name: Security Scan
|
||
runs-on: ubuntu-latest
|
||
|
||
steps:
|
||
- uses: actions/checkout@v4
|
||
|
||
- name: Set up Python
|
||
uses: actions/setup-python@v4
|
||
with:
|
||
python-version: '3.11'
|
||
|
||
- name: Install dependencies
|
||
run: |
|
||
python -m pip install --upgrade pip
|
||
pip install safety bandit
|
||
|
||
- name: Run safety check
|
||
run: safety check
|
||
|
||
- name: Run bandit security check
|
||
run: bandit -r src/ -f json -o bandit-report.json
|
||
|
||
- name: Upload security scan results
|
||
uses: actions/upload-artifact@v3
|
||
if: failure()
|
||
with:
|
||
name: security-reports
|
||
path: bandit-report.json
|
||
|
||
build-and-deploy:
|
||
name: Build and Deploy
|
||
runs-on: ubuntu-latest
|
||
needs: [test, security]
|
||
if: github.ref == 'refs/heads/main'
|
||
|
||
steps:
|
||
- uses: actions/checkout@v4
|
||
|
||
- name: Set up Python
|
||
uses: actions/setup-python@v4
|
||
with:
|
||
python-version: '3.11'
|
||
|
||
- name: Build package
|
||
run: |
|
||
python -m pip install --upgrade pip build
|
||
python -m build
|
||
|
||
- name: Deploy to PyPI
|
||
uses: pypa/gh-action-pypi-publish@release/v1
|
||
with:
|
||
password: ${{ secrets.PYPI_API_TOKEN }}
|
||
```
|
||
|
||
---
|
||
|
||
## 3. 高度なワークフロー設計
|
||
|
||
### 🔄 再利用可能ワークフロー
|
||
|
||
#### 共通CI/CDテンプレート
|
||
```yaml
|
||
# .github/workflows/reusable-ci.yml
|
||
name: Reusable CI Workflow
|
||
|
||
on:
|
||
workflow_call:
|
||
inputs:
|
||
node-version:
|
||
required: false
|
||
type: string
|
||
default: '18'
|
||
environment:
|
||
required: false
|
||
type: string
|
||
default: 'development'
|
||
run-e2e:
|
||
required: false
|
||
type: boolean
|
||
default: false
|
||
secrets:
|
||
NPM_TOKEN:
|
||
required: false
|
||
CODECOV_TOKEN:
|
||
required: false
|
||
outputs:
|
||
build-version:
|
||
description: "Built application version"
|
||
value: ${{ jobs.build.outputs.version }}
|
||
artifact-name:
|
||
description: "Build artifact name"
|
||
value: ${{ jobs.build.outputs.artifact-name }}
|
||
|
||
jobs:
|
||
build:
|
||
name: Build and Test
|
||
runs-on: ubuntu-latest
|
||
|
||
outputs:
|
||
version: ${{ steps.version.outputs.version }}
|
||
artifact-name: ${{ steps.artifact.outputs.name }}
|
||
|
||
steps:
|
||
- uses: actions/checkout@v4
|
||
|
||
- name: Setup Node.js
|
||
uses: actions/setup-node@v4
|
||
with:
|
||
node-version: ${{ inputs.node-version }}
|
||
cache: 'npm'
|
||
registry-url: 'https://registry.npmjs.org'
|
||
|
||
- name: Generate version
|
||
id: version
|
||
run: |
|
||
VERSION=$(date +%Y%m%d)-$(git rev-parse --short HEAD)
|
||
echo "version=$VERSION" >> $GITHUB_OUTPUT
|
||
|
||
- name: Install dependencies
|
||
run: npm ci
|
||
env:
|
||
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||
|
||
- name: Run tests
|
||
run: npm run test:coverage
|
||
|
||
- name: Upload coverage
|
||
if: secrets.CODECOV_TOKEN != ''
|
||
uses: codecov/codecov-action@v3
|
||
with:
|
||
token: ${{ secrets.CODECOV_TOKEN }}
|
||
|
||
- name: Build application
|
||
run: npm run build
|
||
env:
|
||
NODE_ENV: ${{ inputs.environment }}
|
||
VERSION: ${{ steps.version.outputs.version }}
|
||
|
||
- name: Create artifact
|
||
id: artifact
|
||
run: |
|
||
ARTIFACT_NAME="build-${{ steps.version.outputs.version }}"
|
||
echo "name=$ARTIFACT_NAME" >> $GITHUB_OUTPUT
|
||
|
||
- name: Upload artifacts
|
||
uses: actions/upload-artifact@v3
|
||
with:
|
||
name: ${{ steps.artifact.outputs.name }}
|
||
path: dist/
|
||
|
||
e2e-tests:
|
||
name: E2E Tests
|
||
runs-on: ubuntu-latest
|
||
needs: build
|
||
if: inputs.run-e2e
|
||
|
||
steps:
|
||
- uses: actions/checkout@v4
|
||
|
||
- name: Download artifacts
|
||
uses: actions/download-artifact@v3
|
||
with:
|
||
name: ${{ needs.build.outputs.artifact-name }}
|
||
path: dist/
|
||
|
||
- name: Setup Node.js
|
||
uses: actions/setup-node@v4
|
||
with:
|
||
node-version: ${{ inputs.node-version }}
|
||
cache: 'npm'
|
||
|
||
- name: Install dependencies
|
||
run: npm ci
|
||
|
||
- name: Install Playwright
|
||
run: npx playwright install --with-deps
|
||
|
||
- name: Run E2E tests
|
||
run: npm run test:e2e
|
||
```
|
||
|
||
#### ワークフローの呼び出し
|
||
```yaml
|
||
# .github/workflows/main-ci.yml
|
||
name: Main CI Pipeline
|
||
|
||
on:
|
||
push:
|
||
branches: [main]
|
||
pull_request:
|
||
branches: [main]
|
||
|
||
jobs:
|
||
ci:
|
||
name: Continuous Integration
|
||
uses: ./.github/workflows/reusable-ci.yml
|
||
with:
|
||
node-version: '18'
|
||
environment: 'production'
|
||
run-e2e: true
|
||
secrets:
|
||
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
|
||
|
||
deploy:
|
||
name: Deploy Application
|
||
runs-on: ubuntu-latest
|
||
needs: ci
|
||
if: github.ref == 'refs/heads/main'
|
||
|
||
steps:
|
||
- name: Download build artifacts
|
||
uses: actions/download-artifact@v3
|
||
with:
|
||
name: ${{ needs.ci.outputs.artifact-name }}
|
||
|
||
- name: Deploy to production
|
||
run: |
|
||
echo "Deploying version ${{ needs.ci.outputs.build-version }}"
|
||
# デプロイメントロジック
|
||
```
|
||
|
||
### 🎯 コンポジットアクション
|
||
|
||
#### カスタムアクション作成
|
||
```yaml
|
||
# .github/actions/setup-app/action.yml
|
||
name: 'Setup Application'
|
||
description: 'Setup Node.js application with caching and dependencies'
|
||
|
||
inputs:
|
||
node-version:
|
||
description: 'Node.js version to use'
|
||
required: false
|
||
default: '18'
|
||
cache-dependency-path:
|
||
description: 'Path to dependency file'
|
||
required: false
|
||
default: 'package-lock.json'
|
||
install-command:
|
||
description: 'Command to install dependencies'
|
||
required: false
|
||
default: 'npm ci'
|
||
|
||
outputs:
|
||
cache-hit:
|
||
description: 'Cache hit status'
|
||
value: ${{ steps.cache.outputs.cache-hit }}
|
||
node-version:
|
||
description: 'Installed Node.js version'
|
||
value: ${{ steps.setup-node.outputs.node-version }}
|
||
|
||
runs:
|
||
using: 'composite'
|
||
steps:
|
||
- name: Setup Node.js
|
||
id: setup-node
|
||
uses: actions/setup-node@v4
|
||
with:
|
||
node-version: ${{ inputs.node-version }}
|
||
cache: 'npm'
|
||
cache-dependency-path: ${{ inputs.cache-dependency-path }}
|
||
|
||
- name: Cache node modules
|
||
id: cache
|
||
uses: actions/cache@v3
|
||
with:
|
||
path: ~/.npm
|
||
key: ${{ runner.os }}-node-${{ hashFiles(inputs.cache-dependency-path) }}
|
||
restore-keys: |
|
||
${{ runner.os }}-node-
|
||
|
||
- name: Install dependencies
|
||
shell: bash
|
||
run: ${{ inputs.install-command }}
|
||
env:
|
||
NODE_AUTH_TOKEN: ${{ env.NODE_AUTH_TOKEN }}
|
||
|
||
- name: Verify installation
|
||
shell: bash
|
||
run: |
|
||
echo "Node.js version: $(node --version)"
|
||
echo "npm version: $(npm --version)"
|
||
echo "Dependencies installed successfully"
|
||
```
|
||
|
||
#### アクションの使用
|
||
```yaml
|
||
# ワークフローでの使用例
|
||
steps:
|
||
- uses: actions/checkout@v4
|
||
|
||
- name: Setup application
|
||
uses: ./.github/actions/setup-app
|
||
with:
|
||
node-version: '18'
|
||
install-command: 'npm ci --production'
|
||
|
||
- name: Build application
|
||
run: npm run build
|
||
```
|
||
|
||
---
|
||
|
||
## 4. セキュリティ・シークレット管理
|
||
|
||
### 🔐 シークレット管理戦略
|
||
|
||
#### 環境別シークレット設定
|
||
```yaml
|
||
# セキュリティベストプラクティス
|
||
name: Secure Deployment
|
||
|
||
on:
|
||
push:
|
||
branches: [main]
|
||
|
||
jobs:
|
||
deploy:
|
||
name: Secure Deployment
|
||
runs-on: ubuntu-latest
|
||
|
||
# 環境の設定
|
||
environment:
|
||
name: production
|
||
url: https://example.com
|
||
|
||
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: ${{ vars.AWS_REGION }}
|
||
role-to-assume: ${{ secrets.AWS_ROLE_ARN }}
|
||
role-session-name: GitHubActions
|
||
|
||
- name: Login to Amazon ECR
|
||
id: login-ecr
|
||
uses: aws-actions/amazon-ecr-login@v2
|
||
|
||
- name: Build and push Docker image
|
||
env:
|
||
ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
|
||
ECR_REPOSITORY: ${{ vars.ECR_REPOSITORY }}
|
||
IMAGE_TAG: ${{ github.sha }}
|
||
run: |
|
||
docker build -t $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG .
|
||
docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG
|
||
|
||
- name: Deploy to ECS
|
||
run: |
|
||
aws ecs update-service \
|
||
--cluster ${{ vars.ECS_CLUSTER }} \
|
||
--service ${{ vars.ECS_SERVICE }} \
|
||
--force-new-deployment
|
||
```
|
||
|
||
#### OIDC プロバイダー認証
|
||
```yaml
|
||
# クラウドプロバイダーとのOIDC認証
|
||
name: OIDC Authentication
|
||
|
||
on:
|
||
push:
|
||
branches: [main]
|
||
|
||
permissions:
|
||
id-token: write # OIDC トークン取得に必要
|
||
contents: read
|
||
|
||
jobs:
|
||
deploy-aws:
|
||
runs-on: ubuntu-latest
|
||
steps:
|
||
- uses: actions/checkout@v4
|
||
|
||
- name: Configure AWS credentials
|
||
uses: aws-actions/configure-aws-credentials@v4
|
||
with:
|
||
role-to-assume: arn:aws:iam::123456789012:role/GitHubActionsRole
|
||
role-session-name: GitHubActions
|
||
aws-region: us-east-1
|
||
|
||
- name: Deploy to AWS
|
||
run: |
|
||
aws s3 sync ./dist s3://${{ vars.S3_BUCKET }}/
|
||
|
||
deploy-azure:
|
||
runs-on: ubuntu-latest
|
||
steps:
|
||
- uses: actions/checkout@v4
|
||
|
||
- name: Azure Login
|
||
uses: azure/login@v1
|
||
with:
|
||
client-id: ${{ secrets.AZURE_CLIENT_ID }}
|
||
tenant-id: ${{ secrets.AZURE_TENANT_ID }}
|
||
subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
|
||
|
||
- name: Deploy to Azure
|
||
run: |
|
||
az webapp deployment source config-zip \
|
||
--resource-group ${{ vars.AZURE_RESOURCE_GROUP }} \
|
||
--name ${{ vars.AZURE_APP_NAME }} \
|
||
--src ./dist.zip
|
||
```
|
||
|
||
### 🛡️ セキュリティスキャン自動化
|
||
|
||
#### 包括的セキュリティチェック
|
||
```yaml
|
||
# .github/workflows/security-scan.yml
|
||
name: Security Scanning
|
||
|
||
on:
|
||
push:
|
||
branches: [main, develop]
|
||
pull_request:
|
||
branches: [main]
|
||
schedule:
|
||
- cron: '0 3 * * 1' # 毎週月曜 3時
|
||
|
||
permissions:
|
||
security-events: write
|
||
contents: read
|
||
|
||
jobs:
|
||
code-scanning:
|
||
name: Code Scanning
|
||
runs-on: ubuntu-latest
|
||
|
||
strategy:
|
||
matrix:
|
||
language: ['javascript', 'python']
|
||
|
||
steps:
|
||
- uses: actions/checkout@v4
|
||
|
||
- name: Initialize CodeQL
|
||
uses: github/codeql-action/init@v2
|
||
with:
|
||
languages: ${{ matrix.language }}
|
||
queries: security-extended,security-and-quality
|
||
|
||
- name: Autobuild
|
||
uses: github/codeql-action/autobuild@v2
|
||
|
||
- name: Perform CodeQL Analysis
|
||
uses: github/codeql-action/analyze@v2
|
||
with:
|
||
category: "/language:${{matrix.language}}"
|
||
|
||
dependency-scanning:
|
||
name: Dependency Scanning
|
||
runs-on: ubuntu-latest
|
||
|
||
steps:
|
||
- uses: actions/checkout@v4
|
||
|
||
- name: Run Trivy vulnerability scanner
|
||
uses: aquasecurity/trivy-action@master
|
||
with:
|
||
scan-type: 'fs'
|
||
scan-ref: '.'
|
||
format: 'sarif'
|
||
output: 'trivy-results.sarif'
|
||
|
||
- name: Upload Trivy scan results
|
||
uses: github/codeql-action/upload-sarif@v2
|
||
with:
|
||
sarif_file: 'trivy-results.sarif'
|
||
|
||
- name: Snyk security scan
|
||
uses: snyk/actions/node@master
|
||
env:
|
||
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
|
||
with:
|
||
args: --severity-threshold=high --sarif-file-output=snyk.sarif
|
||
|
||
- name: Upload Snyk results
|
||
uses: github/codeql-action/upload-sarif@v2
|
||
with:
|
||
sarif_file: snyk.sarif
|
||
|
||
container-scanning:
|
||
name: Container Scanning
|
||
runs-on: ubuntu-latest
|
||
if: github.event_name == 'push'
|
||
|
||
steps:
|
||
- uses: actions/checkout@v4
|
||
|
||
- name: Build Docker image
|
||
run: docker build -t test-image .
|
||
|
||
- name: Run Trivy container scan
|
||
uses: aquasecurity/trivy-action@master
|
||
with:
|
||
image-ref: 'test-image'
|
||
format: 'sarif'
|
||
output: 'trivy-container.sarif'
|
||
|
||
- name: Upload container scan results
|
||
uses: github/codeql-action/upload-sarif@v2
|
||
with:
|
||
sarif_file: 'trivy-container.sarif'
|
||
|
||
secret-scanning:
|
||
name: Secret Scanning
|
||
runs-on: ubuntu-latest
|
||
|
||
steps:
|
||
- uses: actions/checkout@v4
|
||
with:
|
||
fetch-depth: 0
|
||
|
||
- name: TruffleHog OSS
|
||
uses: trufflesecurity/trufflehog@main
|
||
with:
|
||
path: ./
|
||
base: main
|
||
head: HEAD
|
||
extra_args: --debug --only-verified
|
||
```
|
||
|
||
---
|
||
|
||
## 5. 外部ツールからの移行
|
||
|
||
### 🔄 Jenkins からの移行
|
||
|
||
#### Jenkinsfile → GitHub Actions 変換例
|
||
```groovy
|
||
// 元のJenkinsfile
|
||
pipeline {
|
||
agent any
|
||
|
||
environment {
|
||
NODE_VERSION = '18'
|
||
DOCKER_REGISTRY = 'myregistry.com'
|
||
}
|
||
|
||
stages {
|
||
stage('Checkout') {
|
||
steps {
|
||
checkout scm
|
||
}
|
||
}
|
||
|
||
stage('Build') {
|
||
steps {
|
||
sh 'npm ci'
|
||
sh 'npm run build'
|
||
}
|
||
}
|
||
|
||
stage('Test') {
|
||
parallel {
|
||
stage('Unit Tests') {
|
||
steps {
|
||
sh 'npm run test:unit'
|
||
}
|
||
post {
|
||
always {
|
||
publishTestResults testResultsPattern: 'test-results.xml'
|
||
}
|
||
}
|
||
}
|
||
|
||
stage('E2E Tests') {
|
||
steps {
|
||
sh 'npm run test:e2e'
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
stage('Deploy') {
|
||
when {
|
||
branch 'main'
|
||
}
|
||
steps {
|
||
sh 'docker build -t $DOCKER_REGISTRY/myapp:$BUILD_NUMBER .'
|
||
sh 'docker push $DOCKER_REGISTRY/myapp:$BUILD_NUMBER'
|
||
}
|
||
}
|
||
}
|
||
|
||
post {
|
||
always {
|
||
cleanWs()
|
||
}
|
||
failure {
|
||
mail to: 'team@example.com',
|
||
subject: "Build Failed: ${env.JOB_NAME} - ${env.BUILD_NUMBER}",
|
||
body: "Build failed. Check console output."
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
```yaml
|
||
# 変換後のGitHub Actions
|
||
name: Migrated from Jenkins
|
||
|
||
on:
|
||
push:
|
||
branches: [main, develop]
|
||
pull_request:
|
||
branches: [main]
|
||
|
||
env:
|
||
NODE_VERSION: '18'
|
||
DOCKER_REGISTRY: 'myregistry.com'
|
||
|
||
jobs:
|
||
build:
|
||
name: Build Application
|
||
runs-on: ubuntu-latest
|
||
|
||
outputs:
|
||
build-number: ${{ steps.build-number.outputs.number }}
|
||
|
||
steps:
|
||
- name: Checkout
|
||
uses: actions/checkout@v4
|
||
|
||
- name: Generate build number
|
||
id: build-number
|
||
run: echo "number=${{ github.run_number }}" >> $GITHUB_OUTPUT
|
||
|
||
- name: Setup Node.js
|
||
uses: actions/setup-node@v4
|
||
with:
|
||
node-version: ${{ env.NODE_VERSION }}
|
||
cache: 'npm'
|
||
|
||
- name: Install dependencies
|
||
run: npm ci
|
||
|
||
- name: Build application
|
||
run: npm run build
|
||
|
||
- name: Upload build artifacts
|
||
uses: actions/upload-artifact@v3
|
||
with:
|
||
name: build-artifacts
|
||
path: dist/
|
||
|
||
test:
|
||
name: Test Suite
|
||
runs-on: ubuntu-latest
|
||
needs: build
|
||
|
||
strategy:
|
||
matrix:
|
||
test-type: [unit, e2e]
|
||
|
||
steps:
|
||
- uses: actions/checkout@v4
|
||
|
||
- name: Setup Node.js
|
||
uses: actions/setup-node@v4
|
||
with:
|
||
node-version: ${{ env.NODE_VERSION }}
|
||
cache: 'npm'
|
||
|
||
- name: Install dependencies
|
||
run: npm ci
|
||
|
||
- name: Download artifacts
|
||
uses: actions/download-artifact@v3
|
||
with:
|
||
name: build-artifacts
|
||
path: dist/
|
||
|
||
- name: Run tests
|
||
run: npm run test:${{ matrix.test-type }}
|
||
|
||
- name: Publish test results
|
||
uses: dorny/test-reporter@v1
|
||
if: success() || failure()
|
||
with:
|
||
name: ${{ matrix.test-type }} Tests
|
||
path: test-results.xml
|
||
reporter: jest-junit
|
||
|
||
deploy:
|
||
name: Deploy Application
|
||
runs-on: ubuntu-latest
|
||
needs: [build, test]
|
||
if: github.ref == 'refs/heads/main'
|
||
|
||
steps:
|
||
- uses: actions/checkout@v4
|
||
|
||
- name: Set up Docker Buildx
|
||
uses: docker/setup-buildx-action@v3
|
||
|
||
- name: Login to registry
|
||
uses: docker/login-action@v3
|
||
with:
|
||
registry: ${{ env.DOCKER_REGISTRY }}
|
||
username: ${{ secrets.DOCKER_USERNAME }}
|
||
password: ${{ secrets.DOCKER_PASSWORD }}
|
||
|
||
- name: Build and push image
|
||
uses: docker/build-push-action@v5
|
||
with:
|
||
context: .
|
||
push: true
|
||
tags: ${{ env.DOCKER_REGISTRY }}/myapp:${{ needs.build.outputs.build-number }}
|
||
|
||
- name: Notify on failure
|
||
if: failure()
|
||
uses: 8398a7/action-slack@v3
|
||
with:
|
||
status: failure
|
||
channel: '#alerts'
|
||
webhook_url: ${{ secrets.SLACK_WEBHOOK }}
|
||
message: |
|
||
Build Failed: ${{ github.workflow }} - ${{ github.run_number }}
|
||
Check the console output for details.
|
||
```
|
||
|
||
### 📊 移行比較表
|
||
|
||
| 機能 | Jenkins | CircleCI | GitLab CI | GitHub Actions | 備考 |
|
||
|------|---------|----------|-----------|----------------|------|
|
||
| **セットアップ** | 複雑 | 簡単 | 中程度 | 最も簡単 | GitHub統合 |
|
||
| **設定ファイル** | Groovy | YAML | YAML | YAML | GitHub Actionsが最も直感的 |
|
||
| **並列実行** | ✅ | ✅ | ✅ | ✅ | matrix戦略が優秀 |
|
||
| **キャッシュ** | プラグイン | ✅ | ✅ | ✅ | 設定が最もシンプル |
|
||
| **シークレット管理** | プラグイン | ✅ | ✅ | ✅ | 環境別管理が優秀 |
|
||
| **コスト(中規模)** | 高 | 中 | 中 | 低 | 無料枠が大きい |
|
||
| **学習コスト** | 高 | 中 | 中 | 低 | 広く普及 |
|
||
| **拡張性** | 高 | 中 | 高 | 高 | Marketplaceが充実 |
|
||
|
||
---
|
||
|
||
## 6. 運用最適化・監視
|
||
|
||
### 📊 パフォーマンス最適化
|
||
|
||
#### 高速ビルド戦略
|
||
```yaml
|
||
# .github/workflows/optimized-ci.yml
|
||
name: Optimized CI Pipeline
|
||
|
||
on:
|
||
push:
|
||
branches: [main]
|
||
pull_request:
|
||
branches: [main]
|
||
|
||
jobs:
|
||
changes:
|
||
name: Detect Changes
|
||
runs-on: ubuntu-latest
|
||
outputs:
|
||
frontend: ${{ steps.changes.outputs.frontend }}
|
||
backend: ${{ steps.changes.outputs.backend }}
|
||
docs: ${{ steps.changes.outputs.docs }}
|
||
steps:
|
||
- uses: actions/checkout@v4
|
||
- uses: dorny/paths-filter@v2
|
||
id: changes
|
||
with:
|
||
filters: |
|
||
frontend:
|
||
- 'frontend/**'
|
||
- 'package.json'
|
||
backend:
|
||
- 'backend/**'
|
||
- 'requirements.txt'
|
||
docs:
|
||
- 'docs/**'
|
||
- '*.md'
|
||
|
||
frontend-ci:
|
||
name: Frontend CI
|
||
runs-on: ubuntu-latest
|
||
needs: changes
|
||
if: needs.changes.outputs.frontend == 'true'
|
||
|
||
steps:
|
||
- uses: actions/checkout@v4
|
||
|
||
- name: Setup Node.js with cache
|
||
uses: actions/setup-node@v4
|
||
with:
|
||
node-version: '18'
|
||
cache: 'npm'
|
||
cache-dependency-path: 'frontend/package-lock.json'
|
||
|
||
- name: Restore node_modules cache
|
||
uses: actions/cache@v3
|
||
with:
|
||
path: frontend/node_modules
|
||
key: ${{ runner.os }}-nodemodules-${{ hashFiles('frontend/package-lock.json') }}
|
||
restore-keys: |
|
||
${{ runner.os }}-nodemodules-
|
||
|
||
- name: Install dependencies
|
||
run: npm ci --prefix frontend
|
||
|
||
- name: Parallel build and test
|
||
run: |
|
||
npm run build --prefix frontend &
|
||
npm run test --prefix frontend &
|
||
wait
|
||
|
||
backend-ci:
|
||
name: Backend CI
|
||
runs-on: ubuntu-latest
|
||
needs: changes
|
||
if: needs.changes.outputs.backend == 'true'
|
||
|
||
steps:
|
||
- uses: actions/checkout@v4
|
||
|
||
- name: Setup Python with cache
|
||
uses: actions/setup-python@v4
|
||
with:
|
||
python-version: '3.11'
|
||
cache: 'pip'
|
||
cache-dependency-path: 'backend/requirements.txt'
|
||
|
||
- name: Install dependencies
|
||
run: |
|
||
cd backend
|
||
pip install -r requirements.txt
|
||
|
||
- name: Run tests
|
||
run: |
|
||
cd backend
|
||
pytest --maxfail=1 --disable-warnings -q
|
||
|
||
docs-check:
|
||
name: Documentation Check
|
||
runs-on: ubuntu-latest
|
||
needs: changes
|
||
if: needs.changes.outputs.docs == 'true'
|
||
|
||
steps:
|
||
- uses: actions/checkout@v4
|
||
|
||
- name: Check documentation
|
||
run: |
|
||
# ドキュメントの軽量チェック
|
||
echo "Checking documentation..."
|
||
# 実際のドキュメントビルド・リンクチェック等
|
||
```
|
||
|
||
### 📈 モニタリング・メトリクス
|
||
|
||
#### 詳細メトリクス収集
|
||
```yaml
|
||
# .github/workflows/metrics-collection.yml
|
||
name: CI/CD Metrics Collection
|
||
|
||
on:
|
||
workflow_run:
|
||
workflows: ["Main CI", "Deploy Pipeline"]
|
||
types: [completed]
|
||
|
||
jobs:
|
||
collect-metrics:
|
||
name: Collect CI/CD Metrics
|
||
runs-on: ubuntu-latest
|
||
|
||
steps:
|
||
- name: Collect workflow metrics
|
||
uses: actions/github-script@v6
|
||
with:
|
||
script: |
|
||
const workflowRun = context.payload.workflow_run;
|
||
|
||
// ワークフロー実行時間の計算
|
||
const startTime = new Date(workflowRun.created_at);
|
||
const endTime = new Date(workflowRun.updated_at);
|
||
const duration = (endTime - startTime) / 1000; // 秒
|
||
|
||
// メトリクスデータの作成
|
||
const metrics = {
|
||
workflow_name: workflowRun.name,
|
||
status: workflowRun.conclusion,
|
||
duration_seconds: duration,
|
||
commit_sha: workflowRun.head_sha,
|
||
branch: workflowRun.head_branch,
|
||
trigger_event: workflowRun.event,
|
||
run_number: workflowRun.run_number,
|
||
timestamp: workflowRun.created_at
|
||
};
|
||
|
||
// メトリクスをログ出力
|
||
console.log('CI/CD Metrics:', JSON.stringify(metrics, null, 2));
|
||
|
||
// 外部監視システムに送信(例:DataDog、Prometheus等)
|
||
if (process.env.DATADOG_API_KEY) {
|
||
await fetch('https://api.datadoghq.com/api/v1/series', {
|
||
method: 'POST',
|
||
headers: {
|
||
'Content-Type': 'application/json',
|
||
'DD-API-KEY': process.env.DATADOG_API_KEY
|
||
},
|
||
body: JSON.stringify({
|
||
series: [{
|
||
metric: 'github_actions.workflow.duration',
|
||
points: [[Math.floor(Date.now() / 1000), duration]],
|
||
tags: [
|
||
`workflow:${workflowRun.name}`,
|
||
`status:${workflowRun.conclusion}`,
|
||
`branch:${workflowRun.head_branch}`
|
||
]
|
||
}]
|
||
})
|
||
});
|
||
}
|
||
env:
|
||
DATADOG_API_KEY: ${{ secrets.DATADOG_API_KEY }}
|
||
|
||
- name: Generate weekly report
|
||
if: github.event.schedule == '0 9 * * 1' # 毎週月曜日
|
||
uses: actions/github-script@v6
|
||
with:
|
||
script: |
|
||
// 過去1週間のワークフロー実行データを取得
|
||
const { data: runs } = await github.rest.actions.listWorkflowRunsForRepo({
|
||
owner: context.repo.owner,
|
||
repo: context.repo.repo,
|
||
per_page: 100,
|
||
created: `>=${new Date(Date.now() - 7 * 24 * 60 * 60 * 1000).toISOString()}`
|
||
});
|
||
|
||
// メトリクス集計
|
||
const metrics = runs.workflow_runs.reduce((acc, run) => {
|
||
const duration = (new Date(run.updated_at) - new Date(run.created_at)) / 1000;
|
||
|
||
if (!acc[run.name]) {
|
||
acc[run.name] = {
|
||
total_runs: 0,
|
||
successful_runs: 0,
|
||
failed_runs: 0,
|
||
total_duration: 0,
|
||
avg_duration: 0
|
||
};
|
||
}
|
||
|
||
acc[run.name].total_runs++;
|
||
acc[run.name].total_duration += duration;
|
||
|
||
if (run.conclusion === 'success') {
|
||
acc[run.name].successful_runs++;
|
||
} else if (run.conclusion === 'failure') {
|
||
acc[run.name].failed_runs++;
|
||
}
|
||
|
||
acc[run.name].avg_duration = acc[run.name].total_duration / acc[run.name].total_runs;
|
||
|
||
return acc;
|
||
}, {});
|
||
|
||
// レポート生成
|
||
let report = '# GitHub Actions Weekly Report\n\n';
|
||
|
||
for (const [workflow, data] of Object.entries(metrics)) {
|
||
const successRate = ((data.successful_runs / data.total_runs) * 100).toFixed(2);
|
||
|
||
report += `## ${workflow}\n`;
|
||
report += `- **Total Runs**: ${data.total_runs}\n`;
|
||
report += `- **Success Rate**: ${successRate}%\n`;
|
||
report += `- **Average Duration**: ${Math.round(data.avg_duration)}s\n`;
|
||
report += `- **Failed Runs**: ${data.failed_runs}\n\n`;
|
||
}
|
||
|
||
// Issueとしてレポートを投稿
|
||
await github.rest.issues.create({
|
||
owner: context.repo.owner,
|
||
repo: context.repo.repo,
|
||
title: `Weekly CI/CD Report - ${new Date().toISOString().split('T')[0]}`,
|
||
body: report,
|
||
labels: ['metrics', 'weekly-report']
|
||
});
|
||
```
|
||
|
||
---
|
||
|
||
## 🎓 実践演習
|
||
|
||
### 演習1: フルスタックCI/CDパイプライン構築
|
||
1. **多言語対応** - Node.js + Python のモノレポ
|
||
2. **並列実行** - 言語別の独立したジョブ
|
||
3. **条件分岐** - 変更検知による最適化
|
||
4. **成果物管理** - アーティファクトの効率的な受け渡し
|
||
|
||
### 演習2: セキュリティファーストパイプライン
|
||
1. **コード解析** - CodeQL・Semgrep統合
|
||
2. **依存関係スキャン** - Snyk・Trivy活用
|
||
3. **シークレット検知** - TruffleHog導入
|
||
4. **コンテナセキュリティ** - イメージスキャン自動化
|
||
|
||
### 演習3: 外部ツール移行プロジェクト
|
||
1. **現状分析** - 既存CI/CDの機能・設定調査
|
||
2. **移行戦略** - 段階的移行計画立案
|
||
3. **並行運用** - リスク軽減・検証期間設定
|
||
4. **完全移行** - 旧システム停止・運用移管
|
||
|
||
---
|
||
|
||
## 🔗 関連リソース
|
||
|
||
### 公式ドキュメント
|
||
- [GitHub Actions Documentation](https://docs.github.com/en/actions)
|
||
- [Workflow Syntax](https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions)
|
||
- [GitHub Actions Marketplace](https://github.com/marketplace?type=actions)
|
||
|
||
### 移行・活用ツール
|
||
- [Jenkins to GitHub Actions Migration](https://github.com/actions/importer)
|
||
- [Actions Toolkit](https://github.com/actions/toolkit)
|
||
- [Runner Images](https://github.com/actions/runner-images)
|
||
|
||
### 監視・最適化ツール
|
||
- [ActionLint](https://github.com/rhymond/actionlint) - ワークフロー検証
|
||
- [GitHub Actions Usage Metrics](https://github.com/github/actions-usage-metrics)
|
||
- [Workflow Optimization Guide](https://docs.github.com/en/actions/using-workflows/about-workflows#using-starter-workflows)
|
||
|
||
---
|
||
|
||
## 📝 まとめ
|
||
|
||
GitHub Actions を効果的に活用することで:
|
||
|
||
✅ **外部ツール不要** - Jenkins・CircleCIからの完全移行
|
||
✅ **コスト大幅削減** - インフラ・ライセンス費用の最適化
|
||
✅ **統合開発環境** - コードとCI/CDの一元管理
|
||
✅ **高度な自動化** - セキュリティ・品質・デプロイの自動化
|
||
✅ **スケーラビリティ** - 企業レベルの大規模開発対応
|
||
|
||
次は[GitHub Security編](06-github-security.md)で、総合的なセキュリティ対策を学習しましょう。
|
||
|
||
## 🔗 関連ガイド
|
||
|
||
- **前のステップ**: [GitHub Projects編](04-github-projects.md) - プロジェクト管理の最適化
|
||
- **次のステップ**: [GitHub Security編](06-github-security.md) - 総合的なセキュリティ対策
|
||
- **さらに学習**: [GitHub Pages編](07-github-pages.md) - Webサイト・ドキュメント公開
|
||
- **基礎知識**: [Pull Request編](03-pull-requests.md) - CI/CD連携の基礎
|
||
- **総合ガイド**: [GitHub完全活用ガイド](../GITHUB_COMPLETE_GUIDE.md) - 全機能の詳細解説
|
||
|
||
## 📖 学習フロー
|
||
|
||
```mermaid
|
||
graph LR
|
||
A[リポジトリ基礎] --> B[Issues管理]
|
||
B --> C[Pull Request]
|
||
C --> D[GitHub Projects]
|
||
D --> E[GitHub Actions]
|
||
E --> F[Security]
|
||
F --> G[Pages]
|
||
G --> H[完全活用]
|
||
|
||
style A fill:#f3e5f5
|
||
style B fill:#f3e5f5
|
||
style C fill:#f3e5f5
|
||
style D fill:#f3e5f5
|
||
style E fill:#e1f5fe
|
||
style F fill:#e8f5e8
|
||
style G fill:#fff3e0
|
||
style H fill:#fce4ec
|
||
``` |