Міграція з Nginx на Envoy Proxy

Привіт, Хабре! Пропоную вашій увазі переклад посту: Міграція з 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 зазвичай мають три ключові елементи:

  1. Налаштування сервера NGINX, структури журналів та функціональності Gzip. Це визначається глобально у всіх випадках.
  2. Налаштування NGINX для прийому запитів на хост one.example.com порту 8080.
  3. Налаштування цільового розташування, як обробляти трафік для різних частин 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 створює робочий потік кожного апаратного потоку у системі. Кожен робочий потік виконує неблокуючий цикл подій, який відповідає за

  1. Прослуховування кожного слухача (listener)
  2. Прийняття нових підключень
  3. Створення набору фільтрів для з'єднання
  4. Обробка всіх операцій введення-виведення за час існування з'єднання.

Вся подальша обробка з'єднання повністю обробляється у робочому потоці, включаючи будь-яку поведінку переадресації.

Для кожного робочого потоку 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 }

Немає необхідності визначати ім'я_сервера, тому що фільтри 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, Монго, 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

Тільки зареєстровані користувачі можуть брати участь в опитуванні. Увійдіть, будь ласка.

Чи спонукав цей пост встановити і протестувати envoy proxy?

  • да

  • немає

Проголосували 75 користувачів. Утрималися 18 користувачів.

Джерело: habr.com

Додати коментар або відгук