404 Not Found

404 Not Found


nginx

総合演習:OrderFlowプロジェクトデプロイ

デプロイはラストマイルです。CI/CD自動化, K8sオーケストレーション, 監視アラートが, アプリケーションを開発から本番までシームレスに運びます。

1. 学ぶこと


2. DevOpsエンジニアの実話

(1) ペインポイント: 手動デプロイは地雷を踏むようなもの

BobはOrderFlowを手動で本番にデプロイしていました:ローカルでmvn packagedocker build → イメージプッシュ → kubectl apply → ヘルスステータス確認。全体で30分かかり, ミスが頻発:設定の更新忘れ, 間違ったイメージバージョンのプッシュ, ローリングアップデート時の旧Podのグレースフルシャットダウン失敗による502エラー。

(2) CI/CDソリューション

自動化生産ラインのワンストップサービス:

100%
graph LR
    A["Git Push"] --> B["GitHub Actions Build + Test"]
    B --> C["Docker Build + Push to Registry"]
    C --> D["K8s Rolling Deploy"]
    D --> E["Health Check + Smoke Test"]
    E --> F["Monitor Grafana"]

(3) 成果

BobがCI/CDを構築した後, コードプッシュが自動デプロイをトリガーし, コードから本番まで5分で完了するようになりました。HPAが自動スケーリング, Prometheusが自動アラートを担当し, Bobは「消防士」から「監視オブザーバー」へと変わりました。


3. CI/CDパイプライン

(1) ▶ サンプル:GitHub Actionsワークフロー

YAML
# .github/workflows/deploy.yml
name: OrderFlow CI/CD

on:
  push:
    branches: [main]
    tags: ['v*']

env:
  REGISTRY: registry.example.com
  IMAGE_NAME: orderflow-service

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v4

    - name: Set up JDK 17
      uses: actions/setup-java@v4
      with:
        java-version: '17'
        distribution: 'temurin'

    - name: Run tests
      run: mvn verify -B

    - name: Build Docker image
      run: docker build -t ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }} .

    - name: Login to Registry
      run: echo "${{ secrets.REGISTRY_PASSWORD }}" | docker login ${{ env.REGISTRY }} -u ${{ secrets.REGISTRY_USERNAME }} --password-stdin

    - name: Push image
      run: docker push ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }}

  deploy:
    needs: build
    runs-on: ubuntu-latest
    if: startsWith(github.ref, 'refs/tags/v')
    steps:
    - uses: actions/checkout@v4

    - name: Deploy to Kubernetes
      run: |
        kubectl set image deployment/orderflow \
          orderflow=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }} \
          -n orderflow
        kubectl rollout status deployment/orderflow -n orderflow --timeout=300s

    - name: Smoke test
      run: |
        sleep 10
        curl -sf https://api.orderflow.example.com/actuator/health | grep '"status":"UP"'

出力:

TEXT
CONTAINER ID   IMAGE          STATUS         PORTS
abc123         nginx:latest   Up 2 hours     0.0.0.0:80->80/tcp
パイプラインステージ 操作 失敗時の処理
Build + Test mvn verify デプロイをブロック
Docker Build マルチステージイメージビルド デプロイをブロック
Push Registry イメージレジストリにプッシュ 3回リトライ
K8s Deploy kubectl set image + rollout 自動ロールバック
Smoke Test ヘルスチェック検証 ロールバック + 通知

4. K8s本番デプロイ

(1) ▶ サンプル:本番グレードDeployment + HPA

YAML
apiVersion: apps/v1
kind: Deployment
metadata:
  name: orderflow
  namespace: orderflow
spec:
  replicas: 3
  selector:
    matchLabels: { app: orderflow }
  strategy:
    rollingUpdate: { maxUnavailable: 0, maxSurge: 1 }
  template:
    metadata:
      labels: { app: orderflow }
    spec:
      terminationGracePeriodSeconds: 60
      containers:
      - name: orderflow
        image: registry.example.com/orderflow-service:latest
        ports:
        - { containerPort: 8080 }
        - { containerPort: 8081 }
        envFrom:
        - configMapRef: { name: orderflow-config }
        - secretRef: { name: orderflow-secrets }
        resources:
          requests: { memory: "512Mi", cpu: "250m" }
          limits: { memory: "1Gi", cpu: "1000m" }
        lifecycle:
          preStop:
            exec:
              command: ["sh", "-c", "sleep 10"]
        livenessProbe:
          httpGet: { path: /actuator/health/liveness, port: 8080 }
          initialDelaySeconds: 60
          periodSeconds: 30
        readinessProbe:
          httpGet: { path: /actuator/health/readiness, port: 8080 }
          initialDelaySeconds: 30
          periodSeconds: 10
---
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: orderflow-hpa
  namespace: orderflow
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: orderflow
  minReplicas: 3
  maxReplicas: 10
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 70
  - type: Resource
    resource:
      name: memory
      target:
        type: Utilization
        averageUtilization: 80

出力:

TEXT
Deployment.apps/my-app created
Service/my-app-service exposed
Ingress/my-app-ingress created
K8s本番設定 理由
maxUnavailable: 0 ゼロダウンタイム 常に目標レプリカ数を維持
terminationGracePeriodSeconds: 60 グレースフルシャットダウン リクエスト排出を待機
preStop: sleep 10 遅延終了 PodがServiceから除外された後もK8sがトラフィックを排出し続ける
resources.requests/limits QoS設定 リソース割り当て保証 + 超過制限

(2) ▶ サンプル:Ingress + TLS

YAML
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: orderflow-ingress
  namespace: orderflow
  annotations:
    cert-manager.io/cluster-issuer: letsencrypt-prod
    nginx.ingress.kubernetes.io/rate-limit: "100"
    nginx.ingress.kubernetes.io/ssl-redirect: "true"
spec:
  ingressClassName: nginx
  tls:
  - hosts: [api.orderflow.example.com]
    secretName: orderflow-tls
  rules:
  - host: api.orderflow.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service: { name: orderflow, port: { number: 80 } }

出力:

TEXT
Deployment.apps/my-app created
Service/my-app-service exposed
Ingress/my-app-ingress created

5. オブザーバビリティ立ち上げ

(1) ▶ サンプル:Prometheus + AlertManager

YAML
# prometheus.yml
scrape_configs:
- job_name: orderflow
  metrics_path: /actuator/prometheus
  scrape_interval: 15s
  kubernetes_sd_configs:
  - role: pod
    namespaces:
      names: [orderflow]
  relabel_configs:
  - source_labels: [__meta_kubernetes_pod_label_app]
    action: keep
    regex: orderflow

出力:

TEXT
Deployment.apps/my-app created
Service/my-app-service exposed
Ingress/my-app-ingress created
YAML
# alert_rules.yml
groups:
- name: orderflow-slo
  rules:
  - alert: SLOErrorRateExceeded
    expr: |
      sum(rate(http_server_requests_seconds_total{namespace="orderflow",status=~"5.."}[5m]))
      / sum(rate(http_server_requests_seconds_total{namespace="orderflow"}[5m])) > 0.001
    for: 5m
    labels: { severity: critical }
    annotations:
      summary: "OrderFlow error rate exceeds SLO (0.1%)"

  - alert: SLOLatencyExceeded
    expr: |
      histogram_quantile(0.99,
        sum(rate(http_server_requests_seconds_bucket{namespace="orderflow"}[5m])) by (le))
      > 0.1
    for: 5m
    labels: { severity: warning }
    annotations:
      summary: "OrderFlow P99 latency exceeds SLO (100ms)"

(2) ▶ サンプル:Grafana SLOダッシュボードメトリクス

ダッシュボード PromQL SLO目標
P99レイテンシ histogram_quantile(0.99, sum(rate(http_server_requests_seconds_bucket{namespace="orderflow"}[5m])) by (le)) < 100 ms
エラー率 sum(rate(http_server_requests_seconds_total{namespace="orderflow",status=~"5.."}[5m])) / sum(rate(http_server_requests_seconds_total{namespace="orderflow"}[5m])) < 0.1%
可用性 1 - (sum(rate(http_server_requests_seconds_total{namespace="orderflow",status=~"5.."}[5m])) / sum(rate(http_server_requests_seconds_total{namespace="orderflow"}[5m]))) > 99.9%
注文スループット rate(orderflow_orders_created_total[1m]) * 60 > 100/分

6. 本番セキュリティ強化

(1) ▶ サンプル:NetworkPolicy + Podセキュリティ

YAML
# NetworkPolicy: アクセス制限
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: orderflow-netpol
  namespace: orderflow
spec:
  podSelector:
    matchLabels: { app: orderflow }
  policyTypes: [Ingress]
  ingress:
  - from:
    - namespaceSelector:
        matchLabels: { name: ingress-nginx }
    ports:
    - { port: 8080, protocol: TCP }
  - from:
    - namespaceSelector:
        matchLabels: { name: monitoring }
    ports:
    - { port: 8081, protocol: TCP }
---
# Podセキュリティ: 非rootで実行
apiVersion: v1
kind: LimitRange
metadata:
  name: orderflow-limits
  namespace: orderflow
spec:
  limits:
  - type: Container
    default:
      memory: "1Gi"
      cpu: "500m"
    defaultRequest:
      memory: "256Mi"
      cpu: "100m"

出力:

TEXT
Deployment.apps/my-app created
Service/my-app-service exposed
Ingress/my-app-ingress created
セキュリティ強化項目 対策 説明
非root実行 Dockerfile USER appuser コンテナ脱出を防止
NetworkPolicy 送信元の制限 Ingressと監視アクセスのみ許可
Secret暗号化 etcd暗号化設定 Secretの平文保存を防止
TLS cert-manager自動証明書 暗号化伝送
リソース制限 LimitRange リソース競合を防止

7. 総合サンプル:OrderFlow完全デプロイチェックリスト

YAML
# k8s/orderflow-complete.yaml
---
apiVersion: v1
kind: Namespace
metadata:
  name: orderflow
  labels: { name: orderflow }

---
apiVersion: v1
kind: ConfigMap
metadata: { name: orderflow-config, namespace: orderflow }
data:
  SPRING_PROFILES_ACTIVE: "prod"
  DB_HOST: "mysql.orderflow.svc.cluster.local"
  REDIS_HOST: "redis.orderflow.svc.cluster.local"
  MANAGEMENT_SERVER_PORT: "8081"

---
apiVersion: v1
kind: Secret
metadata: { name: orderflow-secrets, namespace: orderflow }
type: Opaque
data:
  DB_PASSWORD: <base64-encoded>
  REDIS_PASSWORD: <base64-encoded>
  JWT_PRIVATE_KEY: <base64-encoded>

---
apiVersion: apps/v1
kind: Deployment
metadata: { name: orderflow, namespace: orderflow }
spec:
  replicas: 3
  selector: { matchLabels: { app: orderflow } }
  strategy: { rollingUpdate: { maxUnavailable: 0, maxSurge: 1 } }
  template:
    metadata: { labels: { app: orderflow } }
    spec:
      terminationGracePeriodSeconds: 60
      containers:
      - name: orderflow
        image: registry.example.com/orderflow-service:1.0.0
        ports: [{ containerPort: 8080 }, { containerPort: 8081 }]
        envFrom:
        - { configMapRef: { name: orderflow-config } }
        - { secretRef: { name: orderflow-secrets } }
        resources:
          requests: { memory: "512Mi", cpu: "250m" }
          limits: { memory: "1Gi", cpu: "1000m" }
        lifecycle:
          preStop: { exec: { command: ["sh", "-c", "sleep 10"] } }
        livenessProbe:
          httpGet: { path: /actuator/health/liveness, port: 8080 }
          initialDelaySeconds: 60; periodSeconds: 30
        readinessProbe:
          httpGet: { path: /actuator/health/readiness, port: 8080 }
          initialDelaySeconds: 30; periodSeconds: 10

---
apiVersion: v1
kind: Service
metadata: { name: orderflow, namespace: orderflow }
spec:
  selector: { app: orderflow }
  ports:
  - { name: http, port: 80, targetPort: 8080 }
  - { name: management, port: 8081, targetPort: 8081 }

---
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata: { name: orderflow-hpa, namespace: orderflow }
spec:
  scaleTargetRef: { apiVersion: apps/v1, kind: Deployment, name: orderflow }
  minReplicas: 3
  maxReplicas: 10
  metrics:
  - { type: Resource, resource: { name: cpu, target: { type: Utilization, averageUtilization: 70 } } }

---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: orderflow-ingress
  namespace: orderflow
  annotations:
    cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
  ingressClassName: nginx
  tls:
  - { hosts: [api.orderflow.example.com], secretName: orderflow-tls }
  rules:
  - host: api.orderflow.example.com
    http:
      paths:
      - { path: /, pathType: Prefix, backend: { service: { name: orderflow, port: { number: 80 } } } }

❓ よくある質問

Q GitHub ActionsとJenkins, どちらを選ぶべきですか?
A GitHub ActionsはGitHubエコシステムと統合されており設定が簡単で, 中小規模プロジェクトに適しています。Jenkinsはより強力な機能がありますが設定が複雑で, 大企業に適しています。GitHubリポジトリを既にお使いならGitHub Actionsを推奨します。
Q ローリングアップデートでのゼロダウンタイムをどう確保しますか?
A 1) maxUnavailable=0; 2) readinessProbeで準備完了のPodのみServiceに追加; 3) preStop sleep 10でPodがServiceから除外された後もK8sがリクエストを排出する時間を確保; 4) server.shutdown=gracefulを設定。
Q HPAのminReplicasとmaxReplicasはどう設定すべきですか?
A minReplicas = 通常負荷に必要なレプリカ数 (OrderFlow = 3); maxReplicas = 推定ピーク負荷 (OrderFlow = 10)。過去の監視データに基づいて調整してください。推奨CPU利用率ターゲットは70%です。
Q Secret管理のベストプラクティスは?
A 1) K8s Secrets + etcd暗号化 (基本アプローチ); 2) External Secrets Operator + AWS Secrets Manager/Vault (推奨アプローチ); 3) Sealed Secrets (GitOpsに適合)。Secretを平文でGitにコミットしないでください。
Q ブルーグリーンデプロイやカナリアデプロイはどう実装しますか?
A K8sはネイティブではブルーグリーン/カナリアデプロイをサポートしません。IstioやArgo Rolloutsなどのツールが必要です。Argo Rolloutsはカナリア (段階的トラフィック移行)とブルーグリーン (瞬時切替)をサポートし, Prometheusによる検証が可能です。
Q 本番環境の監視アラートは何をカバーすべきですか?
A 3大カテゴリ:1) SLOアラート (P99レイテンシ, エラー率, 可用性); 2) リソースアラート (CPU > 80%, メモリ > 85%, ディスク > 90%); 3) ビジネスアラート (注文量の異常な低下, 決済成功率の低下)。

📖 まとめ


📝 練習問題

  1. 基本問題 (難易度:⭐): GitHub Actionsワークフローを書き, コードプッシュ後に自動テストとDockerイメージビルドを行ってください。

  2. 応用問題 (難易度:⭐⭐): 完全なK8s本番デプロイYAML (Deployment + Service + Ingress + HPA + ConfigMap + Secret)を書き, ゼロダウンタイムのローリングアップデートを実装してください。

  3. チャレンジ (難易度:⭐⭐⭐): 完全なオブザーバビリティシステム (Prometheus + Grafana + AlertManager + Jaeger)を構築し, SLOダッシュボードとアラートルールを設定し, 障害をシミュレートしてアラートと自動復旧能力をテストしてください。

Web-Tutorial.com

Web-Tutorial 技術チーム

複数の開発者によって共同維持されているプログラミングチュートリアルプラットフォーム。各チュートリアルは専門分野の開発者が執筆・レビューしています。正確で信頼性の高いコンテンツを目指しています — 問題を見つけた場合はお知らせください。

100%