- PVSM.RU - https://www.pvsm.ru -
Прим. перев.: Service mesh'и определённо стали актуальным решением в современной инфраструктуре для приложений, следующих микросервисной архитектуре. Хотя Istio может быть на слуху у многих DevOps-инженеров, это довольно новый продукт, который, будучи комплексным в смысле предоставляемых возможностей, может потребовать значительного времени для знакомства. Немецкий инженер Rinor Maloku, отвечающий за облачные вычисления для крупных клиентов в телекоммуникационной компании Orange Networks, написал замечательный цикл материалов, что позволяют достаточно быстро и глубоко погрузиться в Istio. Начинает же он свой рассказ с того, что вообще умеет Istio и как на это можно быстро посмотреть собственными глазами.
Istio — Open Source-проект, разработанный при сотрудничестве команд из Google, IBM и Lyft. Он решает сложности, возникающие в приложениях, основанных на микросервисах, например, такие как:
Все они могут быть решены на уровне приложения, однако после этого ваши сервисы перестанут быть «микро». Все дополнительные усилия по решению этих проблем — лишний расход ресурсов компании, которые могли бы использоваться непосредственно для бизнес-ценностей. Рассмотрим пример:
Менеджер проектов: Как долго добавлять возможность обратной связи?
Разработчик: Два спринта.МП: Что?.. Это ведь всего лишь CRUD!
Р: Сделать CRUD — простая часть задачи, но нам ещё потребуется аутентифицировать и авторизовывать пользователей и сервисы. Поскольку сеть ненадёжна, понадобится реализовать повторные запросы, а также паттерн circuit breaker [1] в клиентах. Ещё, чтобы убедиться, что вся система не упала, понадобятся таймауты и bulkheads [2] (подробнее об обоих упомянутых паттернах см. дальше в статье — прим. перев.), а для того, чтобы обнаруживать проблемы, потребуется мониторинг, трассировка, […]МП: Ох, давайте тогда просто вставим эту фичу в сервис Product.
Думаю, идея понятна: объём шагов и усилий, которые требуются для добавления одного сервиса, огромен. В этой статье мы рассмотрим, как Istio устраняет все упомянутые выше сложности (не являющиеся целевыми для бизнес-логики) из сервисов.
Примечание: Статья предполагает, что у вас есть практические знания по Kubernetes. В ином случае рекомендую прочитать моё введение в Kubernetes [3] и только после этого продолжить чтение данного материала.
В мире без Istio один сервис делает прямые запросы к другому, а в случае сбоя сервис должен сам обработать его: предпринять новую попытку, предусмотреть таймаут, открыть circuit breaker и т.п.
Сетевой трафик в Kubernetes
Istio же предлагает специализированное решение, полностью отделённое от сервисов и функционирующее путём вмешательства в сетевое взаимодействие. И таким образом оно реализует:
Это лишь некоторые из возможностей (действительно лишь некоторые!), чтобы заинтриговать вас. А теперь давайте погрузимся в технические подробности!
Istio перехватывает весь сетевой трафик и применяет к нему набор правил, вставляя в каждый pod умный прокси в виде sidecar-контейнера. Прокси, которые активируют все возможности, образуют собой Data Plane, и они могут динамически настраиваться с помощью Control Plane.
Вставляемые в pod'ы прокси позволяют Istio с лёгкостью добиться соответствия нужным нам требованиям. Например, проверим функции повторных попыток и circuit breaker.
Как retries и circuit breaking реализованы в Envoy
Подытожим:
Это означает, что вам не придётся использовать очередную библиотеку Retry, не придётся делать свою реализацию Circuit Breaking и Service Discovery на языке программирования X, Y или Z. Всё это и многое другое доступно из коробки в Istio и не требует никаких изменений в коде.
Отлично! Теперь вы можете захотеть отправиться в вояж с Istio, но всё ещё есть какие-то сомнения, открытые вопросы. Если это универсальное решение на все случаи в жизни, то у вас возникает закономерное подозрение: ведь все такие решения в действительности оказываются не подходящими ни для какого случая.
И вот наконец вы спросите: «Оно настраивается?»
Теперь вы готовы к морскому путешествию — и давайте же познакомимся с Control Plane.
Он состоит из трёх компонентов: Pilot, Mixer и Citadel, — которые совместными усилиями настраивают Envoy'и для маршрутизации трафика, применяют политики и собирают телеметрические данные. Схематично всё это выглядит так:
Взаимодействие Control Plane с Data Plane
Envoy'и (т.е. data plane) сконфигурированы с помощью Kubernetes CRD [5] (Custom Resource Definitions), определёнными Istio и специально предназначенными для этой цели. Для вас это означает, что они представляются очередным ресурсом в Kubernetes со знакомым синтаксисом. После создания этот ресурс будет подобран control plane'ом и применён к Envoy'ям.
Мы описали отношение Istio к сервисам, но не обратное: как же сервисы относятся к Istio?
Честно говоря, о присутствии Istio сервисам известно так же хорошо, как рыбам — о воде, когда они спрашивают себя: «Что вообще такое вода?».
Иллюстрация Victoria Dimitrakopoulos [6]: — Как вам вода? — Что вообще такое вода?
Таким образом, вы можете взять рабочий кластер и после деплоя компонентов Istio сервисы, находящиеся в нём, продолжат работать, а после устранения этих компонентов — снова всё будет хорошо. Понятное дело, что при этом вы потеряете возможности, предоставляемые Istio.
Достаточно теории — давайте перенесём это знание в практику!
Istio требует кластера Kubernetes, в котором как минимум доступны 4 vCPU и 8 Гб RAM. Чтобы быстро поднять кластер и следовать инструкциям из статьи, рекомендую воспользоваться Google Cloud Platform, которая предлагает новым пользователям бесплатные $300 [7].
После создания кластера и настройки доступа к Kubernetes через консольную утилиту можно установить Istio через пакетный менеджер Helm.
Установите клиент Helm на своём компьютере, как рассказывают в официальной документации [8]. Его мы будем использовать для генерации шаблонов для установки Istio в следующем разделе.
Скачайте ресурсы Istio из последнего релиза [9] (оригинальная авторская ссылка на версию 1.0.5 изменена на актуальную, т.е. 1.0.6 — прим. перев.), извлеките содержимое в одну директорию, которую я буду в дальнейшем называть [istio-resources]
.
Для простоты идентификации ресурсов Istio создайте в кластере K8s пространство имён istio-system
:
$ kubectl create namespace istio-system
Завершите установку, перейдя в каталог [istio-resources]
и выполнив команду:
$ helm template install/kubernetes/helm/istio
--set global.mtls.enabled=false
--set tracing.enabled=true
--set kiali.enabled=true
--set grafana.enabled=true
--namespace istio-system > istio.yaml
Эта команда выведет ключевые компоненты Istio в файл istio.yaml
. Мы изменили стандартный шаблон под себя, указав следующие параметры:
global.mtls.enabled
установлено в false
(т.е. mTLS-аутентификация отключена — прим перев.), чтобы упростить наш процесс знакомства;tracing.enabled
включает трассировку запросов с помощью Jaeger;kiali.enabled
устанавливает Kiali в кластер для визуализации сервисов и трафика;grafana.enabled
устанавливает Grafana для визуализации собранных метрик.Применим сгенерированные ресурсы командой:
$ kubectl apply -f istio.yaml
Установка Istio в кластер завершена! Дождитесь, пока все pod'ы в пространстве имён istio-system
окажутся в состоянии Running
или Completed
, выполнив команду ниже:
$ kubectl get pods -n istio-system
Теперь мы готовы продолжить в следующем разделе, где поднимем и запустим приложение.
Воспользуемся примером микросервисного приложения Sentiment Analysis, использованного в уже упомянутой статье-введении в Kubernetes [3]. Оно достаточно сложное, чтобы показать возможности Istio на практике.
Приложение состоит из четырёх микросервисов:
На этой схеме помимо сервисов мы видим также Ingress Controller, который в Kubernetes маршрутизирует входящие запросы на соответствующие сервисы. В Istio используется схожая концепция в рамках Ingress Gateway, подробности о котором последуют.
Для дальнейших операций, упоминаемых в статье, склонируйте себе репозиторий istio-mastery [11]. В нём содержатся приложение и манифесты для Kubernetes и Istio.
Вставка может быть произведена автоматически или вручную. Для автоматической вставки sidecar-контейнеров потребуется выставить пространству имён лейбл istio-injection=enabled
, что делается следующей командой:
$ kubectl label namespace default istio-injection=enabled
namespace/default labeled
Теперь каждый pod, который будет разворачиваться в пространстве имён по умолчанию (default
) получит свой sidecar-контейнер. Чтобы убедиться в этом, давайте задеплоим тестовое приложение, перейдя в корневой каталог репозитория [istio-mastery]
и выполнив следующую команду:
$ kubectl apply -f resource-manifests/kube
persistentvolumeclaim/sqlite-pvc created
deployment.extensions/sa-feedback created
service/sa-feedback created
deployment.extensions/sa-frontend created
service/sa-frontend created
deployment.extensions/sa-logic created
service/sa-logic created
deployment.extensions/sa-web-app created
service/sa-web-app created
Развернув сервисы, проверим, что у pod'ов по два контейнера (с самим сервисом и его sidecar'ом), выполнив команду kubectl get pods
и убедившись, что под столбцом READY
указано значение 2/2
, символизирующее, что оба контейнера запущены:
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
sa-feedback-55f5dc4d9c-c9wfv 2/2 Running 0 12m
sa-frontend-558f8986-hhkj9 2/2 Running 0 12m
sa-logic-568498cb4d-2sjwj 2/2 Running 0 12m
sa-logic-568498cb4d-p4f8c 2/2 Running 0 12m
sa-web-app-599cf47c7c-s7cvd 2/2 Running 0 12m
Визуально это представляется так:
Прокси Envoy в одном из pod'ов
Теперь, когда приложение поднято и функционирует, нам потребуется разрешить входящему трафику приходить в приложение.
Лучшая практика добиться этого (разрешить трафик в кластере) — через Ingress Gateway в Istio, что располагается у «границы» кластера и позволяет включать для входящего трафика такие функции Istio, как маршрутизация, балансировка нагрузки, безопасность и мониторинг.
Компонент Ingress Gateway и сервис, который пробрасывает его вовне, были установлены в кластер во время инсталляции Istio. Чтобы узнать внешний IP-адрес сервиса, выполните:
$ kubectl get svc -n istio-system -l istio=ingressgateway
NAME TYPE CLUSTER-IP EXTERNAL-IP
istio-ingressgateway LoadBalancer 10.0.132.127 13.93.30.120
Мы будем обращаться к приложению по этому IP и дальше (я буду ссылаться на него как EXTERNAL-IP), поэтому для удобства запишем значение в переменную:
$ EXTERNAL_IP=$(kubectl get svc -n istio-system
-l app=istio-ingressgateway
-o jsonpath='{.items[0].status.loadBalancer.ingress[0].ip}')
Если попробуете сейчас зайти на этот IP через браузер, то получите ошибку Service Unavailable, т.к. по умолчанию Istio блокирует весь входящий трафик, пока не определён Gateway.
Gateway — это CRD (Custom Resource Definition) в Kubernetes, определяемый после установки Istio в кластере и активирующий возможность указывать порты, протокол и хосты, для которых мы хотим разрешить входящий трафик.
В нашем случае мы хотим разрешить HTTP-трафик на 80-й порт для всех хостов. Задача реализуется следующим определением (http-gateway.yaml [12]):
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: http-gateway
spec:
selector:
istio: ingressgateway
servers:
- port:
number: 80
name: http
protocol: HTTP
hosts:
- "*"
Такая конфигурация не нуждается в объяснениях за исключением селектора istio: ingressgateway
. С помощью этого селектора мы можем указать, к какому Ingress Gateway применить конфигурацию. В нашем случае таковым является контроллер Ingress Gateway, что был по умолчанию установлен в Istio.
Конфигурация применяется вызовом следующей команды:
$ kubectl apply -f resource-manifests/istio/http-gateway.yaml gateway.networking.istio.io/http-gateway created
Теперь шлюз разрешает доступ к порту 80, но не имеет представления о том, куда маршрутизировать запросы. Для этого понадобятся Virtual Services.
VirtualService указывает Ingress Gateway'ю, как маршрутизировать запросы, которые разрешены внутри кластера.
Запросы к нашему приложению, приходящие через http-gateway, должны быть отправлены в сервисы sa-frontend, sa-web-app и sa-feedback:
Маршруты, которые необходимо настроить с VirtualServices
Рассмотрим запросы, которые должны направляться на SA-Frontend:
/
должно отправляться в SA-Frontend для получения index.html;/static/*
должны отправляться в SA-Frontend для получения статических файлов, используемых во фронтенде, таких как CSS и JavaScript;'^.*.(ico|png|jpg)$'
, должны отправляться в SA-Frontend, т.к. это картинки, отображаемые на странице.Реализация достигается следующей конфигурацией (sa-virtualservice-external.yaml [13]):
kind: VirtualService
metadata:
name: sa-external-services
spec:
hosts:
- "*"
gateways:
- http-gateway # 1
http:
- match:
- uri:
exact: /
- uri:
exact: /callback
- uri:
prefix: /static
- uri:
regex: '^.*.(ico|png|jpg)$'
route:
- destination:
host: sa-frontend # 2
port:
number: 80
Важные моменты:
destination
определяется сервис, куда отправляются запросы.
Примечание: Конфигурация выше хранится в файле sa-virtualservice-external.yaml
, который также содержит настройки для маршрутизации в SA-WebApp и SA-Feedback, но был сокращён здесь в статье для лаконичности.
Применим VirtualService вызовом:
$ kubectl apply -f resource-manifests/istio/sa-virtualservice-external.yaml
virtualservice.networking.istio.io/sa-external-services created
Примечание: Когда мы применяем ресурсы Istio, Kubernetes API Server создаёт событие, которое получает Istio Control Plane, и уже после этого новая конфигурация применяется к прокси-серверам Envoy каждого pod'а. А контроллер Ingress Gateway представляется очередным Envoy, сконфигурированным в Control Plane. Всё это на схеме выглядит так:
Конфигурация Istio-IngressGateway для маршрутизации запросов
Приложение Sentiment Analysis стало доступным по http://{EXTERNAL-IP}/
. Не переживайте, если вы получаете статус Not Found: иногда требуется чуть больше времени для того, чтобы конфигурация вступила в силу и кэши Envoy обновились.
Перед тем, как продолжить, поработайте немного с приложением, чтобы сгенерировать трафик (его наличие необходимо для наглядности в последующих действиях — прим. перев.).
Чтобы попасть в административный интерфейс Kiali, выполните следующую команду:
$ kubectl port-forward
$(kubectl get pod -n istio-system -l app=kiali
-o jsonpath='{.items[0].metadata.name}')
-n istio-system 20001
… и откройте http://localhost:20001/ [14], залогинившись под admin/admin. Здесь вы найдете множество полезных возможностей, например, для проверки конфигурации компонентов Istio, визуализации сервисов по информации, собранной при перехвате сетевых запросов, получения ответов на вопросы «Кто к кому обращается?», «У какой версии сервиса возникают сбои?» и т.п. В общем, изучите возможности Kiali перед тем, как двигаться дальше — к визуализации метрик с Grafana.
Собранные в Istio метрики попадают в Prometheus и визуализируются с Grafana. Чтобы попасть в административный интерфейс Grafana, выполните команду ниже, после чего откройте http://localhost:3000/ [15]:
$ kubectl -n istio-system port-forward
$(kubectl -n istio-system get pod -l app=grafana
-o jsonpath={.items[0].metadata.name}) 3000
Кликнув на меню Home слева сверху и выбрав Istio Service Dashboard в левом верхнем углу, начните с сервиса sa-web-app, чтобы посмотреть на собранные метрики:
Здесь нас ждёт пустое и совершенно скучное представление — руководство никогда такое не одобрит. Давайте же создадим небольшую нагрузку следующей командой:
$ while true; do
curl -i http://$EXTERNAL_IP/sentiment
-H "Content-type: application/json"
-d '{"sentence": "I love yogobella"}';
sleep .8; done
Вот теперь у нас гораздо более симпатичные графики, а в дополнение к ним — замечательные инструменты Prometheus для мониторинга и Grafana для визуализации метрик, что позволят нам узнать о производительности, состоянии здоровья, улучшениях/деградации в работе сервисов на протяжении времени.
Наконец, посмотрим на трассировку запросов в сервисах.
Трассировка нам потребуется, потому что чем больше у нас сервисов, тем сложнее добраться до причины сбоя. Посмотрим на простой случай из картинки ниже:
Типовой пример случайного неудачного запроса
Запрос приходит, падает — в чём же причина? Первый сервис? Или второй? Исключения есть в обоих — давайте посмотрим на логи каждого. Как часто вы ловили себя за таким занятием? Наша работа больше похожа на детективов программного обеспечения, а не разработчиков…
Это широко распространённая проблема в микросервисах и решается она распределёнными системами трассировки, в которых сервисы передают друг другу уникальный заголовок, после чего эта информация перенаправляется в систему трассировки, где она сопоставляется с данными запроса. Вот иллюстрация:
Для идентификации запроса используется TraceId
В Istio используется Jaeger Tracer, который реализует независимый от вендоров фреймворк OpenTracing API. Получить доступ к пользовательского интерфейсу Jaeger можно следующей командой:
$ kubectl port-forward -n istio-system
$(kubectl get pod -n istio-system -l app=jaeger
-o jsonpath='{.items[0].metadata.name}') 16686
Теперь зайдите на http://localhost:16686/ [16] и выберите сервис sa-web-app. Если сервис не показан в выпадающем меню — проявите/сгенерируйте активность на странице и обновите интерфейс. После этого нажмите на кнопку Find Traces, которая покажет самые последние трейсы — выберите любой — покажется детализированная информация по всем трейсам:
Этот трейс показывает:
Примечание: На 4 шаге приложение должно увидеть заголовки, сгенерированные Istio, и передать их в последующие запросы, как показано на изображении ниже:
(A) За проброс заголовков отвечает Istio; (B) За заголовки отвечают сервисы
Istio делает основную работу, т.к. генерирует заголовки для входящих запросов, создаёт новые span'ы в каждом sidecare'е и пробрасывает их. Однако без работы с заголовками внутри сервисов полный путь трассировки запроса будет утерян.
Необходимо учитывать (пробрасывать) следующие заголовки:
x-request-id
x-b3-traceid
x-b3-spanid
x-b3-parentspanid
x-b3-sampled
x-b3-flags
x-ot-span-context
Это несложная задача, однако для упрощения её реализации уже существует множество библиотек [18] — например, в сервисе sa-web-app клиент RestTemplate пробрасывает эти заголовки, если просто добавить библиотеки Jaeger и OpenTracing в его зависимости [19].
Заметьте, что приложение Sentiment Analysis демонстрирует реализации на Flask, Spring и ASP.NET Core.
Теперь, когда стало ясно, что мы получаем из коробки (или почти «из коробки»), рассмотрим вопросы тонко настраиваемой маршрутизации, управления сетевым трафиком, безопасности и т.п.!
Прим. перев.: об этом читайте в следующей части материалов по Istio от Rinor Maloku, переводы которых последуют в нашем блоге в ближайшее время.
Читайте также в нашем блоге:
Автор: Андрей Сидоров
Источник [24]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/sistemnoe-administrirovanie/310898
Ссылки в тексте:
[1] паттерн circuit breaker: https://en.wikipedia.org/wiki/Circuit_breaker_design_pattern
[2] bulkheads: https://docs.microsoft.com/en-us/azure/architecture/patterns/bulkhead
[3] моё введение в Kubernetes: https://medium.freecodecamp.org/learn-kubernetes-in-under-3-hours-a-detailed-guide-to-orchestrating-containers-114ff420e882
[4] отдельный продукт: https://www.envoyproxy.io/
[5] Kubernetes CRD: https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/custom-resources/
[6] Victoria Dimitrakopoulos: https://fityourself.club/@victoriadimitrakopoulos
[7] бесплатные $300: https://console.developers.google.com/billing/freetrial?hl=en
[8] официальной документации: https://docs.helm.sh/using_helm/#installing-the-helm-client
[9] последнего релиза: https://github.com/istio/istio/releases/tag/1.0.6
[10] сентимент-анализ: https://ru.wikipedia.org/wiki/%D0%90%D0%BD%D0%B0%D0%BB%D0%B8%D0%B7_%D1%82%D0%BE%D0%BD%D0%B0%D0%BB%D1%8C%D0%BD%D0%BE%D1%81%D1%82%D0%B8_%D1%82%D0%B5%D0%BA%D1%81%D1%82%D0%B0
[11] istio-mastery: https://github.com/rinormaloku/istio-mastery
[12] http-gateway.yaml: https://gist.github.com/rinormaloku/577d0e23590f7a8dfbe56fe2a1f853d7#file-http-gateway-yaml
[13] sa-virtualservice-external.yaml: https://gist.github.com/rinormaloku/580a872b330e14111958aaac20f65aa6#file-sa-virtualservice-external-yaml
[14] http://localhost:20001/: http://localhost:20001/
[15] http://localhost:3000/: http://localhost:3000/
[16] http://localhost:16686/: http://localhost:16686/
[17] Span: https://www.jaegertracing.io/docs/1.9/architecture/#span
[18] множество библиотек: https://github.com/opentracing-contrib
[19] его зависимости: https://github.com/rinormaloku/istio-mastery/blob/master/sa-webapp/pom.xml#L36-L47
[20] Conduit — легковесный service mesh для Kubernetes: https://habr.com/ru/company/flant/blog/349496/
[21] Что такое service mesh и почему он мне нужен [для облачного приложения с микросервисами]?: https://habr.com/ru/company/flant/blog/327536/
[22] Иллюстрированное руководство по устройству сети в Kubernetes. Части 1 и 2: https://habr.com/ru/company/flant/blog/346304/
[23] Как этот sidecar-контейнер оказался здесь [в Kubernetes]?: https://habr.com/ru/company/flant/blog/431252/
[24] Источник: https://habr.com/ru/post/438426/?utm_source=habrahabr&utm_medium=rss&utm_campaign=438426
Нажмите здесь для печати.