DevOps CI/CDパイプライン実践:Docker + Kubernetesフルチェーン

DevOps

CI/CDの基礎と2026年の技術状況

CI/CD(継続的インテグレーション/継続的デプロイ)はDevOpsの中核プラクティスであり、コードのコミットから本番環境までの全プロセスを自動化・トレーサブル・ロールバック可能にすることが目標です。

コア概念

概念 フルネーム コア目標
CI Continuous Integration 頻繁にコードをマージ、自動ビルド+テスト、早期に問題を発見
CD(デリバリー) Continuous Delivery コードはいつでもデプロイ可能、手動承認が必要
CD(デプロイ) Continuous Deployment テスト通過後自動的に本番へデプロイ、手動ゲートなし

2026年主要CI/CDプラットフォーム比較

プラットフォーム ユースケース コア強み Pipeline定義
GitHub Actions オープンソース、中小チーム ネイティブ統合、Marketplaceエコシステム、寛大な無料枠 .github/workflows/*.yml
GitLab CI エンタープライズ自己ホスト 組み込みコンテナレジストリ、セキュリティスキャン、K8s統合 .gitlab-ci.yml
Jenkins 複雑パイプライン、従来型エンタープライズ 最も豊富なプラグインエコシステム、高度にカスタマイズ可能 Jenkinsfile(Groovy)

💡 YAMLフォーマッターツールでCI/CD設定ファイルを編集・検証し、インデントエラーを回避できます。


Dockerベストプラクティス

DockerはCI/CDパイプラインの基盤であり、各ビルドは決定的で再現可能なコンテナイメージを生成すべきです。

マルチステージビルド(Multi-Stage Build)

マルチステージビルドはイメージサイズ削減の最優先手法であり、ビルド環境とランタイム環境を分離します:

# ステージ1:ビルド
FROM golang:1.23-alpine AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -ldflags="-s -w" -o /app/server ./cmd/server

# ステージ2:ランタイム
FROM gcr.io/distroless/static:nonroot
COPY --from=builder /app/server /server
USER nonroot:nonroot
ENTRYPOINT ["/server"]

効果:Goイメージが~300MBから~5MBに圧縮。

Node.jsマルチステージビルド例:

FROM node:22-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
RUN npm run build

FROM node:22-alpine AS runner
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
EXPOSE 3000
CMD ["node", "dist/main.js"]

イメージレイヤキャッシュ最適化

Dockerレイヤキャッシュのキー原則:変更頻度の低い命令を前に、変更頻度の高い命令を後に配置

# 良い例:依存ファイルを先にコピー、キャッシュを活用
COPY package*.json ./
RUN npm ci
COPY . .

# 悪い例:全ソースを先にコピー、毎回依存を再インストール
COPY . .
RUN npm ci

イメージサイズ最適化チェックリスト

手法 効果 ユースケース
マルチステージビルド 60-90%削減 全コンパイル型言語
Alpineベースイメージ 50-80%削減 glibcに依存しないアプリ
distrolessイメージ アプリバイナリのみ Go、Java等の静的コンパイル
.dockerignore ビルドコンテキスト削減 全プロジェクト
RUN命令の統合 イメージレイヤ削減 apt/apkインストール場面
バイナリストリップ -ldflags="-s -w" 20-30%削減 Goプロジェクト
# RUN命令を統合してレイヤを削減
RUN apk add --no-cache curl=8.11.0 && \
    apk add --no-cache git=2.45.0 && \
    rm -rf /var/cache/apk/*

.dockerignoreベストプラクティス

# .dockerignore
node_modules
npm-debug.log
.git
.github
.gitlab
.vscode
.idea
*.md
*.test.js
coverage/
dist/
.env
.env.local

💡 JSONフォーマッターツールでpackage.jsonの依存バージョン一貫性を確認できます。


Kubernetesデプロイ戦略

Kubernetesは複数のデプロイ戦略を提供し、選択はビジネスリスク許容度ロールバック速度要件に依存します。

ローリングアップデート(Rolling Update)

K8sのデフォルト戦略、古いPodを段階的に置き換え:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
spec:
  replicas: 6
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 2        # 同時に最大2つの余分なPod
      maxUnavailable: 1   # 最大1つのPodが利用不可
  selector:
    matchLabels:
      app: my-app
  template:
    metadata:
      labels:
        app: my-app
    spec:
      containers:
        - name: my-app
          image: registry.example.com/my-app:v2.0.0
          ports:
            - containerPort: 8080
          readinessProbe:
            httpGet:
              path: /healthz
              port: 8080
            initialDelaySeconds: 5
            periodSeconds: 10

ブルーグリーンデプロイ(Blue-Green Deployment)

2つの完全な環境を同時に実行し、Serviceのセレクタを切り替えてゼロダウンタイムを実現:

# blue-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app-blue
spec:
  replicas: 3
  selector:
    matchLabels:
      app: my-app
      version: blue
  template:
    metadata:
      labels:
        app: my-app
        version: blue
    spec:
      containers:
        - name: my-app
          image: registry.example.com/my-app:v1.0.0
---
# green-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app-green
spec:
  replicas: 3
  selector:
    matchLabels:
      app: my-app
      version: green
  template:
    metadata:
      labels:
        app: my-app
        version: green
    spec:
      containers:
        - name: my-app
          image: registry.example.com/my-app:v2.0.0
---
# service.yaml(セレクタを切り替えてブルーグリーン切替)
apiVersion: v1
kind: Service
metadata:
  name: my-app-svc
spec:
  selector:
    app: my-app
    version: blue    # greenに変更で新バージョンに切替
  ports:
    - port: 80
      targetPort: 8080

カナリアリリース(Canary Release)

段階的にトラフィックを新バージョンに移行し、小規模で検証後にフルロールアウト:

# canary-with-istio.yaml
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  name: my-app-vs
spec:
  hosts:
    - my-app.example.com
  http:
    - match:
        - headers:
            x-canary:
              exact: "true"
      route:
        - destination:
            host: my-app
            subset: canary
          weight: 100
    - route:
        - destination:
            host: my-app
            subset: stable
          weight: 90
        - destination:
            host: my-app
            subset: canary
          weight: 10

デプロイ戦略比較

戦略 ダウンタイム ロールバック速度 リソースコスト 複雑さ ユースケース
ローリングアップデート 通常リリース
ブルーグリーン ゼロ 高速(Service切替) 高(2倍) クリティカルサービス
カナリア ゼロ 高速 高リスク変更

GitOpsとArgoCD

GitOpsは2026年のKubernetesデプロイの事実上の標準であり、Gitリポジトリを単一の真実の情報源として使用し、全変更をGitコミットでトリガーします。

GitOpsコア原則

  1. 宣言的:全インフラとアプリ設定が宣言的
  2. バージョン管理:全設定をGitに保存、完全な変更履歴
  3. 自動プル:デプロイツールがGitから自動的に変更をプルして適用
  4. 継続的調和:クラスタ状態とGit宣言を継続的に比較、ドリフトを自動修復

ArgoCD設定例

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: my-app
  namespace: argocd
spec:
  project: default
  source:
    repoURL: https://git.example.com/platform/k8s-manifests.git
    targetRevision: main
    path: overlays/production
  destination:
    server: https://kubernetes.default.svc
    namespace: my-app
  syncPolicy:
    automated:
      prune: true
      selfHeal: true
      allowEmpty: false
    syncOptions:
      - CreateNamespace=true
      - PrunePropagationPolicy=foreground
    retry:
      limit: 5
      backoff:
        duration: 5s
        factor: 2
        maxDuration: 3m

Kustomizeマルチ環境管理

k8s-manifests/
├── base/
│   ├── deployment.yaml
│   ├── service.yaml
│   └── kustomization.yaml
└── overlays/
    ├── development/
    │   ├── kustomization.yaml
    │   └── patch-replicas.yaml
    ├── staging/
    │   ├── kustomization.yaml
    │   └── patch-replicas.yaml
    └── production/
        ├── kustomization.yaml
        └── patch-replicas.yaml
# overlays/production/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
bases:
  - ../../base
patchesStrategicMerge:
  - patch-replicas.yaml
  - patch-resources.yaml
configMapGenerator:
  - name: app-config
    literals:
      - ENV=production
      - LOG_LEVEL=warn
      - DB_HOST=prod-db.internal

Pipeline as Code:完全なGitHub Actions Workflow

これは本番級CI/CDパイプラインの完全な実装であり、ビルド、テスト、セキュリティスキャン、デプロイのフルチェーンをカバーします:

name: CI/CD Pipeline

on:
  push:
    branches: [main, develop]
  pull_request:
    branches: [main]

env:
  REGISTRY: ghcr.io
  IMAGE_NAME: ${{ github.repository }}
  K8S_NAMESPACE: my-app

jobs:
  # ジョブ1:リントとユニットテスト
  lint-and-test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-go@v5
        with:
          go-version: '1.23'
      - name: Lint
        run: golangci-lint run ./...
      - name: Unit Test
        run: go test -race -coverprofile=coverage.out ./...
      - name: Upload Coverage
        uses: codecov/codecov-action@v4
        with:
          file: coverage.out

  # ジョブ2:セキュリティスキャン
  security-scan:
    runs-on: ubuntu-latest
    needs: lint-and-test
    steps:
      - uses: actions/checkout@v4
      - name: Trivy FS Scan
        uses: aquasecurity/trivy-action@master
        with:
          scan-type: fs
          severity: CRITICAL,HIGH
          exit-code: '1'
      - name: Snyk SAST
        uses: snyk/actions/golang@master
        env:
          SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}

  # ジョブ3:Dockerイメージのビルドとプッシュ
  build-and-push:
    runs-on: ubuntu-latest
    needs: security-scan
    permissions:
      contents: read
      packages: write
    outputs:
      image_tag: ${{ steps.meta.outputs.tags }}
      image_digest: ${{ steps.build.outputs.digest }}
    steps:
      - uses: actions/checkout@v4
      - uses: docker/setup-buildx-action@v3
      - uses: docker/login-action@v3
        with:
          registry: ${{ env.REGISTRY }}
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}
      - name: Docker Metadata
        id: meta
        uses: docker/metadata-action@v5
        with:
          images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
          tags: |
            type=sha,prefix=
            type=ref,event=branch
            type=semver,pattern={{version}}
      - name: Build and Push
        id: build
        uses: docker/build-push-action@v6
        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: |
            BUILD_DATE=${{ github.event.head_commit.timestamp }}
            VCS_REF=${{ github.sha }}

  # ジョブ4:イメージセキュリティスキャン
  image-scan:
    runs-on: ubuntu-latest
    needs: build-and-push
    steps:
      - name: Trivy Image Scan
        uses: aquasecurity/trivy-action@master
        with:
          image-ref: ${{ needs.build-and-push.outputs.image_tag }}
          severity: CRITICAL,HIGH
          exit-code: '1'
          format: sarif
          output: trivy-results.sarif
      - name: Upload SARIF
        uses: github/codeql-action/upload-sarif@v3
        with:
          sarif_file: trivy-results.sarif

  # ジョブ5:K8sへデプロイ
  deploy:
    runs-on: ubuntu-latest
    needs: [build-and-push, image-scan]
    if: github.ref == 'refs/heads/main'
    environment: production
    steps:
      - uses: actions/checkout@v4
      - uses: azure/setup-kubectl@v3
      - uses: azure/setup-helm@v3
      - name: Configure kubectl
        run: |
          mkdir -p $HOME/.kube
          echo "${{ secrets.KUBE_CONFIG }}" | base64 -d > $HOME/.kube/config
      - name: Deploy with Helm
        run: |
          helm upgrade --install my-app ./helm/my-app \
            --namespace ${{ env.K8S_NAMESPACE }} \
            --set image.tag=${{ needs.build-and-push.outputs.image_tag }} \
            --set image.digest=${{ needs.build-and-push.outputs.image_digest }} \
            --values ./helm/my-app/values-production.yaml \
            --timeout 5m \
            --wait
      - name: Verify Deployment
        run: |
          kubectl rollout status deployment/my-app \
            --namespace ${{ env.K8S_NAMESPACE }} \
            --timeout=3m
      - name: Smoke Test
        run: |
          STATUS=$(curl -s -o /dev/null -w "%{http_code}" \
            https://my-app.example.com/healthz)
          if [ "$STATUS" != "200" ]; then
            echo "Smoke test failed: HTTP $STATUS"
            exit 1
          fi

GitLab CI完全設定

# .gitlab-ci.yml
stages:
  - test
  - security
  - build
  - deploy

variables:
  DOCKER_TLS_CERTDIR: "/certs"
  REGISTRY: $CI_REGISTRY
  IMAGE_TAG: $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA

test:
  stage: test
  image: golang:1.23-alpine
  script:
    - go test -race -coverprofile=coverage.out ./...
    - go tool cover -func=coverage.out
  artifacts:
    reports:
      coverage_report:
        coverage_format: cobertura
        path: coverage.xml

security-scan:
  stage: security
  image: aquasec/trivy:latest
  script:
    - trivy fs --severity CRITICAL,HIGH --exit-code 1 .
  allow_failure: false

build:
  stage: build
  image: docker:24
  services:
    - docker:24-dind
  before_script:
    - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
  script:
    - docker build
        --cache-from $CI_REGISTRY_IMAGE:latest
        --tag $IMAGE_TAG
        --tag $CI_REGISTRY_IMAGE:latest
        --build-arg VCS_REF=$CI_COMMIT_SHA
        .
    - docker push $IMAGE_TAG
    - docker push $CI_REGISTRY_IMAGE:latest

deploy:staging:
  stage: deploy
  image: bitnami/kubectl:latest
  script:
    - kubectl config use-context staging
    - helm upgrade --install my-app ./helm/my-app
        --namespace staging
        --set image.tag=$CI_COMMIT_SHORT_SHA
        --values ./helm/my-app/values-staging.yaml
        --wait
  environment:
    name: staging
    url: https://staging.my-app.example.com
  only:
    - develop

deploy:production:
  stage: deploy
  image: bitnami/kubectl:latest
  script:
    - kubectl config use-context production
    - helm upgrade --install my-app ./helm/my-app
        --namespace production
        --set image.tag=$CI_COMMIT_SHORT_SHA
        --values ./helm/my-app/values-production.yaml
        --wait
  environment:
    name: production
    url: https://my-app.example.com
  when: manual
  only:
    - main

Jenkins Pipeline(Declarative)

// Jenkinsfile
pipeline {
    agent any

    environment {
        REGISTRY = 'registry.example.com'
        IMAGE_NAME = 'my-app'
        IMAGE_TAG = "${env.BUILD_NUMBER}-${env.GIT_COMMIT.take(8)}"
    }

    stages {
        stage('Test') {
            agent { label 'golang' }
            steps {
                sh 'go test -race -coverprofile=coverage.out ./...'
                sh 'golangci-lint run ./...'
            }
        }

        stage('Security Scan') {
            steps {
                sh "trivy fs --severity CRITICAL,HIGH --exit-code 1 ."
            }
        }

        stage('Build & Push') {
            agent { label 'docker' }
            steps {
                script {
                    docker.withRegistry("https://${REGISTRY}", 'registry-credentials') {
                        def image = docker.build(
                            "${IMAGE_NAME}:${IMAGE_TAG}",
                            '--build-arg VCS_REF=${GIT_COMMIT} .'
                        )
                        image.push()
                        image.push('latest')
                    }
                }
            }
        }

        stage('Deploy to Staging') {
            when { branch 'develop' }
            steps {
                sh """
                    helm upgrade --install ${IMAGE_NAME} ./helm/${IMAGE_NAME} \
                        --namespace staging \
                        --set image.tag=${IMAGE_TAG} \
                        --values ./helm/${IMAGE_NAME}/values-staging.yaml \
                        --wait
                """
            }
        }

        stage('Deploy to Production') {
            when { branch 'main' }
            input {
                message '本番環境へのデプロイを確認しますか?'
                ok 'デプロイ'
            }
            steps {
                sh """
                    helm upgrade --install ${IMAGE_NAME} ./helm/${IMAGE_NAME} \
                        --namespace production \
                        --set image.tag=${IMAGE_TAG} \
                        --values ./helm/${IMAGE_NAME}/values-production.yaml \
                        --wait
                """
            }
        }
    }

    post {
        failure {
            slackSend(
                channel: '#cicd-alerts',
                color: 'danger',
                message: "パイプライン失敗: ${env.JOB_NAME} #${env.BUILD_NUMBER}"
            )
        }
        success {
            slackSend(
                channel: '#cicd-alerts',
                color: 'good',
                message: "デプロイ成功: ${env.JOB_NAME} #${env.BUILD_NUMBER} → ${IMAGE_TAG}"
            )
        }
    }
}

コンテナレジストリ管理

イメージタグ付け戦略

タグタイプ ライフサイクル 用途
不変タグ sha-abc1234 永続 本番デプロイ参照
セマンティックバージョン v2.1.0 永続 バージョンリリース
ブランチタグ main, develop 上書き可能 開発/プレビュー
latest latest 上書き可能 ローカル開発のみ

コア原則:本番環境では可変タグ(latest等)を絶対に使用せず、不変タグ(Git SHA等)を使用してください。

イメージクリーンアップ戦略

# GitHub Actions: 古いイメージの定期クリーンアップ
name: Registry Cleanup
on:
  schedule:
    - cron: '0 2 * * 0'  # 毎週日曜午前2時

jobs:
  cleanup:
    runs-on: ubuntu-latest
    steps:
      - name: Delete untagged images
        uses: actions/delete-package-versions@v5
        with:
          package-name: my-app
          min-versions-to-keep: 10
          delete-only-untagged-versions: true

セキュリティスキャン統合

Trivy:フルスタックセキュリティスキャン

# ファイルシステムスキャン(依存関係の脆弱性)
trivy fs --severity CRITICAL,HIGH --exit-code 1 .

# イメージスキャン
trivy image --severity CRITICAL,HIGH registry.example.com/my-app:v2.0.0

# IaCスキャン(K8s manifest / Dockerfile)
trivy config --severity CRITICAL,HIGH ./k8s/

# SBOM生成
trivy image --format spdx-json --output sbom.json registry.example.com/my-app:v2.0.0

Snyk:開発者フレンドリーなセキュリティプラットフォーム

# GitHub Actions: Snyk統合
- name: Snyk Open Source
  uses: snyk/actions/golang@master
  env:
    SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
  with:
    args: --severity-threshold=high

- name: Snyk Container
  uses: snyk/actions/docker@master
  env:
    SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
  with:
    image: registry.example.com/my-app:v2.0.0
    args: --severity-threshold=high --file=Dockerfile

セキュリティスキャンレイヤー

レイヤー ツール スキャン対象 トリガー
SAST Snyk Code / SonarQube ソースコードの脆弱性 各コミット
SCA Snyk Open Source / Trivy fs 依存関係の脆弱性 各コミット
コンテナスキャン Trivy image / Snyk Container イメージの脆弱性 イメージビルド後
IaCスキャン Trivy config / Checkov K8s/Dockerfile設定リスク PR段階
DAST OWASP ZAP ランタイム脆弱性 stagingデプロイ後

💡 Hash暗号化ツールでCI/CD Secretのチェックサムを生成し、機密設定の改ざんを防止できます。


環境管理:Dev / Staging / Prod

環境分離戦略

# Helm valuesマルチ環境設定
# values-development.yaml
replicaCount: 1
resources:
  requests:
    cpu: 100m
    memory: 128Mi
autoscaling:
  enabled: false
config:
  logLevel: debug
  dbHost: dev-db.internal

# values-staging.yaml
replicaCount: 2
resources:
  requests:
    cpu: 250m
    memory: 256Mi
autoscaling:
  enabled: true
  minReplicas: 2
  maxReplicas: 5
config:
  logLevel: info
  dbHost: staging-db.internal

# values-production.yaml
replicaCount: 3
resources:
  requests:
    cpu: 500m
    memory: 512Mi
  limits:
    cpu: 1000m
    memory: 1Gi
autoscaling:
  enabled: true
  minReplicas: 3
  maxReplicas: 20
  targetCPUUtilizationPercentage: 70
config:
  logLevel: warn
  dbHost: prod-db.internal

GitHub Actions Environment保護ルール

# 本番環境は手動承認が必要
deploy-production:
  runs-on: ubuntu-latest
  environment: production    # GitHub Settingsで承認者を設定
  steps:
    - name: Deploy
      run: helm upgrade --install my-app ./helm/my-app

GitHubリポジトリSettings → Environmentsで設定:

  • production:Required reviewers = 2名承認、Wait timer = 5分
  • staging:承認不要、自動デプロイ

モニタリングとアラート統合

Prometheus + Grafanaメトリクス収集

# K8s Pod Monitorアノテーション
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
  annotations:
    prometheus.io/scrape: "true"
    prometheus.io/port: "8080"
    prometheus.io/path: "/metrics"
spec:
  template:
    spec:
      containers:
        - name: my-app
          image: registry.example.com/my-app:v2.0.0
          ports:
            - containerPort: 8080

デプロイアラートルール

apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
  name: deployment-alerts
  namespace: monitoring
spec:
  groups:
    - name: deployment
      rules:
        - alert: DeploymentRolloutStuck
          expr: |
            kube_deployment_status_replicas_unavailable / kube_deployment_status_replicas > 0.5
          for: 5m
          labels:
            severity: warning
          annotations:
            summary: "Deployment {{ $labels.deployment }} のロールアウトが停滞"
        - alert: HighErrorRateAfterDeploy
          expr: |
            rate(http_requests_total{status=~"5.."}[5m])
            /
            rate(http_requests_total[5m]) > 0.05
          for: 3m
          labels:
            severity: critical
          annotations:
            summary: "デプロイ後5xxエラー率が5%を超過"

Slack/Teamsアラート通知

# GitHub Actions: デプロイ通知
- name: Notify Deployment
  if: always()
  uses: 8398a7/action-slack@v3
  with:
    status: ${{ job.status }}
    fields: repo,message,commit,author,action,eventName,ref,workflow
  env:
    SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK }}

ロールバック戦略

自動ロールバック:ヘルスチェック失敗時

# Helmデプロイ + 自動ロールバック
- name: Deploy with Auto Rollback
  run: |
    helm upgrade --install my-app ./helm/my-app \
      --namespace production \
      --set image.tag=${{ steps.meta.outputs.tags }} \
      --values ./helm/my-app/values-production.yaml \
      --timeout 5m \
      --wait || \
    (echo "デプロイ失敗、ロールバック実行中..." && \
     helm rollback my-app --namespace production && \
     exit 1)

手動ロールバック:Git SHAベース

# 特定リビジョンにロールバック
kubectl rollout undo deployment/my-app --to-revision=3

# Helmリリースのロールバック
helm rollback my-app 2 --namespace production

# GitOpsベースのロールバック:Gitコミットをリバート
git revert <commit-hash>
git push origin main
# ArgoCDが変更を自動検出してロールバックを実行

カナリア自動ロールバック

# Argo Rollouts: 自動分析 + ロールバック
apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
  name: my-app
spec:
  strategy:
    canary:
      canaryAnalysis:
        templates:
          - templateName: success-rate
            clusterScope: true
        startingStep: 2
        steps:
          - setWeight: 10
          - pause: { duration: 5m }
          - setWeight: 30
          - pause: { duration: 5m }
          - setWeight: 60
          - pause: { duration: 5m }
          - setWeight: 100
        analysisRun:
          successfulRunHistoryLimit: 3
          unsuccessfulRunHistoryLimit: 3

よくあるパイプライン障害と修正

障害現象 根本原因 修正案
Dockerビルドキャッシュ無効 .dockerignoreの欠落やCOPY順序エラー Dockerfile命令順序を最適化、.dockerignoreを追加
イメージプッシュ403 Registry認証期限切れや権限不足 Service Account / Token権限を確認
K8s ImagePullBackOff イメージタグが存在しない、またはRegistryに到達不能 イメージタグを検証、RegistryネットワークとSecretを確認
Helmデプロイタイムアウト readinessProbeの設定ミスやリソース不足 probeパラメータを調整、resources limitsを増加
ステージングと本番の不一致 環境設定の差異 Kustomize/Helmで統一管理、ハードコードを削減
セキュリティスキャンの誤検出 間接依存からの脆弱性 .trivyignoreやSnyk policyで既知の誤検出を無視
同時デプロイの競合 複数人が同時にパイプラインをトリガー GitHub ConcurrencyやGitLab resource_groupを使用
Secretの漏洩 YAMLやログに平文で記述 Sealed Secrets / External Secrets Operatorを使用

同時実行制御

# GitHub Actions: 同時デプロイ競合を防止
concurrency:
  group: deploy-${{ github.ref }}
  cancel-in-progress: true

デバッグティップス

# Podイベントを確認
kubectl describe pod <pod-name> -n <namespace>

# デプロイ履歴を確認
kubectl rollout history deployment/my-app -n production

# Helmリリース履歴を確認
helm history my-app -n production

# ポートフォワードでデバッグ
kubectl port-forward svc/my-app 8080:80 -n staging

# コンテナログを確認
kubectl logs -f deployment/my-app -n production --all-containers

FAQ

Q:GitHub Actionsの無料枠は十分ですか? A:パブリックリポジトリは無制限、プライベートリポジトリは月2000分(Linux)。セルフホストRunnerは制限なし。

Q:Dockerイメージにlatestタグを使用すべきですか? A:本番環境ではlatestを絶対に使用しないでください。Git SHAやセマンティックバージョンを不変タグとして使用し、デプロイのトレーサビリティとロールバック可能性を確保してください。

Q:ブルーグリーンとカナリアのどちらを選ぶべきですか? A:ブルーグリーンは高速ロールバックが必要なクリティカルサービスに(Service切替のみ)、カナリアは段階的検証が必要な高リスク変更に適しています。通常リリースにはローリングアップデートで十分です。

Q:GitOpsと従来のCI/CD Pushモデルの違いは? A:従来Pushモデル:CIパイプラインが能動的にkubectl apply。GitOps:クラスタ内Agent(ArgoCD)が能動的にGit変更をプル。GitOpsの利点:Gitが単一の真実の情報源、クラスタ状態ドリフトを自動修復。

Q:CI/CDでSecretをどう扱うべきですか? A:プラットフォームネイティブのSecret管理(GitHub Secrets / GitLab Variables / Jenkins Credentials)を使用し、K8sではSealed SecretsやExternal Secrets Operatorを使用。SecretをGitにコミットしないでください

Q:マルチクラスタデプロイをどう管理しますか? A:ArgoCD ApplicationSet + Gitディレクトリ構造、またはHelm + kubeconfigマルチコンテキスト切替を使用。ArgoCDがネイティブにマルチクラスタをサポートするため推奨。

Q:パイプラインが遅すぎる場合の最適化方法は? A:1)DockerレイヤキャッシュとGitHub Actionsキャッシュを活用;2)独立したJobを並列実行;3)セルフホストRunnerでコールドスタートを削減;4)インクリメンタルテスト(変更モジュールのみテスト)。

ブラウザローカルツールを無料で試す →

#DevOps#CI/CD#Docker#Kubernetes#教程