Вітаю! Гэта невялікі артыкул, якая адказвае на пытанні: "што такое envoy?", "навошта ён патрэбен?" і "з чаго пачаць?".
Што гэта
Envoy - гэта L4-L7 балансавальнік напісаны на З ++, арыентаваны на высокую прадукцыйнасць і даступнасць. З аднаго боку, гэта ў некаторым родзе аналог nginx і haproxy, сувымерны з імі па прадукцыйнасці. З іншага, ён больш арыентаваны пад мікрасэрвісную архітэктуру і валодае функцыяналам не горш балансавальнікаў на java і go, такіх як zuul ці traefik.
Табліца параўнання haproxy/nginx/envoy, яна не прэтэндуе на абсалютную ісціну, але дае агульную карціну.
Nginx
гапраксі
пасланы
траефік
зорак на github
11.2k/mirror
1.1k/mirror
12.4k
27.6k
напісаны на
C
C
C + +
go
API
няма
socket only/push
dataplane/pull
цягнуць
active healthcheck
няма
ды
ды
ды
Open tracing
вонкавы плягін
няма
ды
ды
Дж.В.Т.
вонкавы плягін
няма
ды
няма
пашырэнне
Lua/C
Lua/C
Lua/C++
няма
навошта
Гэта малады праект, у ім шмат чаго няма, нешта ў ранняй альфе. Але пасланы, у тым ліку за кошт маладосці, хутка развіваецца і ўжо зараз мае шмат цікавых магчымасцяў: дынамічную канфігурацыю, шмат гатовых фільтраў, просты інтэрфейс для напісання сваіх фільтраў.
З гэтага выцякаюць вобласці ўжывання, але для пачатку 2 антыпатэрна:
- Аддача статыкі.
Справа ў тым, што на дадзены момант у пасланы няма падтрымкі кэшавання. Хлопцы з google спрабуюць гэта
А пакуль выкарыстоўвайце для статыкі nginx.
- Статычная канфігурацыя.
Можна яе выкарыстоўваць, але пасланы быў створаны не для гэтага. Магчымасці ў статычнай канфігурацыі не будуць раскрыты. Момантаў шмат:
Рэдактуючы канфігурацыю ў yaml, Вы будзеце памыляцца, мацерыць распрацоўнікаў за шматслоўнасць і думаць, што канфігі nginx/haproxy, хай меней структураваныя, але лаканічна. У гэтым і сутнасць. Канфігурацыя Nginx і Haproxy стваралася пад рэдагаванне рукамі, а ў пасланы пад генерацыю з кода. Уся канфігурацыя апісана ў
Сцэнары canary, b/g дэплою і шмат іншае, нармальна рэалізуюцца толькі ў дынамічнай канфігурацыі. Я не кажу, што гэта нельга зрабіць у статыцы, мы ўсё гэта робім. Але для гэтага трэба абкласціся мыліцамі, у любым з балансараў, у пасланы у тым ліку.
Задачы ў якіх Envoy незаменны:
- Балансіроўка трафіку ў складаных і дынамічных сістэмах. Сюды пападае service mesh, але гэта не абавязкова толькі ён.
- Неабходнасць функцыяналу размеркаванай трасіроўкі, складанай аўтарызацыі ці іншага, які ёсць у пасланы са скрынкі ці зручна рэалізоўваецца, а ў nginx/haproxy трэба абкласціся lua і сумнеўнымі ўбудовамі.
І тое, і іншае пры неабходнасці забяспечыць высокую прадукцыйнасць.
Як гэта працуе
Envoy распаўсюджваецца ў бінарніках толькі як docker вобраз. У выяве ўжо ёсць прыклад статычнай канфігурацыі. Але нам ён цікавы толькі для разумення структуры.
envoy.yaml статычная канфігурацыя
static_resources:
listeners:
- name: listener_0
address:
socket_address:
protocol: TCP
address: 0.0.0.0
port_value: 10000
filter_chains:
- filters:
- name: envoy.http_connection_manager
typed_config:
"@type": type.googleapis.com/envoy.config.filter.network.http_connection_manager.v2.HttpConnectionManager
stat_prefix: ingress_http
route_config:
name: local_route
virtual_hosts:
- name: local_service
domains: ["*"]
routes:
- match:
prefix: "/"
route:
host_rewrite: www.google.com
cluster: service_google
http_filters:
- name: envoy.router
clusters:
- name: service_google
connect_timeout: 0.25s
type: LOGICAL_DNS
# Comment out the following line to test on v6 networks
dns_lookup_family: V4_ONLY
lb_policy: ROUND_ROBIN
load_assignment:
cluster_name: service_google
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
address: www.google.com
port_value: 443
transport_socket:
name: envoy.transport_sockets.tls
typed_config:
"@type": type.googleapis.com/envoy.api.v2.auth.UpstreamTlsContext
sni: www.google.com
Дынамічная канфігурацыя
Рашэнне якой праблемы мы шукаем? Нельга проста так узяць і перазагрузіць канфігурацыю балансавальніка пад нагрузкай, узнікнуць "невялікія" праблемы:
- Валідацыя канфігурацыі.
Канфіг можа быць вялікі, можа быць вельмі вялікі, калі мы перагружаем яго ўвесь час, шанцы што недзе памылка ўзрастаюць.
- Доўгажывучыя злучэнні.
Пры ініцыялізацыі новага ліста, трэба паклапаціцца аб злучэннях якія працуюць на старым, калі змены адбываюцца часта і ёсць доўгажывучыя злучэнні, прыйдзецца шукаць кампраміс. Прывітанне, kubernetes ingress на nginx.
- Актыўныя хелсчэкі.
Калі ў нас ёсць актыўныя хелсчэкі, трэба было б іх усё пераправерыць на новым канфігу да таго як паслаць трафік. Калі апстрымаў шмат, гэта патрабуе час. Прывітанне, haproxy.
Як гэта вырашаецца ў пасланы, падгружаючы канфіг дынамічна, па пул мадэлі, можна яго падзяліць на асобныя часткі і не пераініцыялізаваць тую частку якая не мянялася. Напрыклад лістанер, які пераініцыялізаваць дорага, а змяняецца ён рэдка.
Канфігурацыя пасланы (з файла вышэй) мае наступныя сутнасці:
- listener - Лісценер які вісіць на вызначаным ip / порце
- віртуальны хост - віртуальны хост па імені дамена
- маршрут - правіла балансавання
- кластар - група апстрымаў з параметрамі балансавання
- канчатковая кропка - адрас інстансу апстрыму
Кожную з гэтых сутнасцяў плюс некаторыя іншыя можна запоўніць дынамічна, для гэтага ў канфігурацыі паказваецца адрас сэрвісу ад куды будзе атрыманы канфіг. Сэрвіс можа быць REST або gRPC, пераважней выкарыстоўваць gRPC.
Сэрвісы называюцца адпаведна: LDS, VHDS, RDS, CDS і EDS. Можна камбінаваць статычную і дынамічную канфігурацыю, з абмежаваннем, што дынамічны рэсурс нельга паказаць у статычным.
Для большасці задач дастаткова рэалізаваць апошнія тры сэрвісу, яны называюцца ADS (Aggregated Discovery Service), для
Канфігурацыя набывае наступны выгляд:
envoy.yaml дынамічная канфігурацыя
dynamic_resources:
ads_config:
api_type: GRPC
grpc_services:
envoy_grpc:
cluster_name: xds_clr
cds_config:
ads: {}
static_resources:
listeners:
- name: listener_0
address:
socket_address:
protocol: TCP
address: 0.0.0.0
port_value: 10000
filter_chains:
- filters:
- name: envoy.http_connection_manager
typed_config:
"@type": type.googleapis.com/envoy.config.filter.network.http_connection_manager.v2.HttpConnectionManager
stat_prefix: ingress_http
rds:
route_config_name: local_route
config_source:
ads: {}
http_filters:
- name: envoy.router
clusters:
- name: xds_clr
connect_timeout: 0.25s
type: LOGICAL_DNS
dns_lookup_family: V4_ONLY
lb_policy: ROUND_ROBIN
load_assignment:
cluster_name: xds_clr
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
address: xds
port_value: 6565
пры запуску пасланы з гэтым канфігам, ён падлучыцца да control-plane і паспрабуе запытаць канфігурацыю RDS, CDS і EDS. Як адбываецца працэс узаемадзеяння апісана
Калі коратка, пасланы шле запыт, з указаннем тыпу запытанага рэсурсу, версіяй і параметрамі ноды. У адказ атрымлівае рэсурс і версію, калі на control-plane версія не памянялася, ён не адказвае.
Ёсць 4 варыянты ўзаемадзеяння:
- Адзін gRPC стрымліваецца на ўсе тыпы рэсурсаў, дасылаецца поўнае стан рэсурсу.
- Паасобныя стрымы, поўны стан.
- Адзін стрым, інкрыментальны стан.
- Паасобныя стрымы, інкрыментальны стан.
Incremental xDS дазваляе паменшыць трафік паміж control-plane і пасланы, гэта актуальна для вялікіх канфігурацый. Але ўскладняе ўзаемадзеянне, у запыце перадаецца спіс рэсурсаў для адпіскі і падпіскі.
У нашым прыкладзе выкарыстоўваецца ADS – адзін стрым для RDS, CDS, EDS і не інкрыментальны рэжым. Для ўключэння інкрыментальнага рэжыму, трэба пазначыць api_type: DELTA_GRPC
Так як у запыце ёсць параметры ноды, мы можам на control-plane дасылаць розныя рэсурсы для розных інстансаў. пасланы, гэта зручна для пабудовы service mesh.
Разагрэў
На пасланы пры старце або пры атрыманні новай канфігурацыі ад control-plane запускаецца працэс warmup рэсурсаў. Ён падзелены, на listener warmup і cluster warmup. Першы запускаецца пры зменах у RDS/LDS, другі пры CDS/EDS. Гэта значыць, што калі мяняюцца толькі апстрымы, лістанер не пераствараецца.
У працэсе прагрэву, чакаюцца залежныя рэсурсы ад control-plane на працягу таймаўту. Калі таймаўт выйшаў, ініцыялізацыя не будзе паспяховай, новы лістанер не пачне слухаць порт.
Парадак ініцыялізацыі: EDS, CDS, active health check, RDS, LDS. Пры ўключаных актыўных хелсчэках, трафік пойдзе на апстрым, толькі пасля аднаго паспяховага хелсчэка.
Калі пераствараецца лістар, стары пераходзіць у стан DRAIN, і будзе выдалены пасля зачынення ўсіх злучэнняў або заканчэнні таймаўту --drain-time-s
, па змаўчанні 10 хвілін.
Працяг будзе.
Крыніца: habr.com