コンテンツにスキップ

12. StatefulSet

ステートフルなアプリケーションを管理するためのリソース

Deployment StatefulSet
Pod 名 ランダム(app-7f4bf9767c-47jpd) 固定(db-0, db-1)
起動順序 保証されない 順番通り(db-0 → db-1)
ストレージ Pod ごとに共有 Pod ごとに独立した PVC が自動作成される
用途 ステートレスなアプリ DB など状態を持つアプリ

PostgreSQLがDeploymentに適さない理由

Pod名が変わる

再起動のたびにPod名が変わる P

PVC との紐づきが不安定

DeploymentではPodとPVCの紐づきが保証されない。Podが別ノードに移動したとき、同じPVCに接続できない可能性がある。

k8s/db-statefulset.yaml
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: db
  namespace: app
spec:
  serviceName: db # Headless Service の名前
  replicas: 1
  selector:
    matchLabels:
      io.kompose.service: db
  template:
    metadata:
      labels:
        io.kompose.service: db # Podに付与するラベル名
    spec:
      containers:
        - env:
            - name: POSTGRES_DB
              value: todo
            - name: POSTGRES_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: app-secret
                  key: postgres-password
            - name: POSTGRES_USER
              valueFrom:
                secretKeyRef:
                  name: app-secret
                  key: postgres-user
          image: postgres:17
          livenessProbe: # Podが生きているか確認する。pg_isreadyを定期実行し、DBが応答しなければPodを再起動する
            exec:
              command:
                - pg_isready
                - -U
                - postgres
            initialDelaySeconds: 5 # 起動後何秒後にチェックを開始するか
            periodSeconds: 10 # 何秒ごとにチェックするか
            timeoutSeconds: 5 # この秒数以内に応答しなかったら失敗扱い
            failureThreshold: 10 # この回数だけ失敗したら再起動
          readinessProbe: # Podがリクエスト処理可能か確認する。pg_isreadyを定期実行し、DBが応答しなければPodを再起動する
            exec:
              command:
                - pg_isready
                - -U
                - postgres
            initialDelaySeconds: 5 # 起動後何秒後にチェックを開始するか
            periodSeconds: 10 # 何秒ごとにチェックするか
            timeoutSeconds: 5 # この秒数以内に応答しなかったら失敗扱い
            failureThreshold: 3 # この回数だけ失敗したらトラフィック除外
          name: db
          ports:
            - containerPort: 5432
              protocol: TCP
          volumeMounts: # 下に定義されているvolumesをコンテナに接続する
            - mountPath: /docker-entrypoint-initdb.d/init.sql
              name: db-cm0
              subPath: init.sql # ConfigMapのinit.sqlを参照するということ
            - mountPath: /var/lib/postgresql/data
              name: pgdata # PVCのキー名
      volumes: # ボリュームの実体定義
        - configMap:
            items:
              - key: init.sql
                path: init.sql
            name: db-cm0
          name: db-cm0
  volumeClaimTemplates: # Pod ごとに PVC を自動作成
    - metadata:
        name: pgdata
      spec:
        accessModes: ["ReadWriteOnce"]
        resources:
          requests:
            storage: 100Mi
k8s/db-service.yaml
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
# データベース側Service
# アプリ側のPodデータベース側Podへのアクセスを中継する窓口
apiVersion: v1
kind: Service
metadata:
  labels:
    io.kompose.service: db
  name: db # アプリのDATABASE_URLに書かれているdb:5432のdb部分
  namespace: app
spec:
  clusterIP: None # Headless Service。StatefulSetのPodにDNS名を付与する
  ports:
    - name: "5432"
      port: 5432 # アプリのDATABASE_URLに書かれているdb:5432の5432部分
      targetPort: 5432 # 転送先
  selector:
    io.kompose.service: db # このServiceに来たリクエストをdbというラベル名のPodに届ける