CTS-KB

Pod・ReplicaSet・Deployment:Webアプリを継続稼働させる仕組み

⏱ 約 3 分で読めます
#Kubernetes#GKE#Pod#ReplicaSet#Deployment

WebアプリをKubernetesで継続稼働させるとき、通常はPodを直接作りません。Deployment → ReplicaSet → Pod という所有関係を使います。

Kubernetesワークロードの所有関係

3層の責務

オブジェクト主な責務直接操作する頻度
Pod1個以上のコンテナを実行する最小単位調査対象。通常は直接作らない
ReplicaSet同じPodを指定数に保つDeploymentが管理するため通常触らない
DeploymentReplicaSetの世代、更新、ロールバックを管理Web/API運用の主な操作対象

Podが削除されてもReplicaSetが新しいPodを作り、イメージを更新するとDeploymentが新しいReplicaSetへ段階的に切り替えます。

Deploymentマニフェスト

apiVersion: apps/v1
kind: Deployment
metadata:
  name: example-api
  namespace: YOUR_NAMESPACE
  labels:
    app: example-api
spec:
  replicas: 3
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxUnavailable: 1
      maxSurge: 1
  selector:
    matchLabels:
      app: example-api
  template:
    metadata:
      labels:
        app: example-api
    spec:
      containers:
        - name: api
          image: registry.gitlab.com/GROUP/PROJECT/IMAGE:TAG
          ports:
            - name: http
              containerPort: 8080
          resources:
            requests:
              cpu: 100m
              memory: 128Mi
            limits:
              cpu: 500m
              memory: 256Mi
          readinessProbe:
            httpGet:
              path: /health/ready
              port: http
            initialDelaySeconds: 5
            periodSeconds: 10
          livenessProbe:
            httpGet:
              path: /health/live
              port: http
            initialDelaySeconds: 15
            periodSeconds: 20

このイメージパスは形式例です。第12回でGitLab Container Registryからpullする認証を設定します。

labelとselectorが接着剤になる

Deploymentは spec.selector.matchLabels に一致するPodを管理します。そのため次の2箇所を一致させます。

selector:
  matchLabels:
    app: example-api
template:
  metadata:
    labels:
      app: example-api

Serviceも同じラベルでPodを選択できます。名前が似ているだけでは関連付かず、ラベルセレクターがオブジェクト間を結ぶことを覚えます。

所有関係をコマンドで確認する

kubectl apply -f deployment.yaml
kubectl get deployment,replicaset,pods -n YOUR_NAMESPACE
kubectl describe deployment example-api -n YOUR_NAMESPACE
kubectl get pods -n YOUR_NAMESPACE -l app=example-api --show-labels

Pod名は example-api-<ReplicaSet hash>-<suffix> のようになります。更新後にhashの異なるReplicaSetとPodが現れることで、世代交代を確認できます。

自己修復を確認する

学習環境でPodを1つ削除すると、ReplicaSetが代わりを作ります。

kubectl delete pod YOUR_POD_NAME -n YOUR_NAMESPACE
kubectl get pods -n YOUR_NAMESPACE -l app=example-api -w

これは同じPodが復活するのではなく、望ましいレプリカ数を満たす新しいPodが作られる動きです。Pod名やIPを永続IDとして扱ってはいけない理由でもあります。

ローリングアップデート

マニフェストの image を新しい固定タグへ変更し、差分を確認して適用します。

kubectl diff -f deployment.yaml
kubectl apply -f deployment.yaml
kubectl rollout status deployment/example-api -n YOUR_NAMESPACE
kubectl rollout history deployment/example-api -n YOUR_NAMESPACE

maxUnavailable: 1 は更新中に利用不能を許す最大数、maxSurge: 1 は指定レプリカ数を超えて一時追加できる最大数です。レプリカが1個しかない場合、設定とアプリの起動時間によっては停止時間が生じ得ます。

問題があればロールバックする

kubectl rollout undo deployment/example-api -n YOUR_NAMESPACE
kubectl rollout status deployment/example-api -n YOUR_NAMESPACE

ロールバック後もログ、イベント、実際の応答を確認します。原因不明のまま再デプロイを繰り返すと証拠を失うため、まず describelogs --previous を保存します。

Probeの役割

  • readinessProbe:通信を受けられるか。失敗中はServiceの転送先から外れる
  • livenessProbe:停止状態から自力回復できないか。連続失敗すると再起動対象になる
  • startupProbe:起動が遅いアプリの初期化完了まで他のProbeを待たせる

Probeは「とりあえず同じ /health」ではなく、目的に合わせて設計します。外部DBが一時停止しただけで全Podのlivenessが失敗する設計は、再起動ループを悪化させることがあります。

ReplicaSetを直接変更しない

Deployment配下のReplicaSetを直接scaleまたは編集しても、Deploymentの望ましい状態によって戻されたり、次回更新で失われたりします。変更点はDeploymentへ記述します。

次回

常時稼働ではなく完了する処理は、Job・CronJobによるバッチ処理へ分けます。

参考資料