- Authors

- Name
- Youngju Kim
- @fjvbn20031
- はじめに
- 1. 2025年(ねん)のCI/CD現況(げんきょう)
- 2. CI/CDプラットフォーム比較(ひかく)
- 3. パイプライン設計(せっけい)原則(げんそく)
- 4. CIでのテスト戦略(せんりゃく)
- 5. Dockerビルド最適化(さいてきか)
- 6. GitOpsとArgoCD
- 7. CI/CDセキュリティ
- 8. デプロイ戦略(せんりゃく)比較(ひかく)
- 9. ロールバック戦略(せんりゃく)
- 10. パイプラインヘルスモニタリング
- 11. 面接(めんせつ)質問集(しつもんしゅう)
- 12. クイズ
- 13. 参考(さんこう)資料(しりょう)
はじめに
2025年(ねん)、CI/CDはもはや選択(せんたく)ではなく必須(ひっす)です。GoogleのDORA(DevOps Research and Assessment)レポートによると、Eliteレベルのチームは1日(にち)に複数回(ふくすうかい)デプロイしながらも、変更(へんこう)失敗率(しっぱいりつ)を5%未満(みまん)に維持(いじ)しています。一方(いっぽう)、Lowレベルのチームは月(つき)1回(かい)のデプロイで失敗率(しっぱいりつ)が46%に達(たっ)しています。
この格差(かくさ)の核心(かくしん)は**パイプライン設計(せっけい)**にあります。単(たん)にCI/CDツールを導入(どうにゅう)するだけでなく、テスト自動化(じどうか)、セキュリティ統合(とうごう)、段階的(だんかいてき)デプロイ、そして可観測性(かかんそくせい)まで含(ふく)む総合的(そうごうてき)な戦略(せんりゃく)が必要(ひつよう)です。
この記事(きじ)では、CI/CDパイプラインを設計(せっけい)・運用(うんよう)するために必要(ひつよう)な全(すべ)てをカバーします。プラットフォーム比較(ひかく)からパイプライン設計原則(げんそく)、テスト戦略(せんりゃく)、Dockerビルド最適化(さいてきか)、GitOps、セキュリティ、デプロイ戦略(せんりゃく)、ロールバック、そしてモニタリングまで実践(じっせん)中心(ちゅうしん)にまとめました。
1. 2025年(ねん)のCI/CD現況(げんきょう)
1.1 DORAメトリクスで見(み)るチームパフォーマンス
DORAメトリクスはソフトウェアデリバリーの成果(せいか)を測定(そくてい)する4つの核心(かくしん)指標(しひょう)です。
| 指標(しひょう) | Elite | High | Medium | Low |
|---|---|---|---|---|
| デプロイ頻度(ひんど) | 1日(にち)複数回(ふくすうかい) | 週1回〜月1回 | 月1回〜6ヶ月(げつ)1回 | 6ヶ月(げつ)以上(いじょう) |
| リードタイム(コミット→デプロイ) | 1時間(じかん)未満(みまん) | 1日〜1週間(しゅうかん) | 1週間〜1ヶ月 | 1ヶ月〜6ヶ月 |
| 変更(へんこう)失敗率(しっぱいりつ) | 0〜5% | 5〜10% | 10〜15% | 46〜60% |
| 復旧時間(ふっきゅうじかん)(MTTR) | 1時間未満 | 1日未満 | 1日〜1週間 | 6ヶ月以上 |
1.2 シフトレフト戦略(せんりゃく)
シフトレフト(Shift Left)は、テストとセキュリティを開発(かいはつ)の初期(しょき)段階(だんかい)に前倒(まえだお)しする戦略(せんりゃく)です。
従来のアプローチ:
Code → Build → Test → Security → Deploy → Monitor
↑ ここで問題発見
シフトレフト:
Code + Test + Security → Build → Deploy → Monitor
↑ ここで問題発見 (コスト10倍削減)
核心原則(かくしんげんそく):
- コミット前(まえ)検証(けんしょう): pre-commit hookでリント、フォーマット、シークレットスキャン
- PR段階(だんかい)テスト: ユニットテスト + 統合(とうごう)テスト + SAST自動実行(じっこう)
- ビルド時(じ)セキュリティ: コンテナイメージスキャン、依存関係(いぞんかんけい)脆弱性(ぜいじゃくせい)検査(けんさ)
- デプロイ前(まえ)検証(けんしょう): スモークテスト、カナリア分析(ぶんせき)
1.3 2025年(ねん)の主要(しゅよう)トレンド
- プラットフォームエンジニアリング: 開発者(かいはつしゃ)セルフサービスプラットフォームでCI/CD標準化(ひょうじゅんか)
- AI駆動(くどう)CI/CD: テスト失敗(しっぱい)予測(よそく)、自動(じどう)ロールバック判断(はんだん)、フレイキーテスト検出(けんしゅつ)
- eBPF基盤(きばん)の可観測性(かかんそくせい): パイプラインパフォーマンスモニタリングの新(あたら)しいパラダイム
- サプライチェーンセキュリティ: SBOM、SLSA、Sigstore基盤(きばん)のソフトウェアサプライチェーンセキュリティ
2. CI/CDプラットフォーム比較(ひかく)
2.1 主要(しゅよう)プラットフォーム比較表(ひかくひょう)
| 機能(きのう) | GitHub Actions | Jenkins | GitLab CI | CircleCI |
|---|---|---|---|---|
| ホスティング | SaaS/セルフホスト | セルフホスト | SaaS/セルフホスト | SaaS |
| 設定方式(ほうしき) | YAML | Groovy/YAML | YAML | YAML |
| エコシステム | Marketplace 15,000+ | Plugin 1,800+ | ビルトイン統合(とうごう) | Orbs 3,000+ |
| コンテナサポート | ネイティブ | プラグイン | ネイティブ | ネイティブ |
| セルフランナー | 対応(たいおう) | デフォルト | 対応 | 対応 |
| 価格(かかく) | 2,000分(ふん)無料(むりょう)/月 | 無料(OSS) | 400分無料/月 | 6,000クレジット無料/月 |
| 学習(がくしゅう)コスト | 低(ひく)い | 高(たか)い | 中程度(ちゅうていど) | 低い |
| キャッシュ | 10GB/リポ | プラグイン | ネイティブ | ネイティブ |
2.2 GitHub Actions
# .github/workflows/ci.yml
name: CI Pipeline
on:
pull_request:
branches: [main]
push:
branches: [main]
concurrency:
group: ci-${{ '{{' }} github.ref {{ '}}' }}
cancel-in-progress: true
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
cache: 'npm'
- run: npm ci
- run: npm run lint
test:
runs-on: ubuntu-latest
needs: lint
strategy:
matrix:
shard: [1, 2, 3, 4]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
cache: 'npm'
- run: npm ci
- run: npm test -- --shard=${{ '{{' }} matrix.shard {{ '}}' }}/4
build:
runs-on: ubuntu-latest
needs: test
steps:
- uses: actions/checkout@v4
- uses: docker/setup-buildx-action@v3
- uses: docker/build-push-action@v5
with:
context: .
push: true
tags: myapp:latest
cache-from: type=gha
cache-to: type=gha,mode=max
2.3 Jenkinsパイプライン
// Jenkinsfile (Declarative Pipeline)
pipeline {
agent any
environment {
DOCKER_REGISTRY = 'registry.example.com'
IMAGE_NAME = 'myapp'
}
stages {
stage('Checkout') {
steps {
checkout scm
}
}
stage('Lint & Test') {
parallel {
stage('Lint') {
steps {
sh 'npm run lint'
}
}
stage('Unit Test') {
steps {
sh 'npm test -- --coverage'
}
post {
always {
junit 'reports/junit.xml'
}
}
}
}
}
stage('Build & Push') {
steps {
script {
def image = docker.build("${DOCKER_REGISTRY}/${IMAGE_NAME}:${BUILD_NUMBER}")
docker.withRegistry("https://${DOCKER_REGISTRY}", 'registry-credentials') {
image.push()
image.push('latest')
}
}
}
}
}
post {
failure {
slackSend(
channel: '#ci-alerts',
color: 'danger',
message: "Build FAILED: ${env.JOB_NAME} #${env.BUILD_NUMBER}"
)
}
}
}
2.4 GitLab CI
# .gitlab-ci.yml
stages:
- lint
- test
- build
- deploy
variables:
DOCKER_HOST: tcp://docker:2376
lint:
stage: lint
image: node:20-alpine
cache:
key: npm-cache
paths:
- node_modules/
script:
- npm ci
- npm run lint
test:
stage: test
image: node:20-alpine
parallel: 4
script:
- npm ci
- npm test -- --shard=$CI_NODE_INDEX/$CI_NODE_TOTAL
coverage: '/Statements\s*:\s*(\d+\.?\d*)%/'
artifacts:
reports:
junit: reports/junit.xml
build:
stage: build
image: docker:24
services:
- docker:24-dind
script:
- docker build -t myapp:latest .
- docker push myapp:latest
only:
- main
3. パイプライン設計(せっけい)原則(げんそく)
3.1 高速(こうそく)フィードバックループ
開発者(かいはつしゃ)がPRを出(だ)してから結果(けっか)を待(ま)つ時間(じかん)は、生産性(せいさんせい)に直接(ちょくせつ)影響(えいきょう)します。
目標時間:
├── リント + フォーマットチェック: 30秒以内
├── ユニットテスト: 2分以内
├── 統合テスト: 5分以内
├── ビルド: 3分以内
└── 全パイプライン: 10分以内
現実 (最適化前): 30分以上
現実 (最適化後): 8〜10分
3.2 並列処理(へいれつしょり)
# 並列パイプライン例
jobs:
# フェーズ1: リント/セキュリティは独立して並列実行
lint:
runs-on: ubuntu-latest
# ...
security-scan:
runs-on: ubuntu-latest
# ...
# フェーズ2: テストはシャードで並列分割
test:
needs: [lint]
strategy:
matrix:
shard: [1, 2, 3, 4]
# ...
# フェーズ3: テスト通過後にビルド
build:
needs: [test, security-scan]
# ...
3.3 キャッシュ戦略(せんりゃく)
# npmキャッシュ(GitHub Actions)
- uses: actions/cache@v4
with:
path: ~/.npm
key: npm-${{ '{{' }} hashFiles('**/package-lock.json') {{ '}}' }}
restore-keys: |
npm-
# Dockerレイヤーキャッシュ
- uses: docker/build-push-action@v5
with:
cache-from: type=gha
cache-to: type=gha,mode=max
# Gradleキャッシュ
- uses: actions/cache@v4
with:
path: |
~/.gradle/caches
~/.gradle/wrapper
key: gradle-${{ '{{' }} hashFiles('**/*.gradle*') {{ '}}' }}
3.4 冪等性(べきとうせい)(Idempotency)
パイプラインは同(おな)じ入力(にゅうりょく)に対(たい)して常(つね)に同(おな)じ結果(けっか)を出(だ)す必要(ひつよう)があります。
# 悪い例: タイムスタンプベースのタグ(再実行時に異なる結果)
# IMAGE_TAG: my-app:build-20250323-142000
# 良い例: コミットSHAベースのタグ(常に同一)
# IMAGE_TAG: my-app:abc1234
# 良い例: セマンティックバージョン(決定的)
# IMAGE_TAG: my-app:v1.2.3
4. CIでのテスト戦略(せんりゃく)
4.1 テストピラミッド
/ E2E \ 遅いが高い信頼性
/ (5〜10%) \
/ Integration \ 中速度、中信頼性
/ (15〜25%) \
/ Unit Tests \ 高速で大量
/ (65〜80%) \
/______________________\
4.2 テスト分割(ぶんかつ)(Test Splitting)
# Jestテストシャーディング
test:
strategy:
matrix:
shard: [1, 2, 3, 4]
steps:
- run: npx jest --shard=${{ '{{' }} matrix.shard {{ '}}' }}/4
# Cypress並列実行
e2e:
strategy:
matrix:
container: [1, 2, 3]
steps:
- uses: cypress-io/github-action@v6
with:
record: true
parallel: true
group: 'e2e-tests'
4.3 フレイキーテスト管理(かんり)
フレイキー(Flaky)テストは、同(おな)じコードで時(とき)に成功(せいこう)し時(とき)に失敗(しっぱい)するテストです。
// フレイキーテスト検出・隔離戦略
// jest.config.js
module.exports = {
// 失敗時に自動リトライ
retryTimes: 2,
// フレイキーテストレポーター
reporters: [
'default',
['jest-flaky-reporter', {
outputFile: 'flaky-tests.json',
threshold: 3 // 3回以上フレイキーなら報告
}]
]
};
# CIでフレイキーテストを隔離
test-stable:
runs-on: ubuntu-latest
steps:
- run: npx jest --testPathIgnorePatterns="flaky"
test-flaky:
runs-on: ubuntu-latest
continue-on-error: true # 失敗してもパイプライン継続
steps:
- run: npx jest --testPathPattern="flaky" --retries=3
4.4 テストカバレッジゲート
# カバレッジ閾値設定
test:
steps:
- run: npx jest --coverage
- name: Check coverage threshold
run: |
COVERAGE=$(cat coverage/coverage-summary.json | jq '.total.statements.pct')
if (( $(echo "$COVERAGE < 80" | bc -l) )); then
echo "Coverage $COVERAGE% is below 80% threshold"
exit 1
fi
5. Dockerビルド最適化(さいてきか)
5.1 マルチステージビルド
# Stage 1: 依存関係インストール
FROM node:20-alpine AS deps
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci --production
# Stage 2: ビルド
FROM node:20-alpine AS builder
WORKDIR /app
COPY /app/node_modules ./node_modules
COPY . .
RUN npm run build
# Stage 3: プロダクションイメージ
FROM node:20-alpine AS runner
WORKDIR /app
ENV NODE_ENV=production
# セキュリティ: non-rootユーザー
RUN addgroup --system --gid 1001 nodejs && \
adduser --system --uid 1001 nextjs
COPY /app/.next ./.next
COPY /app/node_modules ./node_modules
COPY /app/package.json ./
USER nextjs
EXPOSE 3000
CMD ["npm", "start"]
5.2 レイヤーキャッシュ最適化(さいてきか)
# 悪い例: ソース変更時にnpm ci再実行
COPY . .
RUN npm ci
RUN npm run build
# 良い例: 依存関係ファイルのみ先にコピー
COPY package.json package-lock.json ./
RUN npm ci
COPY . .
RUN npm run build
5.3 BuildKitとBuildx
# GitHub ActionsでBuildKit使用
- uses: docker/setup-buildx-action@v3
- uses: docker/build-push-action@v5
with:
context: .
push: true
tags: myapp:latest
cache-from: type=gha
cache-to: type=gha,mode=max
platforms: linux/amd64,linux/arm64
5.4 Kaniko(Dockerデーモン不要(ふよう)のビルド)
# KubernetesでKanikoによるイメージビルド
apiVersion: v1
kind: Pod
metadata:
name: kaniko-build
spec:
containers:
- name: kaniko
image: gcr.io/kaniko-project/executor:latest
args:
- "--dockerfile=Dockerfile"
- "--context=git://github.com/myorg/myapp"
- "--destination=registry.example.com/myapp:latest"
- "--cache=true"
- "--cache-repo=registry.example.com/myapp/cache"
5.5 イメージサイズ最適化(さいてきか)
イメージサイズ比較:
├── node:20 → 1.1GB
├── node:20-slim → 220MB
├── node:20-alpine → 140MB
├── distroless/nodejs → 120MB
└── マルチステージ最適化 → 80〜100MB
6. GitOpsとArgoCD
6.1 GitOps原則(げんそく)
GitOpsはGitリポジトリを単一(たんいつ)真実(しんじつ)の情報源(じょうほうげん)(Single Source of Truth)として使用(しよう)する運用(うんよう)モデルです。
GitOpsワークフロー:
1. 開発者がGitに変更をPush
2. CIがイメージをビルド・テスト
3. CIがデプロイマニフェストのイメージタグを更新
4. ArgoCDがGitとクラスター状態を比較
5. 差異があれば自動同期(または手動承認)
6. クラスターがGit状態と一致
┌────────┐ Push ┌────────┐ Detect ┌────────┐
│ Dev │ ──────────> │ Git │ <────────> │ ArgoCD │
└────────┘ └────────┘ └───┬────┘
│ Sync
┌────▼────┐
│ K8s │
│ Cluster │
└─────────┘
6.2 ArgoCD App of Appsパターン
# apps/root-app.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: root-app
namespace: argocd
spec:
project: default
source:
repoURL: https://github.com/myorg/gitops-config
targetRevision: main
path: apps
destination:
server: https://kubernetes.default.svc
namespace: argocd
syncPolicy:
automated:
prune: true
selfHeal: true
# apps/api-service.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: api-service
spec:
project: default
source:
repoURL: https://github.com/myorg/gitops-config
path: services/api
targetRevision: main
destination:
server: https://kubernetes.default.svc
namespace: production
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true
6.3 Argo Rollouts(段階的(だんかいてき)デリバリー)
apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
name: api-service
spec:
replicas: 10
strategy:
canary:
canaryService: api-canary
stableService: api-stable
trafficRouting:
istio:
virtualService:
name: api-vsvc
steps:
- setWeight: 10
- pause:
duration: 5m
- analysis:
templates:
- templateName: success-rate
- setWeight: 30
- pause:
duration: 5m
- analysis:
templates:
- templateName: success-rate
- setWeight: 60
- pause:
duration: 5m
- setWeight: 100
# AnalysisTemplate
apiVersion: argoproj.io/v1alpha1
kind: AnalysisTemplate
metadata:
name: success-rate
spec:
metrics:
- name: success-rate
interval: 60s
successCondition: result[0] >= 0.95
provider:
prometheus:
address: http://prometheus:9090
query: |
sum(rate(http_requests_total{status=~"2.*",app="api-service",version="canary"}[5m]))
/
sum(rate(http_requests_total{app="api-service",version="canary"}[5m]))
7. CI/CDセキュリティ
7.1 セキュリティスキャン統合(とうごう)
CI/CDセキュリティレイヤー:
┌─────────────────────────────────────────────┐
│ Layer 1: Pre-commit │
│ - Secret scanning (gitleaks, detect-secrets)│
│ - Lint (security rules) │
├─────────────────────────────────────────────┤
│ Layer 2: PR / Build │
│ - SAST (Semgrep, CodeQL, SonarQube) │
│ - SCA (Dependabot, Snyk, Trivy) │
│ - License compliance │
├─────────────────────────────────────────────┤
│ Layer 3: Container Build │
│ - Image scanning (Trivy, Grype) │
│ - Base image policy (distroless, alpine) │
│ - SBOM generation (Syft) │
├─────────────────────────────────────────────┤
│ Layer 4: Deploy │
│ - Policy enforcement (OPA/Kyverno) │
│ - Signing (cosign, Sigstore) │
│ - Runtime security (Falco) │
└─────────────────────────────────────────────┘
7.2 シークレット管理(かんり)
# GitHub Actionsでシークレット使用
deploy:
steps:
- name: Deploy
env:
AWS_ACCESS_KEY_ID: ${{ '{{' }} secrets.AWS_ACCESS_KEY_ID {{ '}}' }}
AWS_SECRET_ACCESS_KEY: ${{ '{{' }} secrets.AWS_SECRET_ACCESS_KEY {{ '}}' }}
run: |
aws ecs update-service --cluster prod --service api
# OIDC認証(シークレットレス方式 - 推奨)
permissions:
id-token: write
contents: read
steps:
- uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::123456789012:role/github-actions
aws-region: ap-northeast-2
7.3 SBOMとサプライチェーンセキュリティ
# SyftでSBOM生成
- name: Generate SBOM
uses: anchore/sbom-action@v0
with:
image: myapp:latest
format: spdx-json
output-file: sbom.spdx.json
# cosignでイメージ署名
- name: Sign image
run: |
cosign sign --key env://COSIGN_PRIVATE_KEY myapp:latest
# cosignで署名検証
- name: Verify signature
run: |
cosign verify --key cosign.pub myapp:latest
7.4 シークレットスキャン自動化(じどうか)
# .pre-commit-config.yaml
repos:
- repo: https://github.com/gitleaks/gitleaks
rev: v8.18.0
hooks:
- id: gitleaks
# CIでgitleaks実行
security:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: gitleaks/gitleaks-action@v2
env:
GITHUB_TOKEN: ${{ '{{' }} secrets.GITHUB_TOKEN {{ '}}' }}
8. デプロイ戦略(せんりゃく)比較(ひかく)
8.1 戦略比較表(ひかくひょう)
| 戦略(せんりゃく) | ダウンタイム | リスク | リソースコスト | ロールバック速度(そくど) | 複雑度(ふくざつど) |
|---|---|---|---|---|---|
| Recreate | あり | 高(たか)い | 1x | 遅(おそ)い | 低(ひく)い |
| Rolling Update | なし | 中(ちゅう) | 1x〜1.25x | 中 | 低い |
| Blue-Green | なし | 低い | 2x | 即時(そくじ) | 中 |
| Canary | なし | 非常(ひじょう)に低い | 1.1x | 即時 | 高い |
| A/B Testing | なし | 非常に低い | 1.1x | 即時 | 非常に高い |
8.2 Blue-Greenデプロイ
# Kubernetes Blue-Greenデプロイ
apiVersion: v1
kind: Service
metadata:
name: api-service
spec:
selector:
app: api
version: green # blueからgreenに切替
ports:
- port: 80
targetPort: 8080
Blue-Green切替プロセス:
1. Blue(v1)運用中 → Green(v2)デプロイ
2. Greenヘルスチェック・スモークテスト
3. Service selectorをGreenに切替
4. 問題時はBlueに即時ロールバック
5. 安定化後にBlueリソースを整理
[Users] → [LB] → [Blue v1] Active
[Green v2] ← 準備中
[Users] → [LB] → [Blue v1] ← 待機
[Green v2] Active
8.3 カナリアデプロイ
# Istio VirtualServiceでカナリアデプロイ
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: api-service
spec:
hosts:
- api-service
http:
- route:
- destination:
host: api-service
subset: stable
weight: 90
- destination:
host: api-service
subset: canary
weight: 10
8.4 Feature Flags
// LaunchDarklyまたは自社Feature Flagシステム
import { featureFlags } from './feature-flags';
async function handleRequest(req: Request) {
const userId = req.user.id;
if (await featureFlags.isEnabled('new-checkout-flow', userId)) {
return newCheckoutFlow(req);
}
return legacyCheckoutFlow(req);
}
Feature Flagベースのデプロイ:
1. 新機能をフラグで囲んでコードをデプロイ
2. 内部ユーザーのみ有効化
3. 段階的に割合を拡大(1% → 5% → 25% → 100%)
4. 問題時はフラグを無効にするだけで即時非活性化
5. デプロイとリリースを分離
9. ロールバック戦略(せんりゃく)
9.1 自動(じどう)ロールバック
# Argo Rollouts自動ロールバック
spec:
strategy:
canary:
steps:
- setWeight: 10
- analysis:
templates:
- templateName: error-rate-check
# 分析失敗時に自動ロールバック
abortScaleDownDelaySeconds: 30
# Kubernetes Deployment自動ロールバック
apiVersion: apps/v1
kind: Deployment
spec:
progressDeadlineSeconds: 300 # 5分以内に完了しなければ失敗
minReadySeconds: 30
strategy:
rollingUpdate:
maxSurge: 25%
maxUnavailable: 0
9.2 サーキットブレイカーパターン
// デプロイサーキットブレイカー
class DeploymentCircuitBreaker {
private errorThreshold = 0.05; // 5%エラー率
private windowSize = 300; // 5分ウィンドウ
async shouldRollback(metrics: DeploymentMetrics): Promise<boolean> {
const errorRate = metrics.errors / metrics.totalRequests;
const p99Latency = metrics.p99LatencyMs;
return (
errorRate > this.errorThreshold ||
p99Latency > 3000 // 3秒超過
);
}
async executeRollback(deployment: string) {
console.log(`Rolling back ${deployment}`);
await exec(`kubectl rollout undo deployment/${deployment}`);
await notify({
channel: '#deployments',
message: `Auto-rollback triggered for ${deployment}`,
severity: 'critical'
});
}
}
9.3 データベースマイグレーションロールバック
安全なDBマイグレーション戦略:
1. Expand-Contractパターン
Phase 1 (Expand): 新カラム追加、両方に書き込み
Phase 2 (Migrate): 既存データの移行
Phase 3 (Contract): 旧カラム削除
2. ロールバック可能なマイグレーションのみ適用
- カラム追加(ロールバック可能)
- インデックス追加(ロールバック可能)
- カラム削除(ロールバック不可 → Expand-Contract使用)
- 型変更(ロールバック不可 → 新カラム追加後に切替)
-- 安全なマイグレーション例
-- Step 1: 新カラム追加(ロールバック可能)
ALTER TABLE users ADD COLUMN email_verified BOOLEAN DEFAULT FALSE;
-- Step 2: データマイグレーション(バックグラウンド)
UPDATE users SET email_verified = TRUE
WHERE verified_at IS NOT NULL;
-- Step 3: アプリコードで新カラム使用に切替
-- Step 4: 旧カラム削除(別マイグレーション)
-- ALTER TABLE users DROP COLUMN verified_at;
10. パイプラインヘルスモニタリング
10.1 コア指標(しひょう)
パイプラインヘルスダッシュボード:
┌─────────────────────────────────────────┐
│ Build Time Trend │
│ ██████████████ 8m (avg) │
│ Target: < 10m │
├─────────────────────────────────────────┤
│ Success Rate │
│ ████████████████████ 94% │
│ Target: > 95% │
├─────────────────────────────────────────┤
│ Flaky Test Rate │
│ ██ 3% │
│ Target: < 2% │
├─────────────────────────────────────────┤
│ Mean Time to Recovery (MTTR) │
│ ████ 25min │
│ Target: < 30min │
└─────────────────────────────────────────┘
10.2 ビルド時間(じかん)追跡(ついせき)
# ビルドメトリクスをDatadogに報告
- name: Report build metrics
if: always()
run: |
END_TIME=$(date +%s)
DURATION=$((END_TIME - START_TIME))
curl -X POST "https://api.datadoghq.com/api/v1/series" \
-H "DD-API-KEY: $DD_API_KEY" \
-d "{
\"series\": [{
\"metric\": \"ci.build.duration\",
\"points\": [[$END_TIME, $DURATION]],
\"tags\": [
\"repo:myapp\",
\"branch:$GITHUB_REF_NAME\",
\"status:$JOB_STATUS\"
]
}]
}"
10.3 失敗(しっぱい)分析(ぶんせき)自動化(じどうか)
# ビルド失敗自動分類スクリプト
import re
from enum import Enum
class FailureCategory(Enum):
FLAKY_TEST = "flaky_test"
DEPENDENCY = "dependency"
COMPILATION = "compilation"
INFRASTRUCTURE = "infrastructure"
TIMEOUT = "timeout"
UNKNOWN = "unknown"
def categorize_failure(log: str) -> FailureCategory:
patterns = {
FailureCategory.FLAKY_TEST: [
r"retry.*failed",
r"intermittent",
r"flaky"
],
FailureCategory.DEPENDENCY: [
r"npm ERR!.*404",
r"Could not resolve dependencies",
r"ECONNRESET"
],
FailureCategory.COMPILATION: [
r"error TS\d+",
r"SyntaxError",
r"TypeError"
],
FailureCategory.INFRASTRUCTURE: [
r"runner.*offline",
r"disk space",
r"out of memory"
],
FailureCategory.TIMEOUT: [
r"timed out",
r"deadline exceeded"
]
}
for category, regexes in patterns.items():
for pattern in regexes:
if re.search(pattern, log, re.IGNORECASE):
return category
return FailureCategory.UNKNOWN
11. 面接(めんせつ)質問集(しつもんしゅう)
基本概念(きほんがいねん)
Q1. CIとCDの違(ちが)いを説明(せつめい)してください。
**CI(Continuous Integration)**は、開発者(かいはつしゃ)がコード変更(へんこう)を頻繁(ひんぱん)にメインブランチに統合(とうごう)するプラクティスです。各統合(かくとうごう)は自動化(じどうか)されたビルドとテストで検証(けんしょう)されます。
CDには2つの意味(いみ)があります:
- Continuous Delivery: コードが常(つね)にデプロイ可能(かのう)な状態(じょうたい)を維持(いじ)。プロダクションデプロイは手動(しゅどう)承認(しょうにん)。
- Continuous Deployment: すべての変更が自動的(じどうてき)にプロダクションにデプロイ。手動介入(かいにゅう)なし。
核心的(かくしんてき)な違い: CIは「統合」に、CDは「配信(はいしん)/デプロイ」に焦点(しょうてん)。CI無(な)しにCDは不可能(ふかのう)ですが、CIだけでCDをしないことは可能です。
Q2. DORAメトリクス4つを説明(せつめい)してください。
- デプロイ頻度(ひんど)(Deployment Frequency): プロダクションにどれくらい頻繁(ひんぱん)にデプロイするか
- リードタイム(Lead Time for Changes): コミットからプロダクションデプロイまでの時間(じかん)
- 変更失敗率(へんこうしっぱいりつ)(Change Failure Rate): デプロイ中(ちゅう)に失敗(しっぱい)またはロールバックが必要(ひつよう)な割合(わりあい)
- 復旧時間(ふっきゅうじかん)(MTTR): 障害発生(しょうがいはっせい)から復旧(ふっきゅう)までの時間
Eliteチーム: 1日複数回(ふくすうかい)デプロイ、1時間未満(みまん)のリードタイム、5%未満の失敗率、1時間未満の復旧
Q3. GitOpsのコア原則(げんそく)を説明(せつめい)してください。
- 宣言的(せんげんてき)(Declarative): システム状態(じょうたい)を宣言的に定義(ていぎ)
- バージョン管理(かんり)(Versioned): Gitを単一(たんいつ)真実(しんじつ)の情報源(じょうほうげん)として使用
- 自動適用(じどうてきよう)(Automated): 承認(しょうにん)された変更(へんこう)が自動的にシステムに適用(てきよう)
- 自己修復(じこしゅうふく)(Self-Healing): 実際(じっさい)の状態が宣言された状態と異(こと)なれば自動復旧(ふっきゅう)
メリット: 監査(かんさ)証跡(しょうせき)、容易(ようい)なロールバック、PRベースの変更管理、再現可能(さいげんかのう)な環境(かんきょう)
Q4. Blue-GreenデプロイとカナリアデプロイのUI(ちが)いを説明してください。
Blue-Green: 2つの同一(どういつ)環境(かんきょう)(Blue/Green)を運用(うんよう)。新(あたら)しいバージョンをGreenにデプロイ後(ご)、トラフィックを一度(いちど)に切替(きりか)え。ロールバックはBlueに即時(そくじ)切替。
- メリット: 即時ロールバック、シンプルな実装(じっそう)
- デメリット: リソース2倍必要(ひつよう)、データベース同期(どうき)が複雑(ふくざつ)
Canary: 新バージョンを少数(しょうすう)(1〜10%)に先(さき)にデプロイ。メトリクス分析(ぶんせき)後(ご)、段階的(だんかいてき)に拡大(かくだい)。
- メリット: リスク最小化(さいしょうか)、実際のトラフィックで検証
- デメリット: 実装が複雑、モニタリング必須(ひっす)
Q5. シフトレフト(Shift Left)とは何(なん)ですか?
テストとセキュリティを開発(かいはつ)ライフサイクルの左側(ひだりがわ)(初期段階(しょきだんかい))に移動(いどう)させる戦略(せんりゃく)です。
適用例(てきようれい):
- pre-commit hookでコードリント、フォーマット、シークレットスキャン
- PR段階(だんかい)でSAST、SCA、ユニットテスト実行(じっこう)
- ビルド時(じ)にコンテナイメージスキャン
- IDEプラグインで開発中(かいはつちゅう)にリアルタイムフィードバック
効果(こうか): 欠陥(けっかん)を早(はや)く発見(はっけん)するほど修正(しゅうせい)コストが指数的(しすうてき)に減少(げんしょう)(プロダクション比(ひ)10〜100倍(ばい)の節約(せつやく))
深掘(ふかぼ)り質問(しつもん)
Q6. フレイキーテスト(Flaky Test)をどう管理(かんり)しますか?
- 検出(けんしゅつ): 同(おな)じコードで繰(く)り返(かえ)し実行(じっこう)時(じ)に結果(けっか)が変(か)わるテストを特定(とくてい)
- 隔離(かくり): フレイキーテストを別(べつ)のtest suiteに分離(ぶんり)、continue-on-error適用(てきよう)
- リトライ: jestのretryTimes、pytest-rerunfailuresなどで自動(じどう)リトライ
- 追跡(ついせき): フレイキーテストダッシュボードで頻度(ひんど)・パターン分析(ぶんせき)
- 根本原因(こんぽんげんいん)解決(かいけつ): タイミング問題(もんだい)、共有状態(きょうゆうじょうたい)、外部依存性(がいぶいぞんせい)など原因(げんいん)除去(じょきょ)
- ポリシー: 一定期間内(いっていきかんない)に修正(しゅうせい)されなければ無効化(むこうか)または削除(さくじょ)
Q7. Dockerイメージビルドをどう最適化(さいてきか)しますか?
- マルチステージビルド: ビルドツールを最終(さいしゅう)イメージから除外(じょがい)
- レイヤーキャッシュ最適化(さいてきか): 頻繁(ひんぱん)に変更(へんこう)されるファイルを後(あと)にCOPY
- 軽量(けいりょう)ベースイメージ: alpine、distroless使用
- .dockerignore: 不要(ふよう)なファイルを除外
- BuildKit使用(しよう): 並列(へいれつ)ビルド、キャッシュマウント
- 依存関係(いぞんかんけい)分離(ぶんり): package.jsonを先(さき)にコピーしてnpm ciキャッシュ
- Kaniko: Dockerデーモン無(な)しでビルド(CI/CDセキュリティ向上(こうじょう))
Q8. シークレット管理(かんり)のベストプラクティスを説明(せつめい)してください。
- 絶対(ぜったい)にGitにコミットしない: gitleaks、detect-secretsでpre-commit検査(けんさ)
- OIDC認証(にんしょう): 長期(ちょうき)シークレットの代(か)わりに一時(いちじ)トークンを使用
- シークレットマネージャー活用(かつよう): AWS Secrets Manager、HashiCorp Vault、Doppler
- 最小権限(さいしょうけんげん)原則(げんそく): 必要(ひつよう)最小限(さいしょうげん)の権限(けんげん)のみ付与(ふよ)
- シークレットローテーション: 定期的(ていきてき)にシークレット更新(こうしん)を自動化(じどうか)
- 監査(かんさ)ログ: シークレットアクセス記録(きろく)を追跡(ついせき)
- 環境(かんきょう)分離(ぶんり): dev/staging/prodシークレットを分離
Q9. データベースマイグレーションを安全(あんぜん)にロールバックする方法(ほうほう)は?
Expand-Contractパターンを使用(しよう):
Phase 1 (Expand):
- 新(あたら)しいカラム/テーブルを追加(ついか)
- アプリが旧(きゅう)スキーマと新(しん)スキーマの両方(りょうほう)に互換(ごかん)するようコード修正(しゅうせい)
- 新スキーマへのデータ書(か)き込(こ)みを開始(かいし)
Phase 2 (Migrate):
- 既存(きそん)データを新スキーマに移行(いこう)(バックグラウンド)
- アプリを新スキーマのみ使用(しよう)するように切替(きりか)え
Phase 3 (Contract):
- 旧カラム/テーブルを削除(さくじょ)(別(べつ)デプロイ)
- この段階(だんかい)のみロールバック不可(ふか)
核心(かくしん): 各(かく)段階(だんかい)が独立(どくりつ)してロールバック可能(かのう)であること。
Q10. CI/CDパイプラインのセキュリティをどう強化(きょうか)しますか?
- サプライチェーンセキュリティ: SBOM生成(せいせい)、イメージ署名(しょめい)(cosign)、SLSA準拠(じゅんきょ)
- シークレット管理(かんり): OIDC、Vault、環境変数(かんきょうへんすう)の最小化(さいしょうか)
- SAST/DAST/SCA: Semgrep、Trivy、Dependabot統合(とうごう)
- コンテナセキュリティ: 非(ひ)rootユーザー、distrolessベース、イメージスキャン
- ポリシー遵守(じゅんしゅ): OPA/Kyvernoでデプロイポリシーを強制(きょうせい)
- アクセス制御(せいぎょ): 最小権限(さいしょうけんげん)、ブランチ保護(ほご)ルール
- 監査(かんさ): すべてのデプロイ記録(きろく)を追跡(ついせき)、変更履歴(へんこうりれき)を維持(いじ)
Q11. GitHub ActionsとJenkinsの長所(ちょうしょ)・短所(たんしょ)を比較(ひかく)してください。
GitHub Actions:
- 長所: GitHubネイティブ統合(とうごう)、SaaSでメンテナンス不要(ふよう)、Marketplaceエコシステム、簡単(かんたん)なYAML設定(せってい)
- 短所: GitHub依存性(いぞんせい)、カスタマイズの限界(げんかい)、複雑(ふくざつ)なワークフロー管理(かんり)が困難(こんなん)
Jenkins:
- 長所: 完全(かんぜん)な自由度(じゆうど)、1800+プラグイン、セルフホスト制御(せいぎょ)、Groovyスクリプティング
- 短所: 高(たか)いメンテナンスコスト、複雑な設定、セキュリティパッチ管理、スケーリングの困難さ
選択基準(せんたくきじゅん): 小規模(しょうきぼ)/GitHub中心(ちゅうしん)プロジェクトはActions、複雑なエンタープライズ/マルチSCMはJenkins
Q12. Argo RolloutsのProgressive Deliveryを説明(せつめい)してください。
Progressive Deliveryは、新(あたら)しいバージョンを段階的(だんかいてき)にデプロイしながら、自動化(じどうか)された分析(ぶんせき)で安全性(あんぜんせい)を検証(けんしょう)する方式(ほうしき)です。
Argo Rolloutsワークフロー:
- カナリアに10%トラフィックを割(わ)り当(あ)て
- AnalysisTemplateで成功率(せいこうりつ)、レイテンシーを検証(5分(ふん))
- 通過(つうか)時(じ)に30%に拡大(かくだい)、再(ふたた)び分析
- 60%、100%へ段階的(だんかいてき)に拡大
- 分析失敗時(しっぱいじ)に自動(じどう)ロールバック
主要(しゅよう)コンポーネント:
- Rollout: デプロイ戦略(せんりゃく)を定義(ていぎ)
- AnalysisTemplate: 検証条件(けんしょうじょうけん)を定義(Prometheus、Datadogなど)
- TrafficRouting: Istio、Nginx、ALBなどと連携(れんけい)
Q13. パイプラインパフォーマンスをどう最適化(さいてきか)しますか?
- 並列処理(へいれつしょり): 独立(どくりつ)した作業(さぎょう)を同時(どうじ)実行(じっこう)
- テスト分割(ぶんかつ): シャーディングでテストを複数(ふくすう)のランナーに分配(ぶんぱい)
- キャッシュ: 依存関係(いぞんかんけい)、Dockerレイヤー、ビルド結果(けっか)のキャッシュ
- 選択的(せんたくてき)実行(じっこう): 変更(へんこう)されたファイルに応(おう)じて必要(ひつよう)な作業(さぎょう)のみ実行
- 増分(ぞうぶん)ビルド: 全体(ぜんたい)ビルドの代(か)わりに変更部分(ぶぶん)のみビルド
- リソース最適化: ランナーサイズ、同時実行数(どうじじっこうすう)の調整(ちょうせい)
- フィードバックループ短縮(たんしゅく): 速(はや)いチェックを先(さき)に、遅(おそ)いチェックは後(あと)に
Q14. Feature Flagベースのデプロイの長所(ちょうしょ)・短所(たんしょ)は?
長所:
- デプロイとリリースの分離(ぶんり): コードをデプロイしつつ、機能(きのう)は後(あと)から有効化(ゆうこうか)
- 高速(こうそく)ロールバック: コードロールバック無(な)しでフラグを無効(むこう)にするだけ
- 段階的(だんかいてき)リリース: ユーザー比率(ひりつ)を段階的(だんかいてき)に拡大(かくだい)
- A/Bテスト: 機能(きのう)ごとの実験(じっけん)が可能(かのう)
短所:
- 技術的負債(ぎじゅつてきふさい): 古(ふる)いフラグの整理(せいり)が必要(ひつよう)
- 複雑性(ふくざつせい): フラグの組(く)み合(あ)わせでテストケースが増加(ぞうか)
- コード可読性(かどくせい): 条件分岐(じょうけんぶんき)の増加(ぞうか)でコードが複雑化(ふくざつか)
- 一貫性(いっかんせい): ユーザーごとに異(こと)なる体験(たいけん)でバグ再現(さいげん)が困難(こんなん)
Q15. モノレポでのCI/CD戦略(せんりゃく)を説明(せつめい)してください。
- 影響範囲(えいきょうはんい)分析(ぶんせき): 変更(へんこう)されたファイルから影響(えいきょう)を受(う)けるパッケージのみビルド/テスト
- ツール活用(かつよう): Turborepo、Nx、Bazelなどで依存関係(いぞんかんけい)グラフベースのビルド
- キャッシュ: リモートキャッシュ(Turborepo Remote Cache)でビルド結果(けっか)を共有(きょうゆう)
- 選択的(せんたくてき)デプロイ: 変更されたサービスのみデプロイ
- 並列処理(へいれつしょり): 独立(どくりつ)したパッケージを同時(どうじ)にビルド/テスト
# Turborepo例
turbo run build --filter=...[HEAD~1]
# HEAD以降に変更されたパッケージとその依存パッケージのみビルド
12. クイズ
Q1. DORAメトリクスでEliteチームのデプロイ頻度(ひんど)は?
正解(せいかい): 1日(にち)に複数回(ふくすうかい)(On-demand, multiple deploys per day)
Eliteチームは1日に複数回デプロイしながらも、変更失敗率(へんこうしっぱいりつ)5%未満(みまん)、復旧時間(ふっきゅうじかん)1時間未満を維持(いじ)しています。
Q2. Expand-Contractパターンでロールバック不可能(ふかのう)な段階(だんかい)は?
正解: Contract段階(旧(きゅう)カラム/テーブルの削除(さくじょ))
Expand(追加(ついか))とMigrate(マイグレーション)はロールバック可能(かのう)ですが、Contract(削除)はデータが消(き)えるためロールバックが不可能です。そのため、Contractは十分(じゅうぶん)な安定化(あんていか)期間(きかん)の後(あと)に別途(べっと)実施(じっし)します。
Q3. GitOpsにおける「単一(たんいつ)真実(しんじつ)の情報源(じょうほうげん)」とは?
正解: Gitリポジトリ
GitOpsにおいて、Gitリポジトリはシステムの望(のぞ)ましい状態(じょうたい)(Desired State)を定義(ていぎ)する唯一(ゆいいつ)のソースです。クラスターの実際(じっさい)の状態は常(つね)にGitで宣言(せんげん)された状態と一致(いっち)する必要(ひつよう)があり、ArgoCDのようなツールがこれを自動的(じどうてき)に検出(けんしゅつ)・同期(どうき)します。
Q4. カナリアデプロイで自動(じどう)ロールバックをトリガーする基準(きじゅん)は?
正解: AnalysisTemplateに定義(ていぎ)されたメトリクス基準(成功率(せいこうりつ)、レイテンシーなど)
Argo RolloutsのAnalysisTemplateでPrometheus、Datadogなどのメトリクスをクエリし、成功率が基準(きじゅん)(例: 95%)以下(いか)、またはP99レイテンシーが基準を超過(ちょうか)した場合(ばあい)、自動的(じどうてき)にロールバックをトリガーします。
Q5. SBOM(Software Bill of Materials)の目的(もくてき)は?
正解: ソフトウェアに含(ふく)まれるすべての構成要素(こうせいようそ)(ライブラリ、依存関係(いぞんかんけい))のリストを提供(ていきょう)し、サプライチェーンセキュリティを強化(きょうか)すること
SBOMはソフトウェアの「材料(ざいりょう)リスト」であり、脆弱性(ぜいじゃくせい)発見時(はっけんじ)に影響範囲(えいきょうはんい)を迅速(じんそく)に把握(はあく)し、ライセンスコンプライアンスを確認(かくにん)し、サプライチェーン攻撃(こうげき)(例: Log4Shell)への対応(たいおう)を支援(しえん)します。Syft、Trivyなどのツールで自動生成(じどうせいせい)できます。