nginx vs kubernetes (как внешний балансировщик) - не удается сбалансировать серверы API - PullRequest
0 голосов
/ 03 мая 2018

Мы пытаемся создать кластер HA Kubernetese с 3 основными узлами, каждый из которых имеет полный набор жизненно важных компонентов: ETCD + APIServer + Scheduller + ControllerManager и внешний балансировщик. Поскольку ETCD может создавать кластеры самостоятельно, мы работаем над созданием HA APIServers. То, что пару недель назад казалось очевидной задачей, теперь превратилось в «не беду» ...

Мы решили использовать nginx в качестве балансировщика для 3 независимых APIServers. Предполагается, что все остальные части нашего кластера, которые взаимодействуют с APIServer (Kublets, Kube-Proxys, Schedulers, ControllerManager ...), используют балансировщик для доступа к нему. Все прошло хорошо, прежде чем мы начали «деструктивные» тесты (как я это называю) с несколькими запущенными стручками. Вот часть конфигурации APIServer, которая набирает с HS:

.. --apiserver-count=3 --endpoint-reconciler-type=lease ..

Вот наш nginx.conf:

user                    nginx;

error_log               /var/log/nginx/error.log warn;
pid                     /var/run/nginx.pid;

worker_processes        auto;

events {
    multi_accept        on;
    use                 epoll;
    worker_connections  4096;
}

http {
    include             /etc/nginx/mime.types;
    default_type        application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                  '$status $body_bytes_sent "$http_referer" '
                  '"$http_user_agent" "$http_x_forwarded_for"';

    access_log          /var/log/nginx/access.log  main;

    sendfile            on;
    #tcp_nopush          on;
    tcp_nodelay         on;
    keepalive_timeout   65;
    types_hash_max_size 2048;

    gzip                on;

    underscores_in_headers on;

   include /etc/nginx/conf.d/*.conf;
}

И apiservers.conf:

upstream apiserver_https {
    least_conn;
    server core1.sbcloud:6443; # max_fails=3 fail_timeout=3s;
    server core2.sbcloud:6443; # max_fails=3 fail_timeout=3s;
    server core3.sbcloud:6443; # max_fails=3 fail_timeout=3s;
}

map $http_upgrade $connection_upgrade {
    default upgrade;
    '' close;
}

server {
    listen                      6443 ssl so_keepalive=1m:10s:3; # http2; 

    ssl_certificate             "/etc/nginx/certs/server.crt";
    ssl_certificate_key         "/etc/nginx/certs/server.key";

    expires                     -1;
    proxy_cache                 off;
    proxy_buffering             off;
    proxy_http_version          1.1;

    proxy_connect_timeout       3s;

    proxy_next_upstream         error timeout invalid_header http_502; # non_idempotent # http_500 http_503 http_504;
    #proxy_next_upstream_tries   3;
    #proxy_next_upstream_timeout 3s;
    proxy_send_timeout          30m;
    proxy_read_timeout          30m;
    reset_timedout_connection   on;


    location / {
        proxy_pass              https://apiserver_https;
        add_header              Cache-Control "no-cache";
        proxy_set_header        Upgrade $http_upgrade;
        proxy_set_header        Connection "upgrade";
        proxy_set_header        Host $http_host;
        proxy_set_header        Authorization $http_authorization;
        proxy_set_header        X-Real-IP $remote_addr;
        proxy_set_header        X-SSL-CLIENT-CERT $ssl_client_cert;
     }
}

После некоторых тестов выяснилось, что Kubernetes, похоже, использует одиночное долгоживущее соединение вместо традиционных сеансов открытого закрытия. Это, вероятно, роса для SSL. Таким образом, мы должны увеличить proxy_send_timeout и proxy_read_timeout до смешных 30 м (значение по умолчанию для APIServer - 1800 с). Если этот параметр меньше 10 м, то все клиенты (такие как Scheduler и ControllerManager) будут генерировать тонны, если INTERNAL_ERROR из-за прерванных потоков.

Итак, для краш-теста я просто положил один из серверов APIServer, аккуратно выключив его. Затем я перезагружаю другой, чтобы nginx увидел, что восходящий поток отключился, и переключил все текущие соединения на последнее. Через пару секунд перезапущенный APIserver возвращается обратно, и у нас работают 2 APIServer. Затем я отключил сеть на третьем сервере APIServer, запустив на этом сервере 'systemctl stop network', чтобы у него не было возможности сообщить Kubernetes или nginx, что он отключается.

Теперь кластер полностью разбит! Кажется, что nginx распознает, что восходящий поток вышел из строя, но он не сбросит и без того захватывающие соединения с мертвым восходящим потоком. Я все еще могу видеть их с помощью 'ss -tnp'. Если я перезапущу службы Kubernetes, они снова подключатся и продолжат работать, то же самое, если я перезапущу nginx - новые сокеты будут отображаться в выводе ss.

Это происходит, только если я делаю APIserver недоступным, отключая сеть (не позволяя ему закрыть существующие соединения с nginx и сообщая Kubernetes, что он отключается). Если я просто остановлю это - все работает как шарм. Но это не настоящий случай. Сервер может отключиться без предупреждения - просто мгновенно.

Что мы делаем не так? Есть ли способ заставить nginx разорвать все соединения с вышестоящим апстримом? Что-нибудь, что можно попробовать, прежде чем мы перейдем на HAProxy или LVS и разрушим неделю, чтобы пнуть nginx в наших попытках сбалансировать его, вместо того, чтобы сломать наш не очень HA-кластер.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...