К Load Balancers в системах оркестрации (Kubernetes, Nomad и других) предъявляется больше требований, чем просто балансировка нагрузки. Во-первых, Load Balancer должен уметь читать каталог со списком сервисов, на которые необходимо перенаправлять трафик (или, как вариант, давать возможность сервисам регистрироваться на включение их в трафик). Во-вторых, делать это динамически, т.к. системы оркестрации в любой момент могут увеличить или уменьшить количество реплик сервисов, или переместить их на другие адреса в сети. И, в-третьих, делать это без остановки трафика.
В сегодняшнем сообщении я опишу работу с двумя Load Balancers — Traefik и HAProxy. Эти Load Balancers имеют возможность работать с внушительным списком средств оркестрации. В примерах будет описана работа с системой оркестрации Nomad.
В прошлом сообщении я уже приводил пример Load Balancers — Fabio. Его ограничения: работает только с http/https протоколами, и работает только с Consul. В отличие от Fabio, Load Balancers Traefik работает с впечатляющим количеством различных систем. Вот их неполный список, взятый с сайта разработчика: Docker, Swarm mode, Kubernetes, Marathon, Consul, Etcd, Rancher, Amazon ECS,…
Я продолжу пример из предыдущего сообщения, в котором создавалось несколько реплик сервиса django.
Traefik можно загрузить с сайта разработчика в виде исполняемого файла для наиболее распространенных операционных систем. Для интеграции с Nomad (собственно с Consul) необходимо создать файл конфигурации:
И далее запустить на выполнение команду с приведенным файлом конфигурации:
После этого на порте 8080 будет доступен UI Traefik, в котором пока не опубликован ни один сервис. Для публикации сервисов существует несколько способов, которые в конечном счете делают одно и тоже — загружают в систему Traefik данные типа ключ/значение. Мы воспользуемся возможностью задавать пары ключ/значение через tags сервисов. Дополним конфигурационный файл сервиса django параметром tags:
В данном примере сервис будет опубликован на хосте localhost и примонтирован к роуту /test. В Traefik разработана гибкая и полная система правил для конфигурирования роутов, включая работу с регулярными выражениями. Перечень параметров для правил в документации разработчика.
После выполнения команды
Недостатком Traefik является то что он работает с протоколами семейства http/https (на всякий случай замечу что это семейство включает и веб-сокеты). Но все же есть такая вероятность, что возникнет необходимость работать и с другими протоколами. Поэтому перейдем к следующему более широкому решению на основе HAProxy. Какое-то время назад у HAProxy были проблемы с «мягкой» перегрузкой, что делало его использование с системами оркестрации сложным (на время рестарта приходилось на сетевом уровне приостанавливать движение пакетов). Сейчас это уже не проблема.
Для начала необходимо установить haproxy на компьютер. Здесь не подойдет вариант с установкой внутри контейнера. В haproxy только недавно появилась возможность рестартовать процесс в «мягком» режиме, но при этом все равно контейнер докер останавливается, так как фактически запускается второй процесс с haproxy, просто их смена проходит в режиме ожидания — что не работает с докером и его принципом «один-контейнер-один процесс».
Для работы haproxy необходимо иметь файл конфигурации, в котором прописаны необходимые правила. В Nomad (собственно в Consul) применяется система шаблонов, которая может генерировать конфигурации:
Ключевое слово
Для запуска процесса генерации по шаблону «на лету» применяется библиотека https://github.com/hashicorp/consul-template. С ресурса разработчика можно загрузить исполняемый файл для всех распространенных операционных систем, и запускать процесс от имени не привилегированного пользователя командой:
Параметр
После запуска шаблонизатора, который сгенерирует первую конфигурацию можно запускать haproxy:
Мы явно указываем pid-файл, для того чтобы иметь возможность отправить сигнал на «мягкую» перегрузку haproxy:
В данном примере сервис опубликован на порту 5001. На этом же порту можно просмотреть статистику самого haproxy по адресу
UPDATED 24.02.2019 22:43
По комментарию @usego было проведено дополнительное уточнение работы haproxy в контейнере докер, в частности по фрагменту из документации github.com/neo4j/docker-library-docs/tree/master/haproxy#reloading-config
При таком подходе действительно происходит перезагрузка конфигурации, но в результате прерывания текущего процесса. А это означает что сервисы будут иметь хотя и очень незначительный, но все же период недоступности и часть клиентов может наблюдать сообщение об ошибке. Но иногда это не является главным критерием выбора. Поэтому приведу в дополнение конфигурацию docker-compose.yml для запуска haproxy в докере:
Также изменится команда, которая будет перегружать конфигурацию haproxy:
К преимуществам такой реализации следует отнести возможность работать без инсталляции haproxy.
Код примеров доступен в репозитарии
Полезные ссылки:
1. www.haproxy.com/blog/haproxy-and-consul-with-dns-for-service-discovery
2. m.mattmclaugh.com/traefik-and-consul-catalog-example-2c33fc1480c0
3. www.hashicorp.com/blog/load-balancing-strategies-for-consul
apapacy@gmail.com
24 февраля 2019 года
В сегодняшнем сообщении я опишу работу с двумя Load Balancers — Traefik и HAProxy. Эти Load Balancers имеют возможность работать с внушительным списком средств оркестрации. В примерах будет описана работа с системой оркестрации Nomad.
В прошлом сообщении я уже приводил пример Load Balancers — Fabio. Его ограничения: работает только с http/https протоколами, и работает только с Consul. В отличие от Fabio, Load Balancers Traefik работает с впечатляющим количеством различных систем. Вот их неполный список, взятый с сайта разработчика: Docker, Swarm mode, Kubernetes, Marathon, Consul, Etcd, Rancher, Amazon ECS,…
Я продолжу пример из предыдущего сообщения, в котором создавалось несколько реплик сервиса django.
Traefik можно загрузить с сайта разработчика в виде исполняемого файла для наиболее распространенных операционных систем. Для интеграции с Nomad (собственно с Consul) необходимо создать файл конфигурации:
[entryPoints]
[entryPoints.http]
address = ":5001"
[web]
address = ":8080"
[consulCatalog]
endpoint = "127.0.0.1:8500"
domain = "consul.localhost"
exposedByDefault = false
prefix = "traefik"
И далее запустить на выполнение команду с приведенным файлом конфигурации:
traefik -c nomad/traefik.toml
После этого на порте 8080 будет доступен UI Traefik, в котором пока не опубликован ни один сервис. Для публикации сервисов существует несколько способов, которые в конечном счете делают одно и тоже — загружают в систему Traefik данные типа ключ/значение. Мы воспользуемся возможностью задавать пары ключ/значение через tags сервисов. Дополним конфигурационный файл сервиса django параметром tags:
job "django-job" {
datacenters = ["dc1"]
type = "service"
group "django-group" {
count = 3
restart {
attempts = 2
interval = "30m"
delay = "15s"
mode = "fail"
}
ephemeral_disk {
size = 300
}
task "django-job" {
driver = "docker"
config {
image = "apapacy/tut-django:1.0.1"
port_map {
lb = 8000
}
}
resources {
network {
mbits = 10
port "lb" {}
}
}
service {
name = "django"
tags = [
"traefik.enable=true",
"traefik.frontend.entryPoints=http",
"traefik.frontend.rule=Host:localhost;PathStrip:/test",
"traefik.tags=exposed"
]
port = "lb"
check {
name = "alive"
type = "http"
path = "/"
interval = "10s"
timeout = "2s"
}
}
}
}
}
В данном примере сервис будет опубликован на хосте localhost и примонтирован к роуту /test. В Traefik разработана гибкая и полная система правил для конфигурирования роутов, включая работу с регулярными выражениями. Перечень параметров для правил в документации разработчика.
После выполнения команды
nomad job run nomad/django.conf
правила применятся, и на сервис будет направлен трафик с Load Balancer. Соответственно, можно менять эти параметры, деплоить новый вариант сервиса командой nomad job run nomad/django.conf
, и все изменения применятся без досадной остановки трафика.Недостатком Traefik является то что он работает с протоколами семейства http/https (на всякий случай замечу что это семейство включает и веб-сокеты). Но все же есть такая вероятность, что возникнет необходимость работать и с другими протоколами. Поэтому перейдем к следующему более широкому решению на основе HAProxy. Какое-то время назад у HAProxy были проблемы с «мягкой» перегрузкой, что делало его использование с системами оркестрации сложным (на время рестарта приходилось на сетевом уровне приостанавливать движение пакетов). Сейчас это уже не проблема.
Для начала необходимо установить haproxy на компьютер. Здесь не подойдет вариант с установкой внутри контейнера. В haproxy только недавно появилась возможность рестартовать процесс в «мягком» режиме, но при этом все равно контейнер докер останавливается, так как фактически запускается второй процесс с haproxy, просто их смена проходит в режиме ожидания — что не работает с докером и его принципом «один-контейнер-один процесс».
Для работы haproxy необходимо иметь файл конфигурации, в котором прописаны необходимые правила. В Nomad (собственно в Consul) применяется система шаблонов, которая может генерировать конфигурации:
global
debug
defaults
log global
mode http
option httplog
option dontlognull
timeout connect 5000
timeout client 50000
timeout server 50000
frontend http_front
bind *:5001
stats uri /haproxy?stats
default_backend http_back
backend http_back
balance roundrobin{{range service "django"}}
server {{.Node}} {{.Address}}:{{.Port}} check{{end}}
Ключевое слово
range
в данном случае выполняет роль итератора. Для трех сервисов «django» будет сформирован такой файл конфигурации:global
debug
defaults
log global
mode http
option httplog
option dontlognull
timeout connect 5000
timeout client 50000
timeout server 50000
frontend http_front
bind *:5001
stats uri /haproxy?stats
default_backend http_back
backend http_back
balance roundrobin
server 228.195.86.224 127.0.0.1:21469 check
server 228.195.86.224 127.0.0.1:25872 check
server 228.195.86.224 127.0.0.1:25865 check
Для запуска процесса генерации по шаблону «на лету» применяется библиотека https://github.com/hashicorp/consul-template. С ресурса разработчика можно загрузить исполняемый файл для всех распространенных операционных систем, и запускать процесс от имени не привилегированного пользователя командой:
consul-template -template="haproxy/haproxy.cfg.tmpl:haproxy/haproxy.cfg:./haproxy/haproxy.reload.sh"
Параметр
-template
содержит разделенные двоеточием параметры 1) имя шаблона, 2) имя получаемого файла конфигурации 3) команда, которая выполняется после генерации файла. Файл будет автоматически генерироваться если будут изменены переменные входящие в шаблон (например изменено количество реплик сервиса django).После запуска шаблонизатора, который сгенерирует первую конфигурацию можно запускать haproxy:
haproxy -D -f haproxy/haproxy.cfg -p `pwd`/haproxy.pid
Мы явно указываем pid-файл, для того чтобы иметь возможность отправить сигнал на «мягкую» перегрузку haproxy:
haproxy -D -f ./haproxy/haproxy.cfg -p `pwd`/haproxy.pid -sf $(cat `pwd`/haproxy.pid)
В данном примере сервис опубликован на порту 5001. На этом же порту можно просмотреть статистику самого haproxy по адресу
/haproxy?stats
.UPDATED 24.02.2019 22:43
По комментарию @usego было проведено дополнительное уточнение работы haproxy в контейнере докер, в частности по фрагменту из документации github.com/neo4j/docker-library-docs/tree/master/haproxy#reloading-config
Reloading config
If you used a bind mount for the config and have edited your haproxy.cfg file, you can use HAProxy's graceful reload feature by sending a SIGHUP to the container:
$ docker kill -s HUP my-running-haproxy
The entrypoint script in the image checks for running the command haproxy and replaces it with haproxy-systemd-wrapper from HAProxy upstream which takes care of signal handling to do the graceful reload. Under the hood this uses the -sf option of haproxy so «there are two small windows of a few milliseconds each where it is possible that a few connection failures will be noticed during high loads» (see Stopping and restarting HAProxy).
При таком подходе действительно происходит перезагрузка конфигурации, но в результате прерывания текущего процесса. А это означает что сервисы будут иметь хотя и очень незначительный, но все же период недоступности и часть клиентов может наблюдать сообщение об ошибке. Но иногда это не является главным критерием выбора. Поэтому приведу в дополнение конфигурацию docker-compose.yml для запуска haproxy в докере:
version: '3'
services:
haproxy_lb:
image: haproxy
volumes:
- ./haproxy:/usr/local/etc/haproxy
network_mode: host
Также изменится команда, которая будет перегружать конфигурацию haproxy:
consul-template -template="haproxy/haproxy.cfg.tmpl:haproxy/haproxy.cfg:docker kill -s HUP $(docker-compose ps -q haproxy_lb)"
К преимуществам такой реализации следует отнести возможность работать без инсталляции haproxy.
Код примеров доступен в репозитарии
Полезные ссылки:
1. www.haproxy.com/blog/haproxy-and-consul-with-dns-for-service-discovery
2. m.mattmclaugh.com/traefik-and-consul-catalog-example-2c33fc1480c0
3. www.hashicorp.com/blog/load-balancing-strategies-for-consul
apapacy@gmail.com
24 февраля 2019 года