LESSON 40分

「Deployment だけ知っていても足りない。StatefulSet、DaemonSet、Job、それぞれに適した使い所がある。ワークロードの特性に合わせたリソースを選べるかどうかが、本番運用の品質を決めるんだ」と佐藤CTOが説明した。

推定読了時間: 40分


ワークロードリソースの全体像

リソース用途ステートスケーリング
Deploymentステートレスアプリなし水平
StatefulSetステートフルアプリあり水平(順序付き)
DaemonSetノードごとのエージェントなしノード数に連動
Job一回限りのタスクなし並列実行
CronJob定期タスクなしスケジュール実行

Deployment 戦略

RollingUpdate(デフォルト)

apiVersion: apps/v1
kind: Deployment
metadata:
  name: api-server
spec:
  replicas: 6
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxUnavailable: 1  # 最大1台まで停止可能
      maxSurge: 2         # 最大2台まで追加起動
  selector:
    matchLabels:
      app: api-server
  template:
    metadata:
      labels:
        app: api-server
        version: v2.0.0
    spec:
      containers:
        - name: api
          image: my-registry/api-server:v2.0.0
          ports:
            - containerPort: 3000
          readinessProbe:
            httpGet:
              path: /ready
              port: 3000
            initialDelaySeconds: 5
            periodSeconds: 10
          livenessProbe:
            httpGet:
              path: /health
              port: 3000
            initialDelaySeconds: 15
            periodSeconds: 20
          startupProbe:
            httpGet:
              path: /health
              port: 3000
            failureThreshold: 30
            periodSeconds: 2
          resources:
            requests:
              cpu: 250m
              memory: 256Mi
            limits:
              memory: 512Mi
              # CPU limits は設定しない(スロットリング回避)

Canary Deployment(手動)

# Canary: 少数のPodに新バージョンをデプロイ
apiVersion: apps/v1
kind: Deployment
metadata:
  name: api-server-canary
spec:
  replicas: 1  # 全体の約15%
  selector:
    matchLabels:
      app: api-server
      track: canary
  template:
    metadata:
      labels:
        app: api-server
        track: canary
        version: v2.1.0
    spec:
      containers:
        - name: api
          image: my-registry/api-server:v2.1.0
---
# Service は label app: api-server でルーティング
# → 安定版6台 + Canary1台 = 約15%が新バージョンへ
apiVersion: v1
kind: Service
metadata:
  name: api-server
spec:
  selector:
    app: api-server  # track を含まない → 両方にマッチ
  ports:
    - port: 80
      targetPort: 3000

「本格的な Canary なら Argo Rollouts や Flagger を使うべきだ。トラフィック比率を細かく制御できる」


StatefulSet

データベース、メッセージキューなどステートフルなワークロード向け。

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: postgres
spec:
  serviceName: postgres  # Headless Service 名
  replicas: 3
  podManagementPolicy: OrderedReady  # 順番にスケール
  updateStrategy:
    type: RollingUpdate
    rollingUpdate:
      partition: 0  # この番号以上のPodのみ更新
  selector:
    matchLabels:
      app: postgres
  template:
    metadata:
      labels:
        app: postgres
    spec:
      terminationGracePeriodSeconds: 60
      containers:
        - name: postgres
          image: postgres:16
          ports:
            - containerPort: 5432
              name: postgres
          env:
            - name: POSTGRES_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: postgres-secret
                  key: password
            - name: PGDATA
              value: /var/lib/postgresql/data/pgdata
          volumeMounts:
            - name: data
              mountPath: /var/lib/postgresql/data
          resources:
            requests:
              cpu: 500m
              memory: 1Gi
            limits:
              memory: 2Gi
  volumeClaimTemplates:
    - metadata:
        name: data
      spec:
        accessModes: ["ReadWriteOnce"]
        storageClassName: fast-ssd
        resources:
          requests:
            storage: 100Gi
---
# Headless Service(ClusterIP: None)
apiVersion: v1
kind: Service
metadata:
  name: postgres
spec:
  clusterIP: None
  selector:
    app: postgres
  ports:
    - port: 5432
      targetPort: 5432

StatefulSet の特徴

特徴説明
安定したネットワークIDpostgres-0, postgres-1, postgres-2
安定したストレージPVC がPodに紐付く
順序付きデプロイ0 → 1 → 2 の順で起動
順序付き削除2 → 1 → 0 の順で停止
DNS名:
postgres-0.postgres.default.svc.cluster.local
postgres-1.postgres.default.svc.cluster.local
postgres-2.postgres.default.svc.cluster.local

DaemonSet

全ノード(または特定のノード)に1つずつPodを配置します。

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: fluent-bit
  namespace: logging
spec:
  selector:
    matchLabels:
      app: fluent-bit
  updateStrategy:
    type: RollingUpdate
    rollingUpdate:
      maxUnavailable: 1
  template:
    metadata:
      labels:
        app: fluent-bit
    spec:
      serviceAccountName: fluent-bit
      tolerations:
        # マスターノードにも配置
        - key: node-role.kubernetes.io/control-plane
          effect: NoSchedule
      containers:
        - name: fluent-bit
          image: fluent/fluent-bit:2.2
          volumeMounts:
            - name: varlog
              mountPath: /var/log
              readOnly: true
            - name: containers
              mountPath: /var/lib/docker/containers
              readOnly: true
          resources:
            requests:
              cpu: 50m
              memory: 64Mi
            limits:
              memory: 128Mi
      volumes:
        - name: varlog
          hostPath:
            path: /var/log
        - name: containers
          hostPath:
            path: /var/lib/docker/containers

DaemonSet のユースケース

ユースケース
ログ収集Fluent Bit, Filebeat
メトリクス収集Node Exporter, Datadog Agent
ストレージCeph OSD, Longhorn
ネットワークCalico, Cilium, kube-proxy

Job / CronJob

Job

apiVersion: batch/v1
kind: Job
metadata:
  name: db-migration-v42
spec:
  backoffLimit: 3
  activeDeadlineSeconds: 600
  ttlSecondsAfterFinished: 3600
  template:
    spec:
      containers:
        - name: migrate
          image: my-registry/api-server:v2.0.0
          command: ["npx", "prisma", "migrate", "deploy"]
          envFrom:
            - secretRef:
                name: db-credentials
      restartPolicy: Never

CronJob

apiVersion: batch/v1
kind: CronJob
metadata:
  name: nightly-report
spec:
  schedule: "0 2 * * *"  # 毎日 AM 2:00
  concurrencyPolicy: Forbid  # 前回が完了するまで次を開始しない
  successfulJobsHistoryLimit: 3
  failedJobsHistoryLimit: 3
  startingDeadlineSeconds: 300
  jobTemplate:
    spec:
      backoffLimit: 2
      template:
        spec:
          containers:
            - name: report
              image: my-registry/report-generator:latest
              command: ["node", "dist/generate-report.js"]
              resources:
                requests:
                  cpu: 500m
                  memory: 512Mi
          restartPolicy: OnFailure

Init Containers

メインコンテナの起動前に実行される初期化コンテナ。

apiVersion: v1
kind: Pod
metadata:
  name: api-server
spec:
  initContainers:
    # 1. DBの準備を待つ
    - name: wait-for-db
      image: busybox:1.36
      command:
        - sh
        - -c
        - |
          until nc -z postgres.default.svc.cluster.local 5432; do
            echo "Waiting for database..."
            sleep 2
          done

    # 2. マイグレーション実行
    - name: run-migration
      image: my-registry/api-server:v2.0.0
      command: ["npx", "prisma", "migrate", "deploy"]
      envFrom:
        - secretRef:
            name: db-credentials

    # 3. 設定ファイルのダウンロード
    - name: fetch-config
      image: amazon/aws-cli:2.15
      command:
        - sh
        - -c
        - |
          aws s3 cp s3://my-bucket/config.yaml /config/config.yaml
      volumeMounts:
        - name: config
          mountPath: /config

  containers:
    - name: api
      image: my-registry/api-server:v2.0.0
      volumeMounts:
        - name: config
          mountPath: /config
          readOnly: true
  volumes:
    - name: config
      emptyDir: {}

HPA (Horizontal Pod Autoscaler)

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: api-server
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: api-server
  minReplicas: 3
  maxReplicas: 20
  behavior:
    scaleUp:
      stabilizationWindowSeconds: 60
      policies:
        - type: Percent
          value: 50
          periodSeconds: 60
    scaleDown:
      stabilizationWindowSeconds: 300
      policies:
        - type: Percent
          value: 25
          periodSeconds: 120
  metrics:
    - type: Resource
      resource:
        name: cpu
        target:
          type: Utilization
          averageUtilization: 70
    - type: Resource
      resource:
        name: memory
        target:
          type: Utilization
          averageUtilization: 80
    - type: Pods
      pods:
        metric:
          name: http_requests_per_second
        target:
          type: AverageValue
          averageValue: "1000"
KEDA (Kubernetes Event-Driven Autoscaling) の例
apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
  name: order-processor
spec:
  scaleTargetRef:
    name: order-processor
  minReplicaCount: 1
  maxReplicaCount: 50
  triggers:
    - type: aws-sqs-queue
      metadata:
        queueURL: https://sqs.ap-northeast-1.amazonaws.com/123456789/orders
        queueLength: "10"  # キューに10メッセージごとに1Pod
        awsRegion: ap-northeast-1

まとめ

リソース最適なユースケース注意点
DeploymentWeb API, Workerステートレス前提
StatefulSetDB, Cache, MQPVC と Headless Service が必要
DaemonSetログ/メトリクス収集tolerations の設定
Jobマイグレーション, バッチbackoffLimit の設定
CronJob定期バッチconcurrencyPolicy の設定
Init Container起動前の初期化順番に実行される

チェックリスト

  • Deployment の RollingUpdate 戦略を理解している
  • StatefulSet の順序保証と安定したIDを理解している
  • DaemonSet の用途と tolerations を理解している
  • Job/CronJob の設定パラメータを理解している
  • Init Containers のユースケースを理解している
  • HPA のスケーリング behavior を設定できる

次のステップへ

次のレッスンでは、Kubernetes のネットワーキングと Ingress について深掘りします。