Поддельная проверка живучести / готовности в kubernetes

#kubernetes

#kubernetes

Вопрос:

Можно ли подделать контейнер, чтобы он всегда был готов / функционировал в kubernetes, чтобы kubernetes думал, что контейнер активен, и не пытался уничтожить / воссоздать контейнер заново? Я ищу быстрое и хакерское решение, желательно.

Комментарии:

1. да, просто настройте эти тесты так, чтобы они всегда возвращали работоспособность, например, HttpGet, который всегда возвращает 200

2. У меня нет конечной точки http, которая всегда возвращает 200, и я не хочу добавлять ее прямо сейчас.

3. Итак, что вы хотите сделать? вы хотите подделать его, ничего не делая?

4. Да, @IjazAhmadKhan. Что-нибудь быстрое и взломанное

Ответ №1:

Контроллеры k8s не требуют проверки работоспособности и готовности, вы можете просто удалить их, и ваши контейнеры всегда будут работать / готовы.

Если вам все равно нужен хакерский подход, используйте exec тест (вместо httpGet ) с чем-то фиктивным, что всегда возвращается 0 в качестве кода выхода. Например:

 apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  labels:
    app: nginx
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.7.9
        ports:
        - containerPort: 80
        livenessProbe:
          exec:
            command:
            - touch
            - /tmp/healthy
        readinessProbe:
          exec:
            command:
            - touch
            - /tmp/healthy
  

Ответ №2:

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

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

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

Сценарий 1:
У вас есть развертывание с 1 репликой, но вы замечаете, что всякий раз, когда вы переходите к обновлению своего приложения (запускаете новую версию с помощью текущего обновления), ваша платформа мониторинга периодически сообщает об ошибках 400, 500 и таймаута во время текущего обновления. После обновления вы переходите к 1 реплике, и ошибки исчезают.

Сценарий 2:
У вас достаточно трафика, чтобы гарантировать автоматическое масштабирование и несколько реплик. Вы постоянно получаете 1-3% ошибок и 97% успеха.

Почему вы получаете ошибки в обоих сценариях?
Допустим, требуется 1 минута, чтобы завершить загрузку / быть готовым к приему трафика. Если у вас нет проверок готовности, то вновь созданные экземпляры вашего контейнера будут получать трафик до того, как они завершат загрузку / станут готовыми к приему трафика. Таким образом, вновь созданные экземпляры, вероятно, вызывают временные ошибки 400, 500 и тайм-аут.

Как исправить:
Вы можете исправить случайные ошибки в сценариях 1 и 2, добавив проверку готовности с initialDelaySeconds (или startup probe), в основном то, что достаточно долго ожидает завершения загрузки вашего контейнерного приложения.

Теперь правильная и рекомендуемая практика, которую нужно сделать, — это написать конечную точку / health, которая должным образом отражает работоспособность вашего приложения. Но написание точной конечной точки проверки работоспособности может занять время. Во многих случаях вы можете получить тот же конечный результат (устранить ошибки), не прилагая усилий для создания конечной точки / health путем ее подделки и просто добавляя период ожидания, который ожидает завершения загрузки вашего приложения перед отправкой на него трафика. (опять же / работоспособность — лучшая практика, но ни у кого нет времени на эту толпу, подделка может быть достаточно хорошим решением для остановки)

Ниже приведена улучшенная версия поддельного теста готовности:
Также вот почему это лучше

  1. тесты живучести на основе exec не работают в 100% случаев, они предполагают, что shell существует в контейнере и что команды существуют в контейнере. Существуют сценарии, в которых в защищенных контейнерах отсутствуют такие элементы, как оболочка или сенсорная команда.
  2. Проверки живучести HttpGet, TCPSocket и grcp выполняются с точки зрения узла, на котором запущен kubelet (агент kubernetes), поэтому они не зависят от программного обеспечения, установленного в контейнере, и должны работать в защищенных контейнерах, в которых отсутствуют такие элементы, как сенсорная команда или даже контейнер для царапин. (Другими словами, этот soln должен работать в 100% случаев против 99% случаев)
  3. Альтернативой проверке при запуске является использование initialDelaySeconds с проверкой готовности, но это создает ненужный трафик по сравнению с проверкой при запуске, которая выполняется один раз. (Опять же, это не лучшее решение с точки зрения точности / максимально быстрого времени запуска, но часто достаточно хорошее решение, которое очень практично.)
  4. Запустите мой пример в кластере, и вы увидите, что он не готов в течение 60 секунд, затем становится готовым через 60 секунд.
  5. Поскольку это поддельный датчик, использовать датчик готовности / живучести бессмысленно, просто используйте startup probe, поскольку это сократит ненужный трафик.
  6. При отсутствии датчика готовности запускающий датчик будет иметь эффект датчика готовности (блокируйте его готовность до тех пор, пока датчик не пройдет, но только во время начального запуска)
 apiVersion: apps/v1
kind: Deployment
metadata:
  name: useful-hack
  labels:
    app: always-true-tcp-probe
spec:
  replicas: 1
  strategy: 
    type: Recreate #dev env fast feedback loop optimized value, don't use in prod
  selector:
    matchLabels:
      app: always-true-tcp-probe
  template:
    metadata:
      labels:
        app: always-true-tcp-probe
    spec:
      containers:
      - name: nginx
        image: nginx:1.7.9
        startupProbe:
          tcpSocket:
            host: 127.0.0.1  #Since kubelet does the probes, this is node's localhost, not pod's localhost
            port: 10250      #worker node kubelet listening port
          successThreshold: 1
          failureThreshold: 2
          initialDelaySeconds: 60 #wait 60 sec before starting the probe  
  

Дополнительные примечания:

  1. Приведенный выше пример сохраняет трафик внутри локальной сети, что имеет несколько преимуществ.
    • Это будет работать в средах, отключенных от Интернета.
    • Плата за выход из сети взиматься не будет
  2. Приведенный ниже пример будет работать только для сред, подключенных к Интернету, и не так уж плох для проверки при запуске, но был бы плохой идеей для проверки готовности / работоспособности, поскольку это может засорить пропускную способность NAT GW, я включаю его только для того, чтобы указать на кое-что интересное.
         startupProbe:
          httpGet:
            host: google.com  #default's to pod IP
            path: /
            port: 80
            scheme: HTTP
          successThreshold: 1
          failureThreshold: 2
          initialDelaySeconds: 60
---
        startupProbe:
          tcpSocket:
            host: 1.1.1.1  #CloudFlare
            port: 53       #DNS
          successThreshold: 1
          failureThreshold: 2
          initialDelaySeconds: 60
  

Интересный момент:
Помните, я сказал «Проверка работоспособности HttpGet, TCPSocket и grcp выполняется с точки зрения узла, на котором запущен kubelet (агент kubernetes)». Kubelet работает в операционной системе хоста рабочего узла, которая настроена для восходящего DNS, другими словами, у нее нет доступа к записям DNS внутреннего кластера, о которых известно kubedns. Таким образом, вы не можете указать имена служб Kubernetes в этих тестах.

Кроме того, служебные IP-адреса Kubernetes также не будут работать для тестов, поскольку они являются VIP (виртуальными IP-адресами), которые * существуют только в iptables (* в большинстве случаев).