Service mesh, работающий через iptables

Воображаемое распределённое приложение подключённое к service mesh
Воображаемое распределённое приложение, подключённое к service mesh

В общем, в прошлый раз я упомянул, что другой, совместимый с Kubernetes сервис меш — Conduit, работает по иному принципу. В отличие от Linkerd, он не устанавливает прокси на каждую машину и не заставляет клиентов общаться с ним, задав переменную окружения http_proxy. Этот кадр мало того, что подключает клиентские сервисы к мешу по-одному, так ещё и совсем другим способом. Мне нравятся такие идеи, ставящие всё с ног на голову, так что я решил разобрать Conduit на части и посмотреть, что же там у него внутри.

Ещё раз, кто такой Conduit?

Как я упомянул абзацем выше, Conduit — это сервис меш для Kubernetes. То есть это компонент, который вместо того, чтобы разрешать сервисам приложения общаться по сети друг с другом напрямую, пропускает весь траффик через себя и даёт некоторые плюшки взамен. Например, статистику по таймингам  и успешности запросов, балансировщик нагрузки, перенаправление траффика, логи и кучи других приятностей, которые мешам полагается раздавать.

Установка

Ставится Conduit очень просто. Во-первых, нужно скачать бинарник (есть даже скрипт для этого) и добавить его в PATH:

Во-вторых, добавить панель управления в Kubernetes-кластер (или тот же minikube), что делается ещё одной командой:

Препарируем скрипт установки

Прежде чем идти дальше, я хочу заглянуть внутрь conduit install , который, походу, просто генерирует YAML конфигурацию для kubectl apply. Интересно же.

Круть! Кроме создания аккаунтов, сервисов и деплойментов там внутри встречаются имена Prometheus и Grafana, так что я уже догадываюсь, на что будет похож дашборд и как они собирают метрики.

Смотрим на дашборд

Конечно, данных там не будет, но всё-таки интересно, как он выглядит. Команда conduit dashboard поможет:

Conduit dashboard

Ха! Всё запустилось и всё работает. Самая интересная часть — внизу. Там написано, что из четырёх пространств имён в текущем кластере, одно — conduit — полностью подключено к сервис мешу. Ещё два — пустые, и одно — kube-system — не подключено никак.

meshed-namespaces

То есть Conduit мониторит сам себя? Уважаю. Это так же означает, что хоть какая-то статистика внутри уже должна быть. Кликаем и смотрим…

Service mesh statistics for given mamespace

Да! Что-то есть. Метрики для деплойментов и подов. Хакей, посмотрим, например, на статистику для деплоймента grafana поближе:

service mesh statistics for given deployment

Grafana, показывающая статистику для деплоймента grafana… Ну не рекурсия ли?

Подключаем поды к сети

Вернёмся-ка мы назад на главную страницу, к списку подключённых и неподключённых пространств имён.

Meshed namespaces

Как мы уже поняли,  conduit подключён полностью,  default и kube-public — пустые, но в kube-system есть аж девять подов и ни один из низ не подключён к мешу. В продакшене я такое вряд ли бы делал, но что если подключить что-нибудь из kube-system к conduit?

Подключение к мешу делается через командную строку (наверняка есть и API какой-нибудь), через conduit inject. На вход ему подаётся YAML конфигурация объекта (например, pod или деплоймент), а на выходе получается та же конфигурация, но настроенная так, чтобы её исходящий траффик шёл через меш. Прежде, чем я что-нибудь начну подключать, хочется выяснить, как же именно меняется конфигурация.

Сравнимаем YAML до и после

В пространстве имён kube-system есть два деплоймента для экспериментов: kube-dns и kubernetes-dashboard.

Я сохранил начальную конфигурацию kube-dns в файле before.yml:

Пропущенную через conduit inject — в after.yml:

И пропустил это всё через vim diff:

Injected containers

И какая ж это красота! В общем, conduit добавил в шаблон для пода два новых контейнера. Первый — постоянный, через который, я так полагаю, траффик и будет пропускаться наверх (gcr.io/runconduit/proxy:v0.4.2, строка 189). Второй же — Init Контейнерgcr.io/runconduit/proxy-init:v0.4.2, строка 211 — делает начальную настройку, и я очень хочу заглянуть ему внутрь.

Ну вот почти кроличья нора

Буквально первый гугловый результат сдал мне Dockerfile для proxy-init образа как стеклотару.

Хм. То есть внутренности написаны на Go. Это приятно. Что ещё приятнее, никакого http_proxy внутри них не встречается. Зато есть iptables. Вот, оказывается, как они собирают траффик из сервисов в свой сервис меш. Кстати, сырцы для второго Докер образа — proxy — лежат неподалёку и  написаны на  Rust. Один язык для одной задачи, чего уж там.

Подключаем kube-system к мешу

Моё любопытство пока удовлетворено, так что наступило время подключать деплойменты неймспейса к мешу.

И-и-и-и-и оно работает! Частично, но всё-таки. kubernetes-dashboard, походу, догадался, что его надругали, и откатил свою конфигурация назад (сам, или кто-то из его начальников). А вот kube-dns подчинился:

System namespace wired to the service mesh

kube-dns mesh statistics

Бонус: командная строка

Conduit, кстати, неплохо поддерживает командную строку. Эта самая статистика, которую мы только что видели в Grafana, есть и в консоли:

Что ещё круче, можно даже посмотреть данные по индивидуальным запросам. Вот, что, например, бегает по проводам в kube-dns деплойменте? А я знаю.

Красотень.

Мораль

Вот такой он, Conduit. Как и в случае с Linkerd или даже сервис мешами в целом, мой мир не пошатнулся и не обрёл истину. Но мне нравятся красивые идеи и их имплементация, и это как раз тот случай. И, как оказалось, удивительно много можно узнать просто заглянув в чужие сырцы. Смешивание языков программирования работает не только в теории, Rust ещё жив, Init Контейнеры прекрасны, iptables — тоже. И ведь это только пара наблюдений. А вот теперь мне интересно, делал ли кто-нибудь бенчмаркинг того, как меш влияет на производительность сети. Вот уверен, как только я попробую продать идею мешей начальству, именно об этом они и спросят в первую очередь.

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *