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, настроенная и корректное отключение, реализованное в вашем приложении.

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