что такое sidecar в openshift
Как этот sidecar-контейнер оказался здесь [в Kubernetes]?
Прим. перев.: Этой статьёй, написанной Scott Rahner — инженером в Dow Jones, мы продолжаем цикл многочисленных материалов, доступно рассказывающих о том, как устроен Kubernetes, как работают, взаимосвязаны и используются его базовые компоненты. На сей раз это практическая заметка с примером кода для создания хука в Kubernetes, демонстрируемого автором «под предлогом» автоматического создания sidecar-контейнеров.
(Автор фото — Gordon A. Maxwell, найдено на просторах интернета.)
Когда я начал изучать sidecar-контейнеры и service mesh’и, мне потребовалось разобраться в том, как работает ключевой механизм — автоматическая вставка sidecar-контейнера. Ведь в случае использования систем вроде Istio или Consul, при деплое контейнера с приложением внезапно в его pod’е появляется и уже настроенный контейнер Envoy (схожая ситуация происходит и у Conduit, о котором мы писали в начале года — прим. перев.). Что? Как? Так начались мои исследования…
Для тех, кто не знает, sidecar-контейнер — контейнер, который деплоится рядом с контейнерами приложения, чтобы каким-либо образом «помогать» этому приложению. Примером такого использования может служить прокси для управления трафиком и завершения TLS-сессий, контейнер для стриминга логов и метрик, контейнер для сканирования проблем в безопасности… Идея в том, чтобы изолировать различные аспекты всего приложения от бизнес-логики с помощью применения отдельных контейнеров для каждой функции.
Перед тем, как продолжить, обозначу свои ожидания. Цель этой статьи — не объяснить хитросплетения и сценарии использования Docker, Kubernetes, service mesh’ей и т.п., а наглядно показать один мощный подход к расширению возможностей этих технологий. Статья — для тех, кто уже знаком с применением данных технологий или, по крайней мере, немало о них прочитал. Чтобы попробовать практическую часть в действии, потребуется машина с уже настроенными Docker и Kubernetes. Простейший способ для этого — https://docs.docker.com/docker-for-windows/kubernetes/ (инструкция для Windows, которая работает и в Docker for Mac). (Прим. перев.: В качестве альтернативы пользователям Linux и *nix-систем можем предложить Minikube.)
Общая картина
Для начала давайте немного разберёмся с Kubernetes:
Kube Arch, лицензированная под CC BY 4.0
Когда вы собираетесь задеплоить что-либо в Kubernetes, необходимо отправить объект в kube-apiserver. Чаще всего это делают передачей аргументов или YAML-файла в kubectl. В таком случае сервер API перед тем, как непосредственно помещать данные в etcd и планировать соответствующие задания, проходит через несколько этапов:
Эта последовательность важна, чтобы разобраться, как работает вставка sidecar-контейнеров. В частности, нужно обратить внимание на Admission Control, в рамках которого Kubernetes валидирует и, если необходимо, модифицирует объекты перед тем, как сохранять их (подробнее об этом этапе см. в главе «Контроль допуска» этой статьи — прим. перев.). Kubernetes также позволяет регистрировать webhooks, которые могут выполнять определяемую пользователем валидацию и изменения (mutations).
Однако процесс создания и регистрации своих хуков не так-то уж прост и хорошо документирован. Мне пришлось потратить несколько дней на чтение и перечитывание документации, а также на анализ кода Istio и Consul. А когда дело дошло до кода для некоторых из ответов API, я провёл не менее половины дня на выполнение случайных проб и ошибок.
После того, как результат был достигнут, думаю, что будет нечестно не поделиться им со всеми вами. Он простой и в то же время действенный.
Название webhook говорит само за себя — это HTTP endpoint, реализующий API, определённый в Kubernetes. Вы создаёте API-сервер, который Kubernetes может вызывать перед тем, как разбираться с Deployment’ами. Здесь мне пришлось столкнуться со сложностями, поскольку доступны всего несколько примеров, некоторые из которых — просто unit-тесты Kubernetes, другие — спрятаны посреди огромной кодовой базы… и все написаны на Go. Но я выбрал более доступный вариант — Node.js:
Deployment
Хорошо, у нас есть код, который принимает запросы от API-сервера Kubernetes и отвечает на них, но как его задеплоить? И как заставить Kubernetes перенаправлять нам эти запросы? Развернуть такой endpoint можно везде, до чего может «достучаться» API-сервер Kubernetes. Простейшим способом является деплой кода в сам кластер Kubernetes, что мы и сделаем в данного примере. Я постарался сделать пример максимально простым, поэтому для всех действий использую лишь Docker и kubectl. Начнём с создания контейнера, в котором будет запускаться код:
Как видно, тут всё очень просто. Возьмите образ с node от сообщества и забросьте в него код. Теперь можно выполнить простую сборку:
Следующим шагом создадим Deployment в Kubernetes:
Заметили, как мы сослались на только что созданный образ? Так же просто тут мог быть и pod, и что-либо иное, к чему мы можем подключить сервис в Kubernetes. Теперь определим этот Service:
Так в Kubernetes появится endpoint с внутренним именем, который указывает на наш контейнер. Финальный шаг — сообщить Kubernetes’у, что мы хотим, чтобы API-сервер вызывал этот сервис, когда он готов производить изменения (mutations):
Название и путь здесь могут быть любыми, но я постарался сделать их настолько осмысленными, насколько возможно. Изменение пути будет означать необходимость модификации соответствующего кода в JavaScript. Важен и webhook failurePolicy — он определяет, должен ли объект сохраняться, если хук возвращает ошибку или не срабатывает. Мы в данном случае говорим Kubernetes’у не продолжать обработку. Наконец, правила ( rules ): они будут меняться в зависимости от того, на какие вызовы API вы ожидаете действий от Kubernetes. В данном случае, поскольку мы пытаемся эмулировать вставку sidecar-контейнера, нам требуется перехват запросов на создание pod’а.
Вот и всё! Так просто… но что насчёт безопасности? RBAC — это один из аспектов, который не затронут в статье. Я предполагаю, что вы запускаете пример в Minikube или же в Kubernetes, что идёт в поставке Docker for Windows/Mac. Однако расскажу ещё об одном необходимом элементе. API-сервер Kubernetes обращается только к endpoint’ам с HTTPS, поэтому для приложения потребуется наличие SSL-сертификатов. Также потребуется сообщить Kubernetes’у, кто является удостоверяющим центром корневого сертификата.
Только для демонстрационных целей(. ) я добавил в Dockerfile немного кода, чтобы создать root CA и воспользоваться им для подписи сертификата:
Теперь код поддерживает запуск HTTPS, а также сообщил Kubernetes’у, где найти нас и какому удостоверяющему центру доверять. Осталось лишь задеплоить всё это в кластер:
Резюмируем
Попробуем в деле!
Всё развёрнуто в кластере — время попробовать код в действии, что мы сделаем добавлением нового pod/Deployment. Если всё работает правильно, хук должен будет добавить дополнительный лейбл foo :
Серия постов по Istio Service Mesh
Мы начинаем серию постов, в которой продемонстрируем некоторые из множества возможностей сервисной сетки Istio Service Mesh в сочетании с Red Hat OpenShift и Kubernetes.
Часть первая, сегодняшняя:
Инструментарий мониторинга и управления Istio – все необходимое для координации микросервисов в сервисной сетке service mesh.
Что такое сервисная сетка Istio
Сервисная сетка реализует для группы сервисов такие функции, как мониторинг трафика, контроль доступа, обнаружение, безопасность, отказоустойчивость и другие полезные вещи. Istio позволяет сделать все это без малейших изменений в коде самих сервисов. В чем секрет волшебства? Istio цепляет к каждому сервису свой прокси в виде sidecar-контейнера (sidecar – мотоциклетная коляска), после чего весь трафик к этому сервису идет через прокси, который, руководствуясь заданными политиками, решает как, когда и должен ли вообще этот трафик дойти до сервиса. Istio также дает возможность реализовать продвинутые техники DevOps, такие как canary deployments, circuit breakers, fault injection и многие другие.
Как Istio работает с контейнерами и Kubernetes
Сервисная сетка Istio – это sidecar’ная реализация всего того, что требуется для создания и управления микросервисами: мониторинг, трассировка, circuit breakers, маршрутизация, балансировка нагрузки, fault injection, повторы, тайм-ауты, зеркалирование, контроль доступа, ограничение скорости и многое другое. И хотя сегодня есть масса библиотек, чтобы реализовать эти функции непосредственно в коде, с Istio вы можете получить все то же самое, ничего не меняя в своем коде.
Согласно sidecar’ной модели, Istio выполняется в Linux-контейнере, который располагается в одном Kubernetes-pod’е с контролируемым сервисом и внедряет (inject) и извлекает (extract) функциональность и информацию согласно заданной конфигурации. Подчеркнем, это ваша собственная конфигурация, и она живет вне вашего кода. Поэтому код становится гораздое проще и короче.
Что еще важно, операционная составляющая микросервисов при этом оказывается никак не связана с самим кодом, а значит их эксплуатацию можно спокойно передать ИТ-специалистам. В самом деле, почему разработчик должен отвечать за circuit breaker’ы и fault injection? Реагировать – да, но обрабатывать их и создавать? Если убрать всё этого из кода, программисты смогут полностью сосредоточиться на прикладном функционале. Да и сам код станет короче и проще.
Сервисная сетка
Istio, реализующий функции управления микросервисами вне их кода – это и есть концепция сервисной сетки Service Mesh. Иначе говоря, это скоординированная группа из одного или нескольких бинарников, которые образуют сетку сетевых функций.
Как Istio работает с микросервисами
Вот как выглядит работа sidecar-контейенров с связке с Kubernetes и Minishift с высоты птичьего полета: запускаете экземпляр Minishift, создаете проект для Istio (назовем его «istio-system»), устанавливаете и запускаете все связанные с Istio компоненты. Затем, по мере создания проектов и pod’ов, добавляете конфигурационные сведения в свои deployment’’ы, и ваши pod’ы начинают использовать Istio. Упрощенно диаграмма выглядит так:
Теперь можно изменять настройки Istio, чтобы, например, организовать fault injection, поддержку Canary Deployment или другие возможности Istio – и все это совершенно не трогая код самих приложений. Допустим, вы хотите перенаправить весь веб-трафик от пользователей своего крупнейшего клиента (Foo Corporation) на новую версию сайта. Для этого достаточно создать правило маршрутизации Istio, которое будет искать @foocorporation.com в идентификаторе пользователя и выполнять соответствующее перенаправление. Для всех остальных пользователей ничего не изменится. А вы тем временем будете спокойно тестировать новую версию сайта. И заметьте, для этого совершенно не надо привлекать разработчиков.
И дорого за это придется заплатить?
Отнюдь. Istio работает довольно быстро, он написан на Go и создает совсем небольшой оверхед. Кроме того, возможный проигрыш в онлайн-производительности компенсируется приростом производительности труда разработчиков. По крайней мере, в теории: не забывайте, что время разработчиков стоит дорого. Что касается затрат на ПО, то Istio – это софт с открытым кодом, поэтому получить и использовать его можно бесплатно.
Освойте сами
Команда Red Hat Developer Experience Team разработала углубленное практическое руководство по Istio (на английском). Оно работает на Linux, MacOS и Windows, а код представлен в вариантах на Java и Node.js.
10 интерактивных занятий по Istio
Блок 1 — Для начинающих
Введение в Istio
30 минут
Знакомимся с Service Mesh, учимся устанавливать Istio в Kubernetes кластере OpenShift.
Начать
Развертывание микросервисов в Istio
30 минут
Используем Istio, чтобы развернуть три микросервиса с Spring Boot и Vert.x.
Начать
Блок 2 – средний уровень
Мониторинг и трассировка в Istio
60 минут
Изучаем встроенные средства мониторинга Istio, настраиваемые метрики, а также OpenTracing через Prometheus и Grafana.
Начать
Простая маршрутизация в Istio
60 минут
Учимся управлять маршрутизацией в Istio с помощью простых правил.
Начать
Расширенные правила маршрутизации
60 минут
Знакомимся с умной маршрутизацией в Istio, управлением доступом, балансировкой нагрузки и ограничением скорости.
Начать
Блок 3 – опытный пользователь
Fault Injection в Istio
60 минут
Изучаем сценарии обработки отказов в распределенных приложений, создавая ошибки HTTP и сетевые задержки, учимся применять хаос-инжиниринга для восстановления среды.
Начать
Circuit Breaker в Istio
30 минут
Устанавливаем Siege для стресс-тестирования сайтов и учимся обеспечить отказоустойчивость бэкенда с помощью повторов, circuit breaker и pool ejection.
Начать
Egress и Istio
10 минут
Используем маршруты Egress для создания правил взаимодействия внутренних сервисов с внешними API и сервисами.
Начать
Istio и Kiali
15 минут
Учимся использовать Kiali для получения общей картины сервисной сетки и изучения потоков запросов и данных.
Начать
Mutual TLS в Istio
15 минут
Создаем Istio Gateway и VirtualService, затем подробно изучаем mutual TLS (mTLS) и его настройки.
Начать
Блок 3.1 — Глубокое погружение: Istio Service Mesh для микросервисов
Серия статей по сервисным сеткам и Istio
Попробуйте сами
Эта серия постов не ставит целью обеспечить глубокое погружение в мир Istio. Мы просто хотим познакомить вас с самой концепцией и, может быть, вдохновить самостоятельно попробовать Istio. Это можно сделать совершенно бесплатно, и Red Hat предоставляет все необходимые инструменты, чтобы начать осваивать OpenShift, Kubernetes, Linux-контейнеры и Istio, а именно: Red Hat Developer OpenShift Container Platform, наше руководство по Istio и другие ресурсы на нашем микро-сайте по Service Mesh. Не стоит откладывать, начните прямо сегодня!
Правила маршрутизации Istio: направляем сервис-запросы туда, куда нужно
OpenShift и Kubernetes прекрасно справляются с тем, чтобы обращения к микросервисам маршрутизировались к нужным pod’ам. В этом и есть одна из целей существования Kubernetes – маршрутизация и балансировка нагрузки. А что, если вам нужна более тонкая и изощренная маршрутизация? Например, чтобы одновременно использовать две версии микросервиса. Как здесь помогут правила маршрутизации Istio Route Rules?
Правила маршрутизации – это правила, которые, собственно, задают выбор маршрута. При любом уровне сложности системы общий принцип работы этих правил остается простым: запросы маршрутизируются на основе определенных параметров и значений заголовков HTTP.
Посмотрим на примерах:
Kubernetes умолчанию: тривиальное «50 на 50»
В нашем примере мы покажем, как одновременно использовать в OpenShift две версии микросервиса, назовем их v1 и v2. Каждая версия запускается в собственном pod’е Kubernetes, и по умолчанию здесь работает равномерно сбалансированная циклическая маршрутизация (evenly balanced round robin routing). Каждый pod получает свою долю запросов по числу его экземпляров микросервиса, иначе говоря, реплик. Istio же позволяет поменять этот баланс вручную.
Допустим, мы развернули на OpenShift две версии нашего рекомендационного сервиса, recommendation-v1 и recommendation-v2.
На рис. 1 видно, что, когда каждый сервис представлен в одном экземпляре, запросы равномерно чередуются между ними: 1-2-1-2-… Именно так маршрутизация Kubernetes работает по умолчанию:
Взвешенное распределение между версиями
Игнор версии с помощью Istio
Istio позволяет легко изменить распределение запросов нужным нам образом. Например, отправлять весь трафик только на recommendation-v1 с помощью следующего yaml-файла Istio:
Здесь надо обратить внимание вот на что: pod’ы выбираются согласно меткам. В нашем примере используется метка v1. Параметр «weight: 100» означает, что 100% трафика будет маршрутизироваться на все pod’ы сервиса, у которых есть метка v1.
Директивное распределение между версиями (Canary Deployment)
Далее, используя параметр weight, можно направлять трафик к обоим pod’ам, игнорируя количество экземпляров микросервисов, запущенных в каждом из них. Например, здесь мы директивно направляем 90% трафика на v1 и 10% – на v2:
Отдельная маршрутизация мобильных пользователей
В заключение покажем, как принудительно маршрутизировать трафик мобильных пользователей на сервис v2, а всех остальных – на v1. Для этого мы помощью регулярных выражений анализируем значение user-agent в заголовке запроса:
Теперь ваша очередь
Пример с регулярными выражениями для анализа заголовков должен мотивировать вас на поиск собственных вариантов применения правил маршрутизации Istio. Тем более что возможности здесь открываются весьма обширные, поскольку значения заголовков можно формировать в исходном коде приложений.
И помните, что Ops, а не Dev
Всё, что мы показали в примерах выше, делается без малейших изменений в исходном коде, ну за исключением тех случаев, когда надо формировать особые заголовки запросов. Istio пригодится как разработчикам, которые, например, смогут применять его на этапе тестировании, так и специалистам по эксплуатации ИТ-систем, которым он сильно поможет в продакшне.
Так что повторим лейтмотив этой серии постов: вам не надо ничего менять в своем коде. Не нужно собирать новые образы или запускать новые контейнеры. Все это реализуется вне кода.
Включите воображение
Только представьте, какие перспективы открывает анализ заголовков с помощью регулярных выражений. Хотите перенаправлять вашего крупнейшего клиента на специальную версию своих микросервисов? Легко! Нужна отдельная версия для браузера Chrome? Не проблема! Вы можете маршрутизировать трафик практически по любой его характеристике.
Kubernetes — изучаем паттерн Sidecar
Объяснение паттерна Sidecar на примере
Под, содержащий один контейнер, относится к одно-контейнерным подам и это самый распространенный вариант их использования в Kubernetes. Под, который содержит несколько связанных контейнеров, относится к мульти-контейнерным подам. Есть несколько паттернов для мульти-контейнерных подов и один из них — это паттерн sidecar. В этом посте мы на примере проекта детально рассмотрим этот паттерн.
Что такое контейнер Sidecar
Другие паттерны
Пример
Тестируем с объектом Deployment
Как настроить ресурсные ограничения Resource Limits
Когда мы должны использовать этот паттерн
Заключение
Что такое Sidecar-контейнер
Sidecar-контейнер — это контейнер, который должен быть запущен рядом с основным контейнером внутри пода. Этот паттерн нужен для расширения и улучшения функциональности основного приложения без внесения в него изменений. Сейчас мы знаем, что технология контейнеризации позволяет собирать все зависимости, чтобы мы могли запустить приложение где угодно. Контейнер делает только одну вещь и делает её хорошо.
Представьте, что у вас есть под с одним контейнером, который очень хорошо работает, и вы бы хотели добавить какой-то функционал к этому контейнеру, не внося в него изменений. Как тогда можно добавить или расширить для него какие-то функции? Паттерн Sidecar может помочь именно в такой ситуации.
На диаграмме выше видно, как вы можете создать любое количество Sidecar контейнеров и ваш основной контейнер будет успешно с ними взаимодействовать. Все контейнеры работают параллельно и полный функционал будет доступен только если каждый из контейнеров успешно запущен. В большинстве случаев sidecar-контейнеры просты и легковесны и потребляют намного меньше ресурсов чем основной контейнер.
Другие паттерны
Вот некоторые другие паттерны, которые можно использовать для повседневной работы в Kubernetes:
Пример проекта
Здесь пример проекта, который вы можете скопировать и запустить на своих мощностях. Предварительно вам нужно установить Minikube.
Давайте запустим простой проект, чтобы понять как работает этот паттерн. Здесь под, в котором есть основной и sidecar контейнеры. Основной контейнер это Nginx, слушающий на порту 80, который отдает страницу index.html из volume, примонтированного в location workdir. И sidecar-контейнер с образом busybox, который пишет лог с timestamp в тот же самый файл. Так как sidecar-контейнер и основной контейнер запущены параллельно, Nginx будет показывать новую информацию каждый раз, когда вы делаете обращение через браузер.
Вы можете установить curl и сделать запрос на localhost, чтобы проверить ответ сервера.
Тестирование Sidecar Container
Тестирование с объектом Deployment
Давайте создадим сущность deployment с тем же определением подов и 5 репликами. Я создал service с типом порта NodePort, чтобы мы могли получить доступ к deployment через браузер. Поды создаются динамически и поддержкой заданного состояния всегда занимается deployment controller, поэтому у вас не может быть одного статического IP для доступа к поду, вместо этого вам нужно создать сущность service, которая будет открывать определенный порт во внешний мир. Внутри кластера service перенаправляет запросы извне на 80 порт контейнеров с соответствующими селекторами (тут много изменений оригинального текста). Вы увидите как это работает через некоторое время.
Deployment
Теперь давайте посмотрим на приведенный ниже deployment, в котором мы определили один основной контейнер и два sidecar-контейнера. Все контейнеры работают параллельно. Два sidecar-контейнера пишут лог в директорию /var/log. Основной контейнер с Nginx будет отдавать эти файлы, когда мы будем подключаться к порту 80. Вы увидите это в действии через некоторое время.
И выполним следующие команды, чтобы протестировать deployment.
deployment в действии
На диаграмме выше вы можете видеть 5 подов, запущенных на разных IP-адресах и service, связывающие порты 32123 и 80. Вы можете получить доступ к этому deployment из браузера через IP ворке-ноды Kubernetes 192.168.64.2 и через порт сервиса 32123:
Вы также можете протестировать под следующими командами:
Паттерн Sidecar в действии
Как настроить ограничения ресурсов
Настроить ограничения ресурсов очень важно, если речь идет о sidecar-контейнерах. Главное, что нам нужно понять, это то, что все контейнеры работают параллельно, поэтому при настройке ограничений ресурсов для пода вы должны это учитывать.
Суммировать все ограничения ресурсов для основных контейнеров, а также для дополнительных контейнеров (поскольку все контейнеры работают параллельно).
Когда нам нужно использовать этот паттерн
Вот несколько сценариев, в которых вы можете использовать этот паттерн:
Всегда, когда вы хотите дополнить функционал уже существующего единичного контейнера без внесения в него изменений
Вы можете использовать этот контейнер для синхронизации кода основного контейнера с кодом на git-сервере используя pull.(You can use this pattern to synchronize the main container code with the git server pull.)
Вы можете использовать этот контейнер, чтобы отправлять логи основного контейнера на внешний сервер.
Вы можете использовать этот контейнер для задач, связанных с установлением сети (network-related tasks.).
Под, который содержит один контейнер, относится к одно-контейнерному поду и это самый распространенный шаблон его использования.
Под, содержащий несколько взаимосвязанных контейнеров, относится к мульти-контейнерному поду.
Sidecar-контейнер запускается параллельно с основным контейнером. Поэтому вам нужно учитывать ограничения ресурсов для sidecar-контейнера прежде, чем вы задаете запросы/ограничения ресурсов для пода.
Контейнер с приложением и Sidecar-контейнер запускаются параллельно, что значит, что они будут работать в одно и то же время. Поэтому вам нужно суммировать все запросы/ограничения ресурсов для контейнеров, прежде чем задавать запросы/ограничения ресурсов для подов.
Вам нужно настроить health checks для sidecar-контейнеров так же, как и для основных контейнеров, что бы быть уверенными, что они в порядке.
Все поды, порожденные deployment не имеют статического IP-адреса, поэтому вам нужно создать сущность service, чтобы дать к ним доступ из внешнего мира.
Сущность service перенаправляет трафик внутри кластера с внешних портов на порты контейнера в соответствии с выбранными селекторами.
Заключение
Знать проверенные временем паттерны в kubernetes полезно. Убедитесь, что все ваши sidecar-контейнеры достаточно просты и малы, потому что вам нужно будет просуммировать все запросы и ограничения ресурсов прежде чем задавать их для пода в целом. Также нужно быть уверенным, что Sidecar-контейнеры “здоровы”, настроив health checks. Помните об этих моментах, когда добавляете функционал в основной контейнер или используйте отдельный контейнер.