Возможны ли непрерывные обновления на GKE с externalTrafficPolicy: Local?

Имею кластер GKE (1.12.10-гке.17).

Я использую nginx-ingress-controller с type: LoadBalancer.

Я установил externalTrafficPolicy: Local на сохранить исходный ip.

Все отлично работает, кроме периодических обновлений. У меня maxSurge: 1 и maxUnavailable: 0.

Моя проблема в том, что во время непрерывного обновления я начинаю получать тайм-ауты запросов. Я подозреваю, что балансировщик нагрузки Google по-прежнему отправляет запросы на узел, на котором находится модуль Terminating, даже несмотря на то, что проверки работоспособности не работают. Это происходит примерно 30-60 секунд, начиная с момента изменения модуля с Running на Terminating. Через некоторое время все стабилизируется, и в конечном итоге трафик идет только на новый узел с новым модулем.

Если балансировщик нагрузки медленно прекращает отправку запросов к завершающему модулю, есть ли способ сделать эти непрерывные развертывания беспроблемными?


Насколько я понимаю, в нормальном сервисе k8s, где externalTrafficPolicy не является нормальным, балансировщик нагрузки Google просто отправляет запросы всем узлам и позволяет iptables разбираться с этим. Когда pod Terminating, iptables обновляются быстро, и трафик на этот pod больше не отправляется. В случае, когда externalTrafficPolicy равно Local, однако, если узел, который получает запрос, не имеет модуля Running, то время ожидания запроса истекает, что и происходит здесь.

Если это правильно, то я вижу только два варианта

  1. прекратить отправку запросов на узел с Terminating pod
  2. продолжить обслуживание запросов, даже если модуль Terminating

Мне кажется, что вариант 1 сложен, поскольку он требует информирования балансировщика нагрузки о том, что модуль собирается начать Terminating.

Я добился некоторого прогресса по варианту 2, но пока он не работает. Мне удалось продолжить обслуживание запросов из модуля, добавив хук жизненного цикла preStop, который просто запускает sleep 60, но я думаю, что проблема в том, что healthCheckNodePort сообщает localEndpoints: 0, и я подозреваю, что что-то блокирует запрос между прибытием на узел и получением стручок Возможно, iptables не выполняет маршрутизацию, когда localEndpoints: 0.

Я также скорректировал проверку работоспособности балансировщика нагрузки Google, которая отличается от readinessProbe и livenessProbe, на "самые быстрые" возможные настройки, например Интервал 1 с, порог сбоя 1, и я убедился, что серверная часть балансировщика нагрузки, также известная как узел k8s, действительно быстро не проходит проверки работоспособности, но все равно продолжает отправлять запросы к завершающему модулю.


person Jesse Shieh    schedule 07.02.2020    source источник
comment
Настроили ли вы ресурс Ingress для использования контроллера входящего трафика NGINX? добавив аннотации. Это может определить, какой контроллер использовать для обслуживания трафика. Возможно, вам потребуется добавить свой входящий yaml-файл. аннотации: kubernetes.io/ingress.class: nginx   -  person Alioua    schedule 08.02.2020
comment
Да, на самом деле все работает нормально, кроме непрерывного обновления. Последовательное обновление относится к одному и тому же входному контроллеру nginx, поэтому, несмотря на то, что в данный момент работают два модуля, они находятся в одном развертывании и поэтому имеют один и тот же класс входящего трафика.   -  person Jesse Shieh    schedule 08.02.2020


Ответы (1)


Аналогичное обсуждение здесь.. Хотя это не идентично, это похожий вариант использования.

Похоже, все работает как положено.

  • LoadBalancer будет отправлять трафик на любой исправный узел на основе проверки работоспособности LoadBalancer. LoadBalancer не знает об отдельных модулях.

  • Проверка работоспособности помечает узел как неработоспособный после превышения порога проверки работоспособности, т.е. HC отправляется каждые x секунд с x задержкой тайм-аута, x количеством неудачных запросов. Это вызывает задержку между моментом, когда модуль переходит в завершение, и помечается как неисправный.

  • Также обратите внимание, что как только модуль помечается как notReady, модуль удаляется из конечной точки службы. Если на узле нет другого модуля, трафик будет продолжать достигать этого узла (из-за поведения HC, описанного выше), запросы не могут быть перенаправлены из-за externalTrafficPolicy (трафик остается на узле, куда он был отправлен).

Есть несколько способов решить эту проблему.

  1. Чтобы свести к минимуму промежуток времени между завершенным модулем и отметкой узла как неработоспособный, вы можете установить более агрессивную проверку работоспособности. Проблема заключается в том, что слишком чувствительный HC может вызывать ложные срабатывания, обычно увеличивает накладные расходы на узле (дополнительные запросы проверки работоспособности) и не устраняет полностью неудачные запросы.

  2. У вас должно быть достаточно запущенных модулей, чтобы на каждый узел всегда приходилось не менее 2 модулей. Поскольку служба удаляет модуль из конечной точки, как только он переходит в notReady, вместо этого запросы будут отправляться только в работающий модуль. Обратной стороной здесь является то, что у вас будут либо дополнительные накладные расходы (больше подов), либо более плотная группировка (более уязвимая к сбоям). Это также не устранит полностью неудавшиеся запросы, но их будет невероятно мало.

  3. Настройте HC и ваш контейнер для совместной работы: 3a. Конечная точка HC должна быть отделена от обычного пути, который вы используете. 3b. Настройте контейнер readinessProbe в соответствии с основным путем, по которому ваш контейнер обслуживает трафик (он будет отличаться от пути LB HC) 3c. Настройте свой образ так, чтобы при получении SIGTERM первым делом переходил по пути HC. 3d. Сконфигурируйте образ так, чтобы он плавно истощал все соединения после получения SIGTERM, вместо того, чтобы немедленно закрывать все сеансы и соединения.

Это должно означать, что текущие сеансы будут корректно завершены, что уменьшит количество ошибок. Это также должно означать, что узел начнет отказывать зонды HC, даже если он готов обслуживать нормальный трафик, это дает время для узла, который будет помечен как неисправный, и LB перестанет отправлять ему трафик, прежде чем он больше не сможет обслуживать Запросы.

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

person Patrick W    schedule 08.02.2020
comment
Большое спасибо за вдумчивый ответ! Мне нравятся варианты 1 и 2, но, как вы сказали, они не совсем безнадежные. На самом деле healthCheckNodePort отделен от обычного пути, который отключается, как только модуль переходит в завершение, а ловушка preStop запускается на SIGTERM и хорошо истощает текущие сеансы. Проблема в том, что трафик по какой-то причине больше не достигает модуля. Я предполагаю, что это связано с тем, что после сбоя проверки работоспособности iptables или что-то еще больше не направляет трафик в модуль, даже если он поступает на узел. Знаете ли вы, правда ли это, и если да, то как это обойти? - person Jesse Shieh; 09.02.2020
comment
Как только модуль завершается, прокси-сервер kube удалил модуль из iptables, поэтому lb HC должен выйти из строя, прежде чем он перейдет в завершение, я считаю, что это можно сделать через жизненный цикл модуля, но мне нужно проверить - person Patrick W; 09.02.2020
comment
Контейнер завершит обработчик предварительной остановки перед тем, как перейдет в состояние завершения.. Можете ли вы настроить крюк предварительного останова так, чтобы он полностью слил воду и подождал, пока HC выйдет из строя? - person Patrick W; 09.02.2020
comment
Извините, я делаю различие между прекращением и прекращением. Вы правы в том, что хуки preStop завершаются до того, как модуль завершается, но я думаю, что он переходит в завершение, когда запускается ловушка preStop. Возможно, завершение - это состояние, о котором сообщает только kubectl, что, я думаю, является функцией удаленияTimestamp, но, похоже, совпадает с тем, когда localEndpoints становится 0 и трафик перестает доходить до модуля. - person Jesse Shieh; 09.02.2020
comment
Думаю, вы попали в предыдущий комментарий, который я пропустил до сих пор. По сути, нам нужен способ, чтобы проверка работоспособности балансировщика нагрузки завершилась ошибкой до того, как модуль перейдет в завершение. Я не нашел способа сделать это. Альтернатива - запретить iptables удалить модуль во время его завершения. Я тоже не нашел способа сделать это. - person Jesse Shieh; 09.02.2020