Хочу запустить в Kubernetes приложение, работающее с БД. Один экземпляр должен быть мастером, другие — воркерами. Опиши такой StatefulSet.

«Хочу запустить в Kubernetes приложение, работающее с БД. Один экземпляр должен быть мастером, другие — воркерами. Опиши такой StatefulSet.» — вопрос из категории Kubernetes, который задают на 23% собеседований Devops Инженер. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

StatefulSet идеально подходит для stateful-приложений с уникальной идентификацией подов. Вот пример манифеста для приложения с мастер-воркер топологией (например, для PostgreSQL с логической репликацией или кастомного приложения):

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: db-app
spec:
  serviceName: "db-app-hl" # Обязательно для работы Headless Service
  replicas: 3
  selector:
    matchLabels:
      app: db-app
  template:
    metadata:
      labels:
        app: db-app
    spec:
      containers:
      - name: app-container
        image: mycompany/db-app:latest
        ports:
        - containerPort: 5432
          name: db
        env:
        - name: POD_NAME
          valueFrom:
            fieldRef:
              fieldPath: metadata.name
        - name: REPLICA_COUNT
          value: "3"
        # Логика внутри контейнера определяет роль по POD_NAME
        # Например, pod 'db-app-0' становится мастером
        command: ["/bin/sh", "-c"]
        args:
          - |
            if [[ "$POD_NAME" = "db-app-0" ]]; then
              echo "Starting as MASTER";
              /usr/bin/start-master.sh;
            else
              echo "Starting as WORKER";
              /usr/bin/start-worker.sh --master-host db-app-0.db-app-hl.default.svc.cluster.local;
            fi
        volumeMounts:
        - name: data
          mountPath: /var/lib/app-data
  volumeClaimTemplates: # Каждый под получает свой уникальный PVC
  - metadata:
      name: data
    spec:
      accessModes: [ "ReadWriteOnce" ]
      resources:
        requests:
          storage: 10Gi
---
# Headless Service для стабильных DNS-имен подов
apiVersion: v1
kind: Service
metadata:
  name: db-app-hl
spec:
  clusterIP: None # Headless Service
  selector:
    app: db-app
  ports:
  - port: 5432
    name: db

Ключевые моменты реализации:

  1. Определение роли: Скрипт инициализации в контейнере проверяет $POD_NAME (или $HOSTNAME). Pod с индексом -0 назначается мастером.
  2. Обнаружение сервиса (Service Discovery): Headless Service (clusterIP: None) создает DNS-записи вида: db-app-0.db-app-hl.default.svc.cluster.local. Это позволяет воркерам надежно подключаться к мастеру.
  3. Устойчивое хранилище: volumeClaimTemplates гарантирует, что каждый под (db-app-0, db-app-1...) получит свой постоянный том, который будет за ним закреплен даже после пересоздания.
  4. Упорядоченный деплой/апдейт: По умолчанию поды создаются и обновляются последовательно (от 0 к N-1), что критично для выбора мастера перед запуском воркеров.