[Системное администрирование, IT-инфраструктура, DevOps, Микросервисы] Пишем фильтры WASM для Envoy и деплоим их с Istio (перевод)
Автор
Сообщение
news_bot ®
Стаж: 6 лет 9 месяцев
Сообщений: 27286
Envoy — это высокопроизводительный программируемый прокси L3/L4 и L7, на котором основано множество реализаций service mesh, например, Istio. Envoy обрабатывает трафик с помощью сетевых фильтров, которые можно объединять в цепочки, чтобы реализовывать сложные функции для контроля доступа, преобразования, обогащения данных, аудита и так далее. Чтобы расширить функционал Envoy, новые фильтры можно добавить одним из двух способов:
- Интегрируем дополнительные фильтры в исходный код Envoy и компилируем новую версию Envoy. Недостаток такого подхода в том, что придется поддерживать свою версию Envoy и постоянно синхронизировать ее с официальным дистрибутивом. Фильтр, кстати, нужно реализовать на C++, как и сам Envoy.
- Динамически загружаем новые фильтры в Envoy Proxy в рантайме.
Второй вариант гораздо интереснее и проще — мы используем WebAssembly (WASM), эффективный и портативный бинарный формат инструкций со встраиваемой и изолированной средой выполнения.
Расскажу подробнее о фильтрах WASM.
Почему фильтры WASM? ︎
Плюсы фильтров WASM:
- Гибкость — фильтры можно динамически загружать в запущенный процесс Envoy без остановки или перекомпиляции.
- Простота использования — мы расширяем функционал Envoy, не меняя кодовую базу.
- Разнообразие — мы можем выбрать язык для реализации фильтров, например C/C++, Rust или golang, и скомпилировать его в WASM.
- Надежность и изоляция — мы деплоим фильтры на виртуальной машине (в песочнице) изолированно от самого процесса Envoy (если что-то пойдет не так, процесс не пострадает).
- Безопасность — фильтры общаются с хостом (Envoy Proxy) через продуманный API, поэтому у них есть доступ к ограниченному числу соединений или свойств запросов.
Минусы, конечно, тоже есть:
- Производительность на уровне 70% от C++.
- Нужно больше памяти, чтобы запускать виртуальные машины для WASM.
Envoy Proxy WASM SDK ︎
Envoy Proxy выполняет фильтры WASM внутри виртуальной машины на основе стека, поэтому память фильтра изолирована от хост-среды. Все взаимодействия между хостом (Envoy Proxy) и фильтром WASM реализуются через функции и обратные вызовы, предоставляемые Envoy Proxy WASM SDK. С Envoy Proxy WASM SDK можно выбрать разные языки:
Здесь я расскажу, как писать фильтры WASM для Envoy с помощью C++ Envoy Proxy WASM SDK. Мы не будем подробно останавливаться на API для Envoy Proxy WASM SDK, но постараемся разобраться в основах написания фильтров WASM для Envoy.
Для реализации фильтров нам нужны два класса:
class RootContext;
class Context;
Когда мы загружаем плагин WASM (бинарный код WASM с фильтром), создается root context. Root context существует столько же, сколько инстанс виртуальной машины, который выполняет фильтр. Его задачи:
- взаимодействия между кодом и Envoy Proxy при начальной настройке;
- взаимодействия, которые продолжат существовать после запроса.
onConfigure(size_t) вызывается Envoy Proxy в RootContext только для передачи конфигураций в виртуальную машину и плагин. Если плагин с одним или несколькими фильтрами ожидает от Envoy Proxy конфигурацию, эту функцию можно отменить и получить конфигурацию с помощью вспомогательной функции getBufferBytes через WasmBufferType::VmConfiguration и WasmBufferType::PluginConfiguration соответственно.
Сетевой трафик, обрабатываемый Envoy Proxy, будет проходить через цепочку фильтров, связанную с listener, который получает этот трафик. Для каждого нового потока через цепочку фильтров Envoy Proxy создает новый контекст, который существует до конца потока.
Базовый класс Context предоставляет хуки (обратные вызовы) в виде виртуальных функций onXXXX(...) для трафика HTTP и TCP, которые вызываются, когда Envoy Proxy проходит по цепочке фильтров. Обратные вызовы в Context зависят от уровня цепочки фильтров, в которую входит фильтр (HTTP или TCP). Например, FilterHeadersStatus onRequestHeaders(uint32_t) вызывается только для фильтров WASM в цепочке на уровне HTTP, но не для TCP.
Реализация базового класса Context используется Envoy Proxy для взаимодействия с кодом на протяжении времени существования потока. В этих функциях обратных вызовов мы можем управлять трафиком. SDK предоставляет функции для управления заголовками HTTP-запросов и ответов (getRequestHeader, addRequestHeader и т. д.), телом HTTP-запроса, TCP-потоками (например, getBufferBytes, setBufferBytes) и т. д. Каждая функция обратного вызова возвращает статус, по которому Envoy Proxy узнает, надо или нет передавать обработку потока на следующий фильтр в цепочке.
Следующий шаг — зарегистрировать инстансы factory, чтобы создать реализации RootContext и Context через объявление статической переменной типа
class RegisterContextFactory;
Переменная будет ждать root context factory и context factory в виде аргументов конструктора.
Пример фильтра ︎
Вот очень простой пример скелета фильтра WASM, который можно создать с C++ Envoy Proxy WASM SDK: example-filter.cc:
#include "proxy_wasm_intrinsics.h"
class ExampleRootContext: public RootContext {
public:
explicit ExampleRootContext(uint32_t id, StringView root_id): RootContext(id, root_id) {}
bool onStart(size_t) override;
};
class ExampleContext: public Context {
public:
explicit ExampleContext(uint32_t id, RootContext* root) : Context(id, root) {}
FilterHeadersStatus onResponseHeaders(uint32_t) override;
FilterStatus onDownstreamData(size_t, bool) override;
};
// register factories for ExampleContext and ExampleRootContext
static RegisterContextFactory register_FilterContext(CONTEXT_FACTORY(ExampleContext),
ROOT_FACTORY(ExampleRootContext),
"my_root_id");
// invoked when the plugin initialised and is ready to process streams
bool ExampleRootContext::onStart(size_t n) {
LOG_DEBUG("ready to process streams");
return true;
}
// invoked when HTTP response header is decoded
FilterHeadersStatus ExampleContext::onResponseHeaders(uint32_t) {
addResponseHeader("resp-header-demo", "added by our filter");
return FilterHeadersStatus::Continue;
}
// invoked when downstream TCP data chunk is received
FilterStatus ExampleContext::onDownstreamData(size_t, bool) {
auto res = setBuffer(WasmBufferType::NetworkDownstreamData, 0, 0, "prepend payload to downstream data");
if (res != WasmResult::Ok) {
LOG_ERROR("Modifying downstream data failed: " + toString(res));
return FilterStatus::StopIteration;
}
return FilterStatus::Continue;
}
Сборка фильтра
Самый простой способ собрать фильтр — использовать Docker, потому что так нам не придется хранить на локальном компьютере разные библиотеки.
- Сначала создаем образ docker с помощью C++ Envoy Proxy WASM SDK, как описано здесь.
- Создаем Makefile для фильтра WASM. Makefile:
.PHONY = all clean
PROXY_WASM_CPP_SDK=/sdk
all: example-filter.wasm
include ${PROXY_WASM_CPP_SDK}/Makefile.base_lite
- Собираем фильтр WASM:
docker run -v $PWD:/work -w /work wasmsdk:v2 /build_wasm.sh
Деплоим фильтр WASM с Istio ︎
Узнать о работе с Istio и внедрении service mesh можно на интенсиве 19—21 марта.
Деплоим наш фильтр Envoy WASM для приложения, запущенного в Istio service mesh в Kubernetes. Можем быстро запустить Istio mesh с демо-приложением в Kubernetes с помощью Backyards, дистрибутива Istio от Banzai Cloud. (прим. переводчика: также можно воспользоваться этой getting started инструкцией до шага Deploy the sample application включительно и далее использовать bookinfo приложение в следующих шагах).
backyards install -a --run-demo
Всего одна команда — и к нашим услугам production-ready и полностью рабочая Istio service mesh с демо-приложением из нескольких микросервисов внутри.
Создаем config map для кода wasm
Создаем config map, где будет размещаться код WASM для нашего фильтра, в неймспейс backyards-demo, где запущено демо (прим. переводчика:либо bookinfo в случае использования чистого Istio).
kubectl create cm -n backyards-demo example-filter --from-file=example-filter.wasm
Внедряем код wasm в демо с помощью Istio ︎
- Внедряем код wasm в сервис frontpage нашего демо-приложения с помощью двух аннотаций:
sidecar.istio.io/userVolume: '[{"name":"wasmfilters-dir","configMap": {"name": "example-filter"}}]'
sidecar.istio.io/userVolumeMount: '[{"mountPath":"/var/local/lib/wasm-filters","name":"wasmfilters-dir"}]'
- Выполняем
kubectl scale deployment -n backyards-demo frontpage-v1 --replicas=1
kubectl patch deployment -n backyards-demo frontpage-v1 -p '{"spec":{"template":{"metadata":{"annotations":{"sidecar.istio.io/userVolume":"[{"name":"wasmfilters-dir","configMap": {"name": "example-filter"}}]","sidecar.istio.io/userVolumeMount":"[{"mountPath":"/var/local/lib/wasm-filters","name":"wasmfilters-dir"}]"}}}}}'
Теперь код фильтра WASM доступен в /var/local/lib/wasm-filters в контейнере istio-proxy:
kubectl exec -n backyards-demo -it deployment/frontpage-v1 -c istio-proxy -- ls /var/local/lib/wasm-filters/
example-filter.wasm
- Включаем для фильтров WASM логирование на уровне DEBUG при обработке трафика к сервису frontpage:
kubectl port-forward -n backyards-demo deployment/frontpage-v1 15000
curl -XPOST "localhost:15000/logging?wasm=debug"
- Вставляем фильтр WASM в цепочку на уровне HTTP, привязанную к порту HTTP 8080:
kubectl apply -f-<<EOF
apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
name: frontpage-v1-examplefilter
namespace: backyards-demo
spec:
configPatches:
- applyTo: HTTP_FILTER
match:
context: SIDECAR_INBOUND
proxy:
proxyVersion: '^1\.5.*'
listener:
portNumber: 8080
filterChain:
filter:
name: envoy.http_connection_manager
subFilter:
name: envoy.router
patch:
operation: INSERT_BEFORE
value:
config:
config:
name: example-filter
rootId: my_root_id
vmConfig:
code:
local:
filename: /var/local/lib/wasm-filters/example-filter.wasm
runtime: envoy.wasm.runtime.v8
vmId: example-filter
allow_precompiled: true
name: envoy.filters.http.wasm
workloadSelector:
labels:
app: frontpage
version: v1
EOF
Примечание. При тестировании мы обнаружили, что фильтр portNumber, указанный для listener match в кастомном ресурсе EnvoyFilter, некорректно обрабатывался в Istio, поэтому хуки для фильтра не вызывались. Мы исправили эту проблему в нашем дистрибутиве Istio — Backyards.
- Отправляем трафик через порт HTTP 8080 в сервис frontpage:
kubectl run curl --image=yauritux/busybox-curl --restart=Never -it --rm sh
/home # curl -L -v http://frontpage.backyards-demo:8080
Мы ожидаем увидеть заголовок фильтра, добавленный к заголовку ответа:
SPL
* About to connect() to frontpage.backyards-demo port 8080 (#0)
* Trying 10.10.178.38...
* Adding handle: conn: 0x10eadbd8
* Adding handle: send: 0
* Adding handle: recv: 0
* Curl_addHandleToPipeline: length: 1
* - Conn 0 (0x10eadbd8) send_pipe: 1, recv_pipe: 0
* Connected to frontpage.backyards-demo (10.10.178.38) port 8080 (#0)
> GET / HTTP/1.1
> User-Agent: curl/7.30.0
> Host: frontpage.backyards-demo:8080
> Accept: */*
>
< HTTP/1.1 200 OK
< content-type: text/plain
< date: Thu, 16 Apr 2020 16:32:20 GMT
< content-length: 9
< x-envoy-upstream-service-time: 10
< resp-header-demo: added by our filter
< x-envoy-peer-metadata: CjYKDElOU1RBTkNFX0lQUxImGiQxMC4yMC4xLjU3LGZlODA6OmQwNDM6NDdmZjpmZWYwOmVkMjkK2QEKBkxBQkVMUxLOASrLAQoSCgNhcHASCxoJZnJvbnRwYWdlCiEKEXBvZC10ZW1wbGF0ZS1oYXNoEgwaCjU3OGM2NTU0ZDQKJAoZc2VjdXJpdHkuaXN0aW8uaW8vdGxzTW9k
ZRIHGgVpc3RpbwouCh9zZXJ2aWNlLmlzdGlvLmlvL2Nhbm9uaWNhbC1uYW1lEgsaCWZyb250cGFnZQorCiNzZXJ2aWNlLmlzdGlvLmlvL2Nhbm9uaWNhbC1yZXZpc2lvbhIEGgJ2MQoPCgd2ZXJzaW9uEgQaAnYxChoKB01FU0hfSUQSDxoNY2x1c3Rlci5sb2NhbAonCgROQU1FEh8aHWZyb250cGFnZS12MS01N
zhjNjU1NGQ0LWxidnFrCh0KCU5BTUVTUEFDRRIQGg5iYWNreWFyZHMtZGVtbwpXCgVPV05FUhJOGkxrdWJlcm5ldGVzOi8vYXBpcy9hcHBzL3YxL25hbWVzcGFjZXMvYmFja3lhcmRzLWRlbW8vZGVwbG95bWVudHMvZnJvbnRwYWdlLXYxCi8KEVBMQVRGT1JNX01FVEFEQVRBEhoqGAoWCgpjbHVzdGVyX2lkEg
gaBm1hc3RlcgocCg9TRVJWSUNFX0FDQ09VTlQSCRoHZGVmYXVsdAofCg1XT1JLTE9BRF9OQU1FEg4aDGZyb250cGFnZS12MQ==
< x-envoy-peer-metadata-id: sidecar~10.20.1.57~frontpage-v1-578c6554d4-lbvqk.backyards-demo~backyards-demo.svc.cluster.local
< x-by-metadata: CjYKDElOU1RBTkNFX0lQUxImGiQxMC4yMC4xLjU3LGZlODA6OmQwNDM6NDdmZjpmZWYwOmVkMjkK2QEKBkxBQkVMUxLOASrLAQoSCgNhcHASCxoJZnJvbnRwYWdlCiEKEXBvZC10ZW1wbGF0ZS1oYXNoEgwaCjU3OGM2NTU0ZDQKJAoZc2VjdXJpdHkuaXN0aW8uaW8vdGxzTW9kZRIHGgVp
c3RpbwouCh9zZXJ2aWNlLmlzdGlvLmlvL2Nhbm9uaWNhbC1uYW1lEgsaCWZyb250cGFnZQorCiNzZXJ2aWNlLmlzdGlvLmlvL2Nhbm9uaWNhbC1yZXZpc2lvbhIEGgJ2MQoPCgd2ZXJzaW9uEgQaAnYxChoKB01FU0hfSUQSDxoNY2x1c3Rlci5sb2NhbAonCgROQU1FEh8aHWZyb250cGFnZS12MS01NzhjNjU1N
GQ0LWxidnFrCh0KCU5BTUVTUEFDRRIQGg5iYWNreWFyZHMtZGVtbwpXCgVPV05FUhJOGkxrdWJlcm5ldGVzOi8vYXBpcy9hcHBzL3YxL25hbWVzcGFjZXMvYmFja3lhcmRzLWRlbW8vZGVwbG95bWVudHMvZnJvbnRwYWdlLXYxCi8KEVBMQVRGT1JNX01FVEFEQVRBEhoqGAoWCgpjbHVzdGVyX2lkEggaBm1hc3
RlcgocCg9TRVJWSUNFX0FDQ09VTlQSCRoHZGVmYXVsdAofCg1XT1JLTE9BRF9OQU1FEg4aDGZyb250cGFnZS12MQ==
* Server istio-envoy is not blacklisted
< server: istio-envoy
< x-envoy-decorator-operation: frontpage.backyards-demo.svc.cluster.local:8080/*
<
* Connection #0 to host frontpage.backyards-demo left intact
frontpage
- Если мы хотим зарегистрировать фильтр WASM в цепочке TCP для сервиса frontpage, который принимает TCP на порте 8083, кастомный ресурс EnvoyFilter будет выглядеть как-то так:
kubectl apply -f-<<EOF
apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
name: frontpage-v1-examplefilter
namespace: backyards-demo
spec:
configPatches:
- applyTo: NETWORK_FILTER
match:
context: SIDECAR_INBOUND
proxy:
proxyVersion: '^1\.5.*'
listener:
portNumber: 8083
filterChain:
filter:
name: "envoy.tcp_proxy"
patch:
operation: INSERT_BEFORE
value:
config:
config:
name: example-filter
rootId: my_root_id
vmConfig:
code:
local:
filename: /var/local/lib/wasm-filters/example-filter.wasm
runtime: envoy.wasm.runtime.v8
vmId: example-filter
allow_precompiled: true
name: envoy.filters.network.wasm
workloadSelector:
labels:
app: frontpage
version: v1
EOF
Если мы добавили фильтр в цепочку на уровне TCP, вызываются только хуки для TCP-трафика.
Вот наглядная схема того, как это работает с Istio:
Пишем фильтры WASM для Envoy с WASME ︎
Solo.io предложили решение для разработки фильтров WASM для Envoy — WebAssembly Hub, чтобы загружать и выгружать свои коды фильтров WASM. Используйте инструмент WASME для скаффолдинга, сборки и отправки фильтров WASM в WebAssembly Hub.
При деплое фильтра WASM wasme вытаскивает образ с плагином фильтра WASM из WebAssembly Hub, запускает daemonset, чтобы извлечь код плагина WASM из этого образа, и открывает его для Envoy Proxy на каждой ноде через тома hostPath.
Примечание. Образы из WebAssembly Hub не будут отображаться как стандартные образы Docker.
Правда, тут мы публикуем и храним фильтры WASM в стороннем хранилище (WebAssembly Hub), так что этот вариант вам не подойдет, если из-за строгих политик безопасности или по другой причине вы не хотите обнародовать проприетарный код, даже в бинарном формате, за пределами корпоративной сети.
Заключение ︎
С фильтрами WASM для Envoy можно написать свой код, скомпилировать его в плагины WASM и настроить Envoy для его выполнения. Плагины могут содержать произвольную логику, поэтому подходят для любых интеграций и изменений в сообщениях. Так что фильтры WASM для Envoy Proxy — это идеальный способ интегрировать любую логику в сетевое взаимодействие.
===========
Источник:
habr.com
===========
===========
Автор оригинала: Toader Sebastian
===========Похожие новости:
- [IT-инфраструктура, Администрирование баз данных, Big Data, Софт] Вот это скорость! Как мы подружили наш UBA-модуль с ClickHouse и что из этого вышло
- [Информационная безопасность, Open source, Системное администрирование, Системное программирование] Защита ядра Linux из ARM Trustzone: как усилить Linux Kernel Runtime Guard и предотвращать последствия zero-day
- [IT-инфраструктура, DevOps, Микросервисы, Kubernetes] Онлайн-интенсив «Service mesh» 19—21 марта
- [Высокая производительность, IT-инфраструктура, Экология] ВТБ направит старые банкоматы на экологическую переработку
- [Настройка Linux, Сетевые технологии, Серверное администрирование, Микросервисы, Kubernetes] Настройка отказоустойчивого кластера Kubernetes на серверах с публичной и приватной сетью с помощью Kubeadm
- [Информационная безопасность, Системное администрирование, Сетевые технологии] Lawful Interception, поиск по вложениям и персонализация страницы аутентификации Zimbra OSE
- [Системное администрирование, Серверное администрирование, DevOps, Kubernetes] Проблемные поды: эскалация привилегий подов в Kubernetes (перевод)
- [Анализ и проектирование систем, Микросервисы] Как мы внедрили кредитный конвейер на микросервисах в банке
- [Системное администрирование, Системное программирование, DevOps] Упаковка любого python пакета в rpm пакет с возможностью offline установки
- [Настройка Linux, Системное администрирование, *nix, Сетевые технологии] Укрощение строптивого HAPROXY. Работаем ssl <--> ssl с генерацией сертификатов отдельно на каждом сервере
Теги для поиска: #_sistemnoe_administrirovanie (Системное администрирование), #_itinfrastruktura (IT-инфраструктура), #_devops, #_mikroservisy (Микросервисы), #_istio, #_envoy_proxy, #_envoy, #_wasm, #_blog_kompanii_southbridge (
Блог компании Southbridge
), #_sistemnoe_administrirovanie (
Системное администрирование
), #_itinfrastruktura (
IT-инфраструктура
), #_devops, #_mikroservisy (
Микросервисы
)
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 14:33
Часовой пояс: UTC + 5
Автор | Сообщение |
---|---|
news_bot ®
Стаж: 6 лет 9 месяцев |
|
Envoy — это высокопроизводительный программируемый прокси L3/L4 и L7, на котором основано множество реализаций service mesh, например, Istio. Envoy обрабатывает трафик с помощью сетевых фильтров, которые можно объединять в цепочки, чтобы реализовывать сложные функции для контроля доступа, преобразования, обогащения данных, аудита и так далее. Чтобы расширить функционал Envoy, новые фильтры можно добавить одним из двух способов:
Второй вариант гораздо интереснее и проще — мы используем WebAssembly (WASM), эффективный и портативный бинарный формат инструкций со встраиваемой и изолированной средой выполнения. Расскажу подробнее о фильтрах WASM. Почему фильтры WASM? ︎ Плюсы фильтров WASM:
Минусы, конечно, тоже есть:
Envoy Proxy WASM SDK ︎ Envoy Proxy выполняет фильтры WASM внутри виртуальной машины на основе стека, поэтому память фильтра изолирована от хост-среды. Все взаимодействия между хостом (Envoy Proxy) и фильтром WASM реализуются через функции и обратные вызовы, предоставляемые Envoy Proxy WASM SDK. С Envoy Proxy WASM SDK можно выбрать разные языки: Здесь я расскажу, как писать фильтры WASM для Envoy с помощью C++ Envoy Proxy WASM SDK. Мы не будем подробно останавливаться на API для Envoy Proxy WASM SDK, но постараемся разобраться в основах написания фильтров WASM для Envoy. Для реализации фильтров нам нужны два класса: class RootContext;
class Context; Когда мы загружаем плагин WASM (бинарный код WASM с фильтром), создается root context. Root context существует столько же, сколько инстанс виртуальной машины, который выполняет фильтр. Его задачи:
onConfigure(size_t) вызывается Envoy Proxy в RootContext только для передачи конфигураций в виртуальную машину и плагин. Если плагин с одним или несколькими фильтрами ожидает от Envoy Proxy конфигурацию, эту функцию можно отменить и получить конфигурацию с помощью вспомогательной функции getBufferBytes через WasmBufferType::VmConfiguration и WasmBufferType::PluginConfiguration соответственно. Сетевой трафик, обрабатываемый Envoy Proxy, будет проходить через цепочку фильтров, связанную с listener, который получает этот трафик. Для каждого нового потока через цепочку фильтров Envoy Proxy создает новый контекст, который существует до конца потока. Базовый класс Context предоставляет хуки (обратные вызовы) в виде виртуальных функций onXXXX(...) для трафика HTTP и TCP, которые вызываются, когда Envoy Proxy проходит по цепочке фильтров. Обратные вызовы в Context зависят от уровня цепочки фильтров, в которую входит фильтр (HTTP или TCP). Например, FilterHeadersStatus onRequestHeaders(uint32_t) вызывается только для фильтров WASM в цепочке на уровне HTTP, но не для TCP. Реализация базового класса Context используется Envoy Proxy для взаимодействия с кодом на протяжении времени существования потока. В этих функциях обратных вызовов мы можем управлять трафиком. SDK предоставляет функции для управления заголовками HTTP-запросов и ответов (getRequestHeader, addRequestHeader и т. д.), телом HTTP-запроса, TCP-потоками (например, getBufferBytes, setBufferBytes) и т. д. Каждая функция обратного вызова возвращает статус, по которому Envoy Proxy узнает, надо или нет передавать обработку потока на следующий фильтр в цепочке. Следующий шаг — зарегистрировать инстансы factory, чтобы создать реализации RootContext и Context через объявление статической переменной типа class RegisterContextFactory;
Переменная будет ждать root context factory и context factory в виде аргументов конструктора. Пример фильтра ︎ Вот очень простой пример скелета фильтра WASM, который можно создать с C++ Envoy Proxy WASM SDK: example-filter.cc: #include "proxy_wasm_intrinsics.h"
class ExampleRootContext: public RootContext { public: explicit ExampleRootContext(uint32_t id, StringView root_id): RootContext(id, root_id) {} bool onStart(size_t) override; }; class ExampleContext: public Context { public: explicit ExampleContext(uint32_t id, RootContext* root) : Context(id, root) {} FilterHeadersStatus onResponseHeaders(uint32_t) override; FilterStatus onDownstreamData(size_t, bool) override; }; // register factories for ExampleContext and ExampleRootContext static RegisterContextFactory register_FilterContext(CONTEXT_FACTORY(ExampleContext), ROOT_FACTORY(ExampleRootContext), "my_root_id"); // invoked when the plugin initialised and is ready to process streams bool ExampleRootContext::onStart(size_t n) { LOG_DEBUG("ready to process streams"); return true; } // invoked when HTTP response header is decoded FilterHeadersStatus ExampleContext::onResponseHeaders(uint32_t) { addResponseHeader("resp-header-demo", "added by our filter"); return FilterHeadersStatus::Continue; } // invoked when downstream TCP data chunk is received FilterStatus ExampleContext::onDownstreamData(size_t, bool) { auto res = setBuffer(WasmBufferType::NetworkDownstreamData, 0, 0, "prepend payload to downstream data"); if (res != WasmResult::Ok) { LOG_ERROR("Modifying downstream data failed: " + toString(res)); return FilterStatus::StopIteration; } return FilterStatus::Continue; } Сборка фильтра Самый простой способ собрать фильтр — использовать Docker, потому что так нам не придется хранить на локальном компьютере разные библиотеки.
.PHONY = all clean
PROXY_WASM_CPP_SDK=/sdk all: example-filter.wasm include ${PROXY_WASM_CPP_SDK}/Makefile.base_lite
Деплоим фильтр WASM с Istio ︎ Узнать о работе с Istio и внедрении service mesh можно на интенсиве 19—21 марта.
backyards install -a --run-demo
Всего одна команда — и к нашим услугам production-ready и полностью рабочая Istio service mesh с демо-приложением из нескольких микросервисов внутри. Создаем config map для кода wasm Создаем config map, где будет размещаться код WASM для нашего фильтра, в неймспейс backyards-demo, где запущено демо (прим. переводчика:либо bookinfo в случае использования чистого Istio). kubectl create cm -n backyards-demo example-filter --from-file=example-filter.wasm
Внедряем код wasm в демо с помощью Istio ︎
sidecar.istio.io/userVolume: '[{"name":"wasmfilters-dir","configMap": {"name": "example-filter"}}]'
sidecar.istio.io/userVolumeMount: '[{"mountPath":"/var/local/lib/wasm-filters","name":"wasmfilters-dir"}]'
kubectl scale deployment -n backyards-demo frontpage-v1 --replicas=1
kubectl patch deployment -n backyards-demo frontpage-v1 -p '{"spec":{"template":{"metadata":{"annotations":{"sidecar.istio.io/userVolume":"[{"name":"wasmfilters-dir","configMap": {"name": "example-filter"}}]","sidecar.istio.io/userVolumeMount":"[{"mountPath":"/var/local/lib/wasm-filters","name":"wasmfilters-dir"}]"}}}}}' Теперь код фильтра WASM доступен в /var/local/lib/wasm-filters в контейнере istio-proxy: kubectl exec -n backyards-demo -it deployment/frontpage-v1 -c istio-proxy -- ls /var/local/lib/wasm-filters/
example-filter.wasm
kubectl port-forward -n backyards-demo deployment/frontpage-v1 15000
curl -XPOST "localhost:15000/logging?wasm=debug"
kubectl apply -f-<<EOF
apiVersion: networking.istio.io/v1alpha3 kind: EnvoyFilter metadata: name: frontpage-v1-examplefilter namespace: backyards-demo spec: configPatches: - applyTo: HTTP_FILTER match: context: SIDECAR_INBOUND proxy: proxyVersion: '^1\.5.*' listener: portNumber: 8080 filterChain: filter: name: envoy.http_connection_manager subFilter: name: envoy.router patch: operation: INSERT_BEFORE value: config: config: name: example-filter rootId: my_root_id vmConfig: code: local: filename: /var/local/lib/wasm-filters/example-filter.wasm runtime: envoy.wasm.runtime.v8 vmId: example-filter allow_precompiled: true name: envoy.filters.http.wasm workloadSelector: labels: app: frontpage version: v1 EOF Примечание. При тестировании мы обнаружили, что фильтр portNumber, указанный для listener match в кастомном ресурсе EnvoyFilter, некорректно обрабатывался в Istio, поэтому хуки для фильтра не вызывались. Мы исправили эту проблему в нашем дистрибутиве Istio — Backyards.
kubectl run curl --image=yauritux/busybox-curl --restart=Never -it --rm sh
/home # curl -L -v http://frontpage.backyards-demo:8080 Мы ожидаем увидеть заголовок фильтра, добавленный к заголовку ответа:SPL* About to connect() to frontpage.backyards-demo port 8080 (#0)
* Trying 10.10.178.38... * Adding handle: conn: 0x10eadbd8 * Adding handle: send: 0 * Adding handle: recv: 0 * Curl_addHandleToPipeline: length: 1 * - Conn 0 (0x10eadbd8) send_pipe: 1, recv_pipe: 0 * Connected to frontpage.backyards-demo (10.10.178.38) port 8080 (#0) > GET / HTTP/1.1 > User-Agent: curl/7.30.0 > Host: frontpage.backyards-demo:8080 > Accept: */* > < HTTP/1.1 200 OK < content-type: text/plain < date: Thu, 16 Apr 2020 16:32:20 GMT < content-length: 9 < x-envoy-upstream-service-time: 10 < resp-header-demo: added by our filter < x-envoy-peer-metadata: CjYKDElOU1RBTkNFX0lQUxImGiQxMC4yMC4xLjU3LGZlODA6OmQwNDM6NDdmZjpmZWYwOmVkMjkK2QEKBkxBQkVMUxLOASrLAQoSCgNhcHASCxoJZnJvbnRwYWdlCiEKEXBvZC10ZW1wbGF0ZS1oYXNoEgwaCjU3OGM2NTU0ZDQKJAoZc2VjdXJpdHkuaXN0aW8uaW8vdGxzTW9k ZRIHGgVpc3RpbwouCh9zZXJ2aWNlLmlzdGlvLmlvL2Nhbm9uaWNhbC1uYW1lEgsaCWZyb250cGFnZQorCiNzZXJ2aWNlLmlzdGlvLmlvL2Nhbm9uaWNhbC1yZXZpc2lvbhIEGgJ2MQoPCgd2ZXJzaW9uEgQaAnYxChoKB01FU0hfSUQSDxoNY2x1c3Rlci5sb2NhbAonCgROQU1FEh8aHWZyb250cGFnZS12MS01N zhjNjU1NGQ0LWxidnFrCh0KCU5BTUVTUEFDRRIQGg5iYWNreWFyZHMtZGVtbwpXCgVPV05FUhJOGkxrdWJlcm5ldGVzOi8vYXBpcy9hcHBzL3YxL25hbWVzcGFjZXMvYmFja3lhcmRzLWRlbW8vZGVwbG95bWVudHMvZnJvbnRwYWdlLXYxCi8KEVBMQVRGT1JNX01FVEFEQVRBEhoqGAoWCgpjbHVzdGVyX2lkEg gaBm1hc3RlcgocCg9TRVJWSUNFX0FDQ09VTlQSCRoHZGVmYXVsdAofCg1XT1JLTE9BRF9OQU1FEg4aDGZyb250cGFnZS12MQ== < x-envoy-peer-metadata-id: sidecar~10.20.1.57~frontpage-v1-578c6554d4-lbvqk.backyards-demo~backyards-demo.svc.cluster.local < x-by-metadata: CjYKDElOU1RBTkNFX0lQUxImGiQxMC4yMC4xLjU3LGZlODA6OmQwNDM6NDdmZjpmZWYwOmVkMjkK2QEKBkxBQkVMUxLOASrLAQoSCgNhcHASCxoJZnJvbnRwYWdlCiEKEXBvZC10ZW1wbGF0ZS1oYXNoEgwaCjU3OGM2NTU0ZDQKJAoZc2VjdXJpdHkuaXN0aW8uaW8vdGxzTW9kZRIHGgVp c3RpbwouCh9zZXJ2aWNlLmlzdGlvLmlvL2Nhbm9uaWNhbC1uYW1lEgsaCWZyb250cGFnZQorCiNzZXJ2aWNlLmlzdGlvLmlvL2Nhbm9uaWNhbC1yZXZpc2lvbhIEGgJ2MQoPCgd2ZXJzaW9uEgQaAnYxChoKB01FU0hfSUQSDxoNY2x1c3Rlci5sb2NhbAonCgROQU1FEh8aHWZyb250cGFnZS12MS01NzhjNjU1N GQ0LWxidnFrCh0KCU5BTUVTUEFDRRIQGg5iYWNreWFyZHMtZGVtbwpXCgVPV05FUhJOGkxrdWJlcm5ldGVzOi8vYXBpcy9hcHBzL3YxL25hbWVzcGFjZXMvYmFja3lhcmRzLWRlbW8vZGVwbG95bWVudHMvZnJvbnRwYWdlLXYxCi8KEVBMQVRGT1JNX01FVEFEQVRBEhoqGAoWCgpjbHVzdGVyX2lkEggaBm1hc3 RlcgocCg9TRVJWSUNFX0FDQ09VTlQSCRoHZGVmYXVsdAofCg1XT1JLTE9BRF9OQU1FEg4aDGZyb250cGFnZS12MQ== * Server istio-envoy is not blacklisted < server: istio-envoy < x-envoy-decorator-operation: frontpage.backyards-demo.svc.cluster.local:8080/* < * Connection #0 to host frontpage.backyards-demo left intact frontpage
kubectl apply -f-<<EOF
apiVersion: networking.istio.io/v1alpha3 kind: EnvoyFilter metadata: name: frontpage-v1-examplefilter namespace: backyards-demo spec: configPatches: - applyTo: NETWORK_FILTER match: context: SIDECAR_INBOUND proxy: proxyVersion: '^1\.5.*' listener: portNumber: 8083 filterChain: filter: name: "envoy.tcp_proxy" patch: operation: INSERT_BEFORE value: config: config: name: example-filter rootId: my_root_id vmConfig: code: local: filename: /var/local/lib/wasm-filters/example-filter.wasm runtime: envoy.wasm.runtime.v8 vmId: example-filter allow_precompiled: true name: envoy.filters.network.wasm workloadSelector: labels: app: frontpage version: v1 EOF Если мы добавили фильтр в цепочку на уровне TCP, вызываются только хуки для TCP-трафика. Вот наглядная схема того, как это работает с Istio: Пишем фильтры WASM для Envoy с WASME ︎ Solo.io предложили решение для разработки фильтров WASM для Envoy — WebAssembly Hub, чтобы загружать и выгружать свои коды фильтров WASM. Используйте инструмент WASME для скаффолдинга, сборки и отправки фильтров WASM в WebAssembly Hub. При деплое фильтра WASM wasme вытаскивает образ с плагином фильтра WASM из WebAssembly Hub, запускает daemonset, чтобы извлечь код плагина WASM из этого образа, и открывает его для Envoy Proxy на каждой ноде через тома hostPath. Примечание. Образы из WebAssembly Hub не будут отображаться как стандартные образы Docker. Правда, тут мы публикуем и храним фильтры WASM в стороннем хранилище (WebAssembly Hub), так что этот вариант вам не подойдет, если из-за строгих политик безопасности или по другой причине вы не хотите обнародовать проприетарный код, даже в бинарном формате, за пределами корпоративной сети. Заключение ︎ С фильтрами WASM для Envoy можно написать свой код, скомпилировать его в плагины WASM и настроить Envoy для его выполнения. Плагины могут содержать произвольную логику, поэтому подходят для любых интеграций и изменений в сообщениях. Так что фильтры WASM для Envoy Proxy — это идеальный способ интегрировать любую логику в сетевое взаимодействие. =========== Источник: habr.com =========== =========== Автор оригинала: Toader Sebastian ===========Похожие новости:
Блог компании Southbridge ), #_sistemnoe_administrirovanie ( Системное администрирование ), #_itinfrastruktura ( IT-инфраструктура ), #_devops, #_mikroservisy ( Микросервисы ) |
|
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 14:33
Часовой пояс: UTC + 5