Привет, Хабр! Предлагаю вашему вниманию перевод поста: Миграция с Nginx на Envoy Proxy.
Envoy — это высокопроизводительный распределенный прокси-сервер (написанный на C++), предназначенный для отдельных сервисов и приложений, также это коммуникационная шина и «universal data plane», разработанный для больших микросервисных архитектур «service mesh». При его создании были учтены решения проблем, которые возникали при разработке таких серверов, как NGINX, HAProxy, аппаратных балансировщиков нагрузки и облачных балансировщиков нагрузки. Envoy работает вместе с каждым приложением и абстрагирует сеть, предоставляя общие функции независимо от платформы. Когда весь служебный трафик в инфраструктуре проходит через сетку Envoy, становится легко визуализировать проблемные области с помощью согласованной наблюдаемости, настройки общей производительности и добавления основных функций в определённом месте.
Возможности
- Архитектура вне процесса: envoy — это автономный, высокопроизводительный сервер занимающий небольшой объем оперативной памяти. Он работает совместно с любым языком приложения или фреймворком.
- Поддержка http/2 и grpc: envoy имеет первоклассную поддержку http/2 и grpc для входящих и исходящих соединений. Это прозрачный прокси от http/1.1 до http/2.
- Расширенная балансировка нагрузки: envoy поддерживает расширенные функции балансировки нагрузки, включая автоматические повторные попытки, разрыв цепи, глобальное ограничение скорости, затенение запросов, локальную балансировку нагрузки зоны и т. д.
- API для управления конфигурацией: envoy предоставляет надежный API для динамического управления своей конфигурацией.
- Наблюдаемость: глубокая наблюдаемость трафика L7, встроенная поддержка распределенной трассировки и наблюдаемость mongodb, dynamodb и многих других приложений.
Шаг 1 — Пример конфига NGINX
В этом сценарии используется специально созданный файл nginx.conf, основанный на полном примере из NGINX Wiki. Вы можете просмотреть конфигурацию в редакторе, открыв nginx.conf
Исходный конфиг nginx
user www www;
pid /var/run/nginx.pid;
worker_processes 2;
events {
worker_connections 2000;
}
http {
gzip on;
gzip_min_length 1100;
gzip_buffers 4 8k;
gzip_types text/plain;
log_format main '$remote_addr - $remote_user [$time_local] '
'"$request" $status $bytes_sent '
'"$http_referer" "$http_user_agent" '
'"$gzip_ratio"';
log_format download '$remote_addr - $remote_user [$time_local] '
'"$request" $status $bytes_sent '
'"$http_referer" "$http_user_agent" '
'"$http_range" "$sent_http_content_range"';
upstream targetCluster {
172.18.0.3:80;
172.18.0.4:80;
}
server {
listen 8080;
server_name one.example.com www.one.example.com;
access_log /var/log/nginx.access_log main;
error_log /var/log/nginx.error_log info;
location / {
proxy_pass http://targetCluster/;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
}
Конфигурации NGINX обычно имеют три ключевых элемента:
- Настройка сервера NGINX, структуры журналов и функциональности Gzip. Это определяется глобально во всех случаях.
- Настройка NGINX для приема запросов на хост one.example.com на порту 8080.
- Настройка целевого местоположения, как обрабатывать трафик для разных частей URL.
Не вся конфигурация будет применяться к Envoy Proxy, и вам не нужно настраивать некоторые параметры. Envoy Proxy имеет четыре ключевых типа, которые поддерживают базовую инфраструктуру, предлагаемую NGINX. Ядро это:
- Слушатели: Они определяют, как Envoy Proxy принимает входящие запросы. В настоящее время Envoy Proxy поддерживает только слушателей на основе TCP. Как только соединение установлено, оно передается на набор фильтров для обработки.
- Фильтры: Они являются частью конвейерной архитектуры, которая может обрабатывать входящие и исходящие данные. Данная функциональность включает фильтры, такие как Gzip, который сжимает данные перед отправкой их клиенту.
- Маршрутизаторы: Они перенаправляют трафик в требуемый пункт назначения, определенный как кластер.
- Кластеры: Они определяют конечную точку для трафика и параметры конфигурации.
Мы будем использовать эти четыре компонента для создания конфигурации Envoy Proxy чтобы соответстветствовать определенной конфигурации NGINX. Цель Envoy работа с API и динамическая конфигурация. В этом случае базовая конфигурация будет использовать статические, жестко заданные параметры из NGINX.
Шаг 2 — Конфигурация NGINX
Первая часть nginx.conf определяет некоторые внутренние компоненты NGINX, которые должны быть настроены.
Worker Connections (Рабочие соединения)
Приведенная ниже конфигурация определяет количество рабочих процессов и соединений. Это указывает на то, как NGINX будет масштабироваться для удовлетворения спроса.
worker_processes 2;
events {
worker_connections 2000;
}
Envoy Proxy по-разному управляет рабочими процессами и соединениями.
Envoy создает рабочий поток для каждого аппаратного потока в системе. Каждый рабочий поток выполняет неблокирующий цикл событий, который отвечает за
- Прослушивание каждого слушателя (listener)
- Принятие новых подключений
- Создание набора фильтров для соединения
- Обработка всех операций ввода-вывода за время существования соединения.
Вся дальнейшая обработка соединения полностью обрабатывается в рабочем потоке, включая любое поведение переадресации.
Для каждого рабочего потока в Envoy существует соединение в пуле. Таким образом, пулы соединений HTTP/2 устанавливают только одно соединение для каждого внешнего хоста за раз, при наличии четырех рабочих потоков будет четыре соединения HTTP/2 для каждого внешнего хоста в стабильном состоянии. Сохраняя все в одном рабочем потоке, почти весь код может быть написан без блокировок, как если бы он был однопоточным. Если рабочих потоков выделено больше чем необходимо, это может привести к не рациональному использованию памяти, созданию большого количества простаивающих соединений и уменьшения числа возвратов соединения обратно в пул.
Для получения дополнительной информации посетите Envoy Proxy blog.
Конфигурация HTTP
Следующий блок конфигурации NGINX определяет настройки HTTP, такие как:
- Какие mime типы поддерживаются
- Тайм-ауты по умолчанию
- Конфигурация Gzip
Вы можете настроить эти аспекты с помощью фильтров в Envoy Proxy, что мы обсудим позже.
Шаг 3 — Конфигурация Server
В блоке конфигурирования HTTP, конфигурация NGINX указывает прослушивать порт 8080 и отвечать на входящие запросы для доменов one.example.com и www.one.example.com.
server {
listen 8080;
server_name one.example.com www.one.example.com;
Внутри Envoy этим управляют Слушатели.
Слушатели Envoy
Самый важный аспект начала работы с Envoy Proxy — это определение слушателей. Вам нужно создать файл конфигурации, который описывает, как вы хотите запустить экземпляр Envoy.
Приведенный ниже фрагмент создаст нового слушателя и свяжет его с портом 8080. Конфигурация указывает Envoy Proxy, к каким портам он должен быть привязан для входящих запросов.
Envoy Proxy использует нотацию YAML для своей конфигурации. Для знакомства с этой нотацией, посмотрите здесь ссылку.
Copy to Editorstatic_resources:
listeners:
- name: listener_0
address:
socket_address: { address: 0.0.0.0, port_value: 8080 }
Нет необходимости определять server_name, так как фильтры Envoy Proxy справятся с этим.
Шаг 4 — Конфигурация местоположения
Когда запрос поступает в NGINX, блок местоположения определяет, как обрабатывать и куда направлять трафик. В следующем фрагменте весь трафик на сайт передается в upstream (примечание переводчика: upstream — обычно это сервера приложений) кластер с именем targetCluster. Upstream кластер определяет узлы, которые должны обрабатывать запрос. Мы обсудим это на следующем шаге.
location / {
proxy_pass http://targetCluster/;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
В Envoy этим занимается Filters.
Envoy Filters
Для статической конфигурации фильтры определяют, как обрабатывать входящие запросы. В этом случае мы устанавливаем фильтры, которые соответствуют server_names на предыдущем шаге. Когда поступают входящие запросы, которые соответствуют определенным доменам и маршрутам, трафик направляется в кластер. Это эквивалент восходящей конфигурации NGINX.
Copy to Editor filter_chains:
- filters:
- name: envoy.http_connection_manager
config:
codec_type: auto
stat_prefix: ingress_http
route_config:
name: local_route
virtual_hosts:
- name: backend
domains:
- "one.example.com"
- "www.one.example.com"
routes:
- match:
prefix: "/"
route:
cluster: targetCluster
http_filters:
- name: envoy.router
Имя envoy.http_connection_manager является встроенным фильтром в Envoy Proxy. Другие фильтры включают Redis, Mongo, TCP. Вы можете найти полный список в документации.
Для получения дополнительной информации о других политиках балансировки нагрузки посетите Документацию Envoy.
Step 5 — Proxy and Upstream Configuration
В NGINX конфигурация upstream определяет набор целевых серверов, которые будут обрабатывать трафик. В этом случае два кластера были назначены.
upstream targetCluster {
172.18.0.3:80;
172.18.0.4:80;
}
В Envoy это управляется кластерами.
Envoy Clusters
Эквивалент upstream определяется как кластеры. В этом случае были определены хосты, которые будут обслуживать трафик. Способ доступа к хостам, например время ожидания, определяется как конфигурация кластера. Это позволяет более точно контролировать зернистость таких аспектов, как время ожидания и балансировка нагрузки.
Copy to Editor clusters:
- name: targetCluster
connect_timeout: 0.25s
type: STRICT_DNS
dns_lookup_family: V4_ONLY
lb_policy: ROUND_ROBIN
hosts: [
{ socket_address: { address: 172.18.0.3, port_value: 80 }},
{ socket_address: { address: 172.18.0.4, port_value: 80 }}
]
При использовании обнаружения службы STRICT_DNS Envoy будет непрерывно и асинхронно разрешать указанные цели DNS. Каждый возвращенный IP-адрес в результате DNS будет считаться явным хостом в восходящем кластере. Это означает, что если запрос возвращает два IP-адреса, Envoy предположит, что в кластере есть два хоста, и оба должны быть сбалансированы по нагрузке. Если хост удален из результата, Envoy предполагает, что он больше не существует, и будет отбирать трафик из любых существующих пулов соединений.
Для получения дополнительной информации см. Документацию прокси-сервера Envoy.
Шаг 6 — Доступ к журналу и ошибки
Окончательная конфигурация — регистрация. Вместо того, чтобы передавать журналы ошибок на диск, Envoy Proxy использует облачный подход. Все журналы приложений выводятся в stdout и stderr.
Когда пользователи делают запрос, журналы доступа являются необязательными и по умолчанию отключены. Чтобы включить журналы доступа для запросов HTTP, включите конфигурацию access_log для диспетчера подключений HTTP. Путь может быть либо устройством, таким как stdout, либо файлом на диске, в зависимости от ваших требований.
Следующая конфигурация перенаправит все журналы доступа в stdout (примечание переводчика — stdout необходимо для использования envoy внутри docker. Если использовать без docker, то замените /dev/stdout на путь до обычного лог-файла). Скопируйте фрагмент в раздел конфигурации для менеджера соединений:
Copy to Clipboardaccess_log:
- name: envoy.file_access_log
config:
path: "/dev/stdout"
Результаты должны выглядеть так:
- name: envoy.http_connection_manager
config:
codec_type: auto
stat_prefix: ingress_http
access_log:
- name: envoy.file_access_log
config:
path: "/dev/stdout"
route_config:
По умолчанию Envoy имеет строку формата, которая включает подробности HTTP-запроса:
[%START_TIME%] "%REQ(:METHOD)% %REQ(X-ENVOY-ORIGINAL-PATH?:PATH)% %PROTOCOL%" %RESPONSE_CODE% %RESPONSE_FLAGS% %BYTES_RECEIVED% %BYTES_SENT% %DURATION% %RESP(X-ENVOY-UPSTREAM-SERVICE-TIME)% "%REQ(X-FORWARDED-FOR)%" "%REQ(USER-AGENT)%" "%REQ(X-REQUEST-ID)%" "%REQ(:AUTHORITY)%" "%UPSTREAM_HOST%"\n
Результат этой строки формата:
[2018-11-23T04:51:00.281Z] "GET / HTTP/1.1" 200 - 0 58 4 1 "-" "curl/7.47.0" "f21ebd42-6770-4aa5-88d4-e56118165a7d" "one.example.com" "172.18.0.4:80"
Содержимое вывода можно настроить, установив поле формата. Например:
access_log:
- name: envoy.file_access_log
config:
path: "/dev/stdout"
format: "[%START_TIME%] "%REQ(:METHOD)% %REQ(X-ENVOY-ORIGINAL-PATH?:PATH)% %PROTOCOL%" %RESPONSE_CODE% %RESP(X-ENVOY-UPSTREAM-SERVICE-TIME)% "%REQ(X-REQUEST-ID)%" "%REQ(:AUTHORITY)%" "%UPSTREAM_HOST%"\n"
Строка журнала также может быть выведена в формате JSON путем установки поля json_format. Например:
access_log:
- name: envoy.file_access_log
config:
path: "/dev/stdout"
json_format: {"protocol": "%PROTOCOL%", "duration": "%DURATION%", "request_method": "%REQ(:METHOD)%"}
Для получения дополнительной информации о методике регистрации посланника, посетите
https://www.envoyproxy.io/docs/envoy/latest/configuration/access_log#config-access-log-format-dictionaries
Ведение журнала — не единственный способ получить представление о работе с Envoy Proxy. В него встроены расширенные возможности трассировки и метрик. Вы можете узнать больше в документации по трассировке или через Сценарий интерактивной трассировки.
Шаг 7 — Запуск
Теперь вы перевели конфигурацию с NGINX на Envoy Proxy. Последний шаг — запустить экземпляр Envoy Proxy для его тестирования.
Запуск от пользователя
В верхней части конфигурации NGINX строка user www www; указывает на запуск NGINX в качестве пользователя с низким уровнем привилегий для повышения безопасности.
Envoy Proxy использует облачный подход к управлению тем, кто является владельцем процесса. Когда мы запускаем Envoy Proxy через контейнер, мы можем указать пользователя с низким уровнем привилегий.
Запуск Envoy Proxy
Команда ниже запустит Envoy Proxy через Docker-контейнер на хосте. Эта команда предоставляет Envoy возможность прослушивать входящие запросы через порт 80. Однако, как указано в конфигурации прослушивателя, Envoy Proxy прослушивает входящий трафик через порт 8080. Это позволяет процессу запускаться как пользователь с низкими привилегиями.
docker run --name proxy1 -p 80:8080 --user 1000:1000 -v /root/envoy.yaml:/etc/envoy/envoy.yaml envoyproxy/envoy
Тестирование
С запущенным прокси, тесты теперь могут быть сделаны и обработаны. Следующая команда cURL выдает запрос с заголовком узла, определенным в конфигурации прокси.
curl -H "Host: one.example.com" localhost -i
Запрос HTTP приведет к ошибке 503. Это связано с тем, что восходящие соединения не работают и они недоступны. Таким образом, у Envoy Proxy нет доступных целевых адресатов для запроса. Следующая команда запустит серию HTTP-сервисов, которые соответствуют конфигурации, определенной для Envoy.
docker run -d katacoda/docker-http-server; docker run -d katacoda/docker-http-server;
С доступными услугами Envoy может успешно проксировать трафик к месту назначения.
curl -H "Host: one.example.com" localhost -i
Вы должны увидеть ответ, указывающий, какой контейнер Docker обработал запрос. В журналах Envoy Proxy вы также должны увидеть выведенную строку доступа.
Дополнительные заголовки ответа HTTP (HTTP Response)
В заголовках ответа действительного запроса вы увидите дополнительные заголовки HTTP. В заголовке отображается время, которое вышестоящий хост потратил на обработку запроса. Выражается в миллисекундах. Это полезно, если клиент хочет определить время обслуживания по сравнению с задержкой в сети.
x-envoy-upstream-service-time: 0
server: envoy
Итоговый конфиг
static_resources:
listeners:
- name: listener_0
address:
socket_address: { address: 0.0.0.0, port_value: 8080 }
filter_chains:
- filters:
- name: envoy.http_connection_manager
config:
codec_type: auto
stat_prefix: ingress_http
route_config:
name: local_route
virtual_hosts:
- name: backend
domains:
- "one.example.com"
- "www.one.example.com"
routes:
- match:
prefix: "/"
route:
cluster: targetCluster
http_filters:
- name: envoy.router
clusters:
- name: targetCluster
connect_timeout: 0.25s
type: STRICT_DNS
dns_lookup_family: V4_ONLY
lb_policy: ROUND_ROBIN
hosts: [
{ socket_address: { address: 172.18.0.3, port_value: 80 }},
{ socket_address: { address: 172.18.0.4, port_value: 80 }}
]
admin:
access_log_path: /tmp/admin_access.log
address:
socket_address: { address: 0.0.0.0, port_value: 9090 }
Дополнительная информация от переводчика
Инструкции по установке Envoy Proxy вы можете найти на сайте https://www.getenvoy.io/
По умолчанию в rpm отсутствует systemd service конфиг.
Добавьте systemd service конфиг /etc/systemd/system/envoy.service:
[Unit]
Description=Envoy Proxy
Documentation=https://www.envoyproxy.io/
After=network-online.target
Requires=envoy-auth-server.service
Wants=nginx.service
[Service]
User=root
Restart=on-failure
ExecStart=/usr/bin/envoy --config-path /etc/envoy/config.yaml
[Install]
WantedBy=multi-user.target
Вам нужно создать директорию /etc/envoy/ и положить туда конфиг config.yaml.
По envoy proxy есть телеграм чат: https://t.me/envoyproxy_ru
Envoy Proxy нет поддержки раздачи статического содержимого. Поэтому кто может проголосуйте за feature: https://github.com/envoyproxy/envoy/issues/378