Настройка проверки готовности, работоспособности или запуска

Мне сложно понять, что лучше всего подходит для моей ситуации и как это реализовать.

В двух словах проблема такая:

  • Я развертываю свои DB (Postgres), BE (Django) и FE (React) с помощью Skaffold
  • Примерно в 50% случаев BE раскручивается до DB
  • Одно из первых, что пытается сделать Django, - это подключиться к БД.
  • Он пытается только один раз (по задумке и не может быть изменен), если не может, он терпит неудачу и приложение не работает

  • Таким образом, мне нужно убедиться, что каждый раз, когда я развертываю свои развертывания, развертывание БД выполняется перед запуском развертывания BE.

Я наткнулся на датчики готовности, живучести и запуска. Я читал его пару раз, и тесты готовности звучат как то, что мне нужно: я не хочу, чтобы развертывание BE запускалось до тех пор, пока развертывание базы данных не будет готово принимать соединения.

Думаю, я не понимаю, как это настроить. Это то, что я пробовал, но до сих пор встречаю случаи, когда один загружается раньше другого.

postgres.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: postgres-deployment
spec:
  replicas: 1
  selector:
    matchLabels:
      component: postgres
  template:
    metadata:
      labels:
        component: postgres
    spec:
      containers:
        - name: postgres
          image: testappcontainers.azurecr.io/postgres
          ports:
            - containerPort: 5432
          env: 
            - name: POSTGRES_DB
              valueFrom:
                secretKeyRef:
                  name: testapp-secrets
                  key: PGDATABASE
            - name: POSTGRES_USER
              valueFrom:
                secretKeyRef:
                  name: testapp-secrets
                  key: PGUSER
            - name: POSTGRES_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: testapp-secrets
                  key: PGPASSWORD
            - name: POSTGRES_INITDB_ARGS
              value: "-A md5"
          volumeMounts:
            - name: postgres-storage
              mountPath: /var/lib/postgresql/data
              subPath: postgres
      volumes:
        - name: postgres-storage
          persistentVolumeClaim:
            claimName: postgres-storage
---
apiVersion: v1
kind: Service
metadata:
  name: postgres-cluster-ip-service
spec:
  type: ClusterIP
  selector:
    component: postgres
  ports:
    - port: 1423
      targetPort: 5432

api.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: api-deployment
spec:
  replicas: 3
  selector:
    matchLabels:
      component: api
  template:
    metadata:
      labels:
        component: api
    spec:
      containers:
        - name: api
          image: testappcontainers.azurecr.io/testapp-api
          ports:
            - containerPort: 5000
          env:
            - name: PGUSER
              valueFrom:
                secretKeyRef:
                  name: testapp-secrets
                  key: PGUSER
            - name: PGHOST
              value: postgres-cluster-ip-service
            - name: PGPORT
              value: "1423"
            - name: PGDATABASE
              valueFrom:
                secretKeyRef:
                  name: testapp-secrets
                  key: PGDATABASE
            - name: PGPASSWORD
              valueFrom:
                secretKeyRef:
                  name: testapp-secrets
                  key: PGPASSWORD
            - name: SECRET_KEY
              valueFrom:
                secretKeyRef:
                  name: testapp-secrets
                  key: SECRET_KEY
            - name: DEBUG
              valueFrom:
                secretKeyRef:
                  name: testapp-secrets
                  key: DEBUG
          readinessProbe:
            httpGet:
              host: postgres-cluster-ip-service
              port: 1423
            initialDelaySeconds: 10
            periodSeconds: 5
            timeoutSeconds: 2
---
apiVersion: v1
kind: Service
metadata:
  name: api-cluster-ip-service
spec:
  type: ClusterIP
  selector:
    component: api
  ports:
    - port: 5000
      targetPort: 5000

client.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: client-deployment
spec:
  replicas: 3
  selector:
    matchLabels:
      component: client
  template:
    metadata:
      labels:
        component: client
    spec:
      containers:
        - name: client
          image: testappcontainers.azurecr.io/testapp-client
          ports:
            - containerPort: 3000
          readinessProbe:
            httpGet:
              path: api-cluster-ip-service
              port: 5000
            initialDelaySeconds: 10
            periodSeconds: 5
            timeoutSeconds: 2
---
apiVersion: v1
kind: Service
metadata:
  name: client-cluster-ip-service
spec:
  type: ClusterIP
  selector:
    component: client
  ports:
    - port: 3000
      targetPort: 3000

Я не думаю ingress.yaml и skaffold.yaml будет полезно, но дайте мне знать, если я должен их добавить.

Так что я здесь делаю не так?


Редактировать:

Итак, я попробовал несколько вещей, основываясь на ответе Дэвида Мейза. Это помогло мне лучше понять, что происходит, но я все еще сталкиваюсь с проблемами, которые я не совсем понимаю, как решить.

Первая проблема в том, что даже со значением по умолчанию restartPolicy: Always, и даже несмотря на то, что Django терпит неудачу, сами модули не терпят неудачу. Стручки думают, что они совершенно здоровы, хотя Django потерпел неудачу.

Вторая проблема заключается в том, что, по-видимому, модули должны быть осведомлены о статусе Django. Это та часть, над которой я не совсем погружаюсь, особенно должны ли зонды проверять статус других развертываний или самих себя?

Вчера я думал о первом, но сегодня я думаю, что второе: Pod должен знать, что содержащаяся в нем программа потерпела неудачу. Однако все, что я пробовал, приводит к провалу проверки, отказу в соединении и т. Д.:

# referring to itself
host: /health
port: 5000

host: /healthz
port: 5000

host: /api
port: 5000

host: /
port: 5000

host: /api-cluster-ip-service
port: 5000

host: /api-deployment
port: 5000

# referring to the DB deployment
host: /health
port: 1423 #or 5432

host: /healthz
port: 1423 #or 5432

host: /api
port: 1423 #or 5432

host: /
port: 1423 #or 5432

host: /postgres-cluster-ip-service
port: 1423 #or 5432

host: /postgres-deployment
port: 1423 #or 5432

Очевидно, я неправильно настраиваю зонд, несмотря на то, что это "сверхлегкая" реализация (как ее описали в нескольких блогах). Например,/health а также /healthzмаршруты: они встроены в Kubernetes или их нужно настраивать? Перечитываем документы, чтобы, надеюсь, прояснить это.

2 ответа

Решение

На самом деле, думаю, я мог бы разобраться в этом.

Отчасти проблема в том, что хотя restartPolicy: Always по умолчанию, модули не знают, что Django потерпел неудачу, поэтому они думают, что они исправны.

Мое мнение было неправильным, поскольку я изначально предполагал, что мне нужно обратиться к развертыванию БД, чтобы увидеть, началось ли оно перед запуском развертывания API. Вместо этого мне нужно было проверить, не сработал ли Django, и повторно развернуть его, если это так.

Для меня это было сделано следующим образом:

livenessProbe:
  tcpSocket:
    port: 5000
  initialDelaySeconds: 2
  periodSeconds: 2
readinessProbe:
  tcpSocket:
    port: 5000
  initialDelaySeconds: 2
  periodSeconds: 2

Я изучаю Kubernetes, поэтому поправьте меня, если есть лучший способ сделать это или это просто неправильно. Я просто знаю, что он выполняет то, что я хочу.

Вы просто не ждете достаточно долго.

Артефакты развертывания, которые вы здесь показываете, выглядят вполне нормально. Даже если ваше приложение не может достичь базы данных, например, потому, что оно еще не запущено, это совершенно нормально. Однако у каждого модуля есть политика перезапуска, которая по умолчаниюAlways. Таким образом, когда модуль выходит из строя, Kubernetes перезапускает его; и когда он снова выйдет из строя, он будет снова запущен; и когда он продолжает выходить из строя, Kubernetes будет делать паузу на десятки секунд между перезапусками (ужасныйCrashLoopBackOff государство).

В конце концов, если вы находитесь в этом цикле ожидания и перезапуска, база данных действительно появится, а затем Kubernetes перезапустит ваши модули приложений, после чего приложение запустится нормально.

Единственное, что я бы здесь изменил, это то, что ваши зонды готовности для двух модулей должны проверять сами службы, а не какую-либо другую службу. Вы, наверное, хотитеpath быть чем-то вроде / или /healthzили что-то еще, что является фактическим путем HTTP-запроса в службе. Это может вернуть 503 Service Unavailable, если обнаружит, что его зависимость недоступна, или вы можете просто дать сбой. Просто сбой - это нормально.

Это совершенно нормальная установка в Kubernetes; Невозможно более прямо сказать, что модуль A не может запуститься, пока служба B не будет готова. Обратной стороной этого является то, что шаблон на самом деле довольно общий: если ваше приложение вылетает и перезапускается всякий раз, когда не может получить доступ к своей базе данных, не имеет значения, размещена ли база данных вне кластера, или если она выйдет из строя через некоторое время. время запуска; та же логика попытается перезапустить ваше приложение, пока оно снова не заработает.

Другие вопросы по тегам