RollingUpdate на kubernetes не предотвращает время ожидания шлюза
Я следил за блогом http://rahmonov.me/posts/zero-downtime-deployment-with-kubernetes/ и создал два образа докера с index.html, возвращающим "версию 1 приложения" и "версию 2 приложения", Чего я хочу добиться, так это нулевого времени простоя. я использую
kubectl apply -f mydeployment.yaml
с image: mynamespace/nodowntime-test:v1
внутри.
развернуть версию v1 на k8s и затем запустить:
while True
do
printf "\n---------------------------------------------\n"
curl "http://myhosthere"
sleep 1s
done
Пока все работает. Через короткое время curl возвращает "Версия 1 приложения". Затем я применяю тот же самый файл развертывания k8s с image: mynamespace/nodowntime-test:v2
, И хорошо, это работает, но есть один (всегда один) ответ Gateway Timeout между v1 и v2. Так что на самом деле это не просто выпуск релиза;) Это намного лучше, чем без RollingUpdate, но не идеально.
я использую RollingUpdate
стратегия и readinessProbe:
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: nodowntime-deployment
spec:
replicas: 1
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 0
maxSurge: 1
selector:
matchLabels:
app: nodowntime-test
template:
metadata:
labels:
app: nodowntime-test
spec:
containers:
...
readinessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 5
periodSeconds: 5
successThreshold: 5
Могу ли я сделать это лучше? Это какая-то проблема с синхронизацией всего этого с входным контроллером? Я знаю, что могу настроить его, используя minReadySeconds
такие старые и новые стручки перекрываются в течение некоторого времени, но единственное ли это решение?
1 ответ
Я воссоздал упомянутый эксперимент и изменил число запросов примерно до 30 в секунду, запустив три одновременных процесса:
While True
do
curl -s https://<NodeIP>:<NodePort>/ -m 0.1 --connect-timeout 0.1 | grep Version || echo "fail"
done
После редактирования развертывания и изменения версии образа несколько раз, в процессе перехода не было потери пакетов. Я даже поймал короткий момент подачи запросов обоими изображениями одновременно.
Version 1 of my awesome app! Money is pouring in!
Version 1 of my awesome app! Money is pouring in!
Version 1 of my awesome app! Money is pouring in!
Version 2 of my awesome app! More Money is pouring in!
Version 1 of my awesome app! Money is pouring in!
Version 1 of my awesome app! Money is pouring in!
Version 2 of my awesome app! More Money is pouring in!
Version 2 of my awesome app! More Money is pouring in!
Version 2 of my awesome app! More Money is pouring in!
Поэтому, если вы отправите запрос в сервис напрямую, он будет работать как положено.
"Тайм-аут шлюза" является ответом от прокси-сервера Traefik. Он открывает TCP-соединение для бэкэнда через набор правил iptables.
Когда вы выполняете RollingUpdates, правила iptables изменились, но Traefic этого не знает, поэтому соединение все еще считается открытым с точки зрения Traefik. И после первой неудачной попытки пройти через несуществующее правило iptables, Traefik сообщает "Время ожидания шлюза" и закрывает соединение tcp. При следующей попытке он открывает новое соединение с бэкендом через новое правило iptables, и все снова идет хорошо.
Это можно исправить, включив повторные попытки в Traefik.
# Enable retry sending request if network error
[retry]
# Number of attempts
#
# Optional
# Default: (number servers in backend) -1
#
# attempts = 3
Обновить:
наконец, мы обошли его без использования функции "повторных попыток" traefik, которая потенциально может нуждаться в идемпотентной обработке для всех сервисов (что в любом случае хорошо, но мы не могли позволить себе заставить все проекты делать это). Что вам нужно, так это стратегия kubernetes RollingUpdate + ReadinessProbe, настроенная и корректное отключение, реализованное в вашем приложении.