Stories injection enabled что это

Dependency injection

От переводчика

Представляемый вашему вниманию перевод открывает серию статей от Jakob Jenkov, посвященных внедрению зависимостей, или DI. Примечательна серия тем, что в ней автор, анализируя понятия и практическое применение таких понятий как «зависимость», «внедрение зависимостей», «контейнер для внедрения зависимостей», сравнивая паттерны создания объектов, анализируя недостатки конкретных реализаций DI-контейнеров (например, Spring), рассказывает, как пришел к написанию собственного DI-контейнера. Таким образом, читателю предлагается познакомиться с довольно цельным взглядом на вопрос управления зависимостями в приложениях.

В данной статье сравнивается подход к настройке объектов изнутри и извне (DI). По смыслу настоящая статья продолжает статью Jakob Jenkov Understanding Dependencies, в которой дается определение самому понятию «зависимости» и их типам.

Stories injection enabled что это. Смотреть фото Stories injection enabled что это. Смотреть картинку Stories injection enabled что это. Картинка про Stories injection enabled что это. Фото Stories injection enabled что это

Серия включает в себя следующие статьи

Внедрение зависимостей

«Внедрение зависимостей» — это выражение, впервые использованное в статье Мартина Фаулера Inversion of Control Containers and the Dependency Injection Pattern. Это хорошая статья, но она упускает из виду некоторые преимущества контейнеров внедрения зависимостей. Также я не согласен с выводами статьи, но об этом — в следующих текстах.

Объяснение внедрения зависимостей

Внедрение зависимостей — это стиль настройки объекта, при котором поля объекта задаются внешней сущностью. Другими словами, объекты настраиваются внешними объектами. DI — это альтернатива самонастройке объектов. Это может выглядеть несколько абстрактно, так что посмотрим пример:

UPD: после обсуждения представленных автором фрагментов кода с flatscode и fogone, я принял решение скорректировать спорные моменты в коде. Изначальный замысел был в том, чтобы не трогать код и давать его таким, каков он написан автором. Оригинальный авторский код в спорных местах закомментирован с указанием «в оригинале», ниже дается его исправленная версия. Также оригинальный код можно найти по ссылке в начале статьи.

Этот DAO (Data Access Object), MyDao нуждается в экземпляре javax.sql.DataSource для того, чтобы получить подключения к базе данных. Подключения к БД используются для чтения и записи в БД, например, объектов Person.

Заметьте, что класс MyDao создает экземпляр DataSourceImpl, так как нуждается в источнике данных. Тот факт, что MyDao нуждается в реализации DataSource, означает, что он зависит от него. Он не может выполнить свою работу без реализации DataSource. Следовательно, MyDao имеет «зависимость» от интерфейса DataSource и от какой-то его реализации.

Класс MyDao создает экземпляр DataSourceImpl как реализацию DataSource. Следовательно, класс MyDao сам «разрешает свои зависимости». Когда класс разрешает собственные зависимости, он автоматически также зависит от классов, для которых он разрешает зависимости. В данном случае MyDao завсист также от DataSourceImpl и от четырех жестко заданных строковых значений, передаваемых в конструктор DataSourceImpl. Вы не можете ни использовать другие значения для этих четырех строк, ни использовать другую реализацию интерфейса DataSource без изменения кода.

Как вы можете видеть, в том случае, когда класс разрешает собственные зависимости, он становится негибким в отношении к этим зависимостям. Это плохо. Это значит, что если вам нужно поменять зависимости, вам нужно поменять код. В данном примере это означает, что если вам нужно использовать другую базу данных, вам потребуется поменять класс MyDao. Если у вас много DAO-классов, реализованных таким образом, вам придется изменять их все. В добавок, вы не можете провести юнит-тестирование MyDao, замокав реализацию DataSource. Вы можете использовать только DataSourceImpl. Не требуется много ума, чтобы понять, что это плохая идея.

Давайте немного поменяем дизайн:

Заметьте, что создание экземпляра DataSourceImpl перемещено в конструктор. Конструктор принимает четыре параметра, это — четыре значения, необходимые для DataSourceImpl. Хотя класс MyDao все еще зависит от этих четырех значений, он больше не разрешает зависимости сам. Они предоставляются классом, создающим экземпляр MyDao. Зависимости «внедряются» в конструктор MyDao. Отсюда и термин «внедрение (прим. перев.: или иначе — инъекция) зависимостей». Теперь возможно сменить драйвер БД, URL, имя пользователя или пароль, используемый классом MyDao без его изменения.

Внедрение зависимостей не ограничено конструкторами. Можно внедрять зависимости также используя методы-сеттеры, либо прямо через публичные поля (прим. перев.: по поводу полей переводчик не согласен, это нарушает защиту данных класса).

Класс MyDao может быть более независимым. Сейчас он все еще зависит и от интерфейса DataSource, и от класса DataSourceImpl. Нет необходимости зависеть от чего-то, кроме интерфейса DataSource. Это может быть достигнуто инъекцией DataSource в конструктор вместо четырех параметров строкового типа. Вот как это выглядит:

Теперь класс MyDao больше не зависит от класса DataSourceImpl или от четырех строк, необходимых конструктору DataSourceImpl. Теперь можно использовать любую реализацию DataSource в конструкторе MyDao.

Цепное внедрение зависимостей

Пример из предыдущего раздела немного упрощен. Вы можете возразить, что зависимость теперь перемещена из класса MyDao к каждому клиенту, который использует класс MyDao. Клиентам теперь приходится знать о реализации DataSource, чтобы быть в состоянии поместить его в конструктор MyDao. Вот пример:

Как вы можете видеть, теперь MyBizComponent зависит от класса DataSourceImpl и четырех строк, необходимых его конструктору. Это еще хуже, чем зависимость MyDao от них, потому что MyBizComponent теперь зависит от классов и от информации, которую он сам даже не использует. Более того, реализация DataSourceImpl и параметры конструктора принадлежат к разным слоям абстракции. Слой ниже MyBizComponent — это слой DAO.

Решение — продолжить внедрение зависимости по всем слоям. MyBizComponent должен зависеть только от экземпляра MyDao. Вот как это выглядит:

Снова зависимость, MyDao, предоставляется через конструктор. Теперь MyBizComponent зависит только от класса MyDao. Если бы MyDao был интерфейсом, можно было бы менять реализацию без ведома MyBizComponent.

Такой паттерн внедрения зависимости должен продолжается через все слои приложения, с самого нижнего слоя (слоя доступа к данным) до пользовательского интерфейса (если он есть).

Источник

Dependency Injection. JavaScript

Понятия «инверсия управления» и «внедрение зависимостей» не являются новыми, но в сообществе JavaScript, несмотря на его бурный и продолжительный рост, почему-то встречаются довольно редко.

Независимо от контекста исполнения, расширяемое и поддерживаемое javascript-приложение, как и приложение, написанное на любом другом языке, должно соответствовать некоторым архитектурным принципам. Одним из которых является инверсия управления.

Что это?

Если вы не знаете, что такое «инверсия управления» и «внедрение зависимостей», или не совсем понимаете, о чем это — не волнуйтесь, здесь нет никакой магии или чего-то сложного. Ниже я попытаюсь дать сжатые определения этих понятий в контексте темы, однако будет более полезно изучить материалы по ссылкам в конце статьи.

Инверсия управления (англ. Inversion of Control, IoC) — это принцип объектно-ориентированного программирования, при котором объекты программы не зависят от конкретных реализаций других объектов, но могут иметь знание об их абстракциях (интерфейсах) для последующего взаимодействия.

Внедрение зависимостей (англ. Dependency Injection) — это композиция структурных шаблонов проектирования, при которой за каждую функцию приложения отвечает один, условно независимый объект (сервис), который может иметь необходимость использовать другие объекты (зависимости), известные ему интерфейсами. Зависимости передаются (внедряются) сервису в момент его создания.

Библиотеки, реализующие эти принципы часто называют IoC контейнерами (англ., Inversion of Control Container).

Пример из жизни

Предположим, вам необходимо отобразить на карте всех зарегистрированных пользователей вашего приложения. Каким-то образом список пользователей вы уже получили. Далее этот список передается объекту, реализующему функцию локации, который мы будем называть Локатор. Локатор, в свою очередь, использует какой-либо публичный сервис работы с картами. Упрощенный код выглядел бы примерно так:

Все работает, и вы переходите к следующим задачам. Но если со временем вдруг вы решите использовать другой сервис карт, вам придется переписать большую часть кода Локатора — от загрузки клиента и его инициализации, до общения с API нового клиента. Причина такой ситуации в том, в ответственности Локатора не только функция локации пользователей, но и функции создания, конфигурации и общения с клиентом карт.

Чтобы убрать из ответственности Локатора функции работы с картами, вынесем их в интерфейс, который будем реализовывать под конкретные карты. Реализацию такого интерфейса будем называть Картограф:

Имплементация такого интерфейса под конкретный сервис карт:

Теперь, если мы захотим поменять сервис карт, нам нужно будет просто создавать объект другой реализации внутри Локатора:

Таким образом мы решили проблему избытка ответственности Локатора, но появилась зависимость от конкретной реализации Картографа.

Если мы захотим перенести Локатор в другой проект, мы не сможем перенести только его реализацию. В другом проекте используется другие карты и, соответственно, другой клиент карт. Поэтому, разработчикам другого проекта придется править код Локатора — инстанцировать внутри уже свою реализацию Картографа.

Другими словами, пока что мы не можем использовать Локатор как плагин:

Stories injection enabled что это. Смотреть фото Stories injection enabled что это. Смотреть картинку Stories injection enabled что это. Картинка про Stories injection enabled что это. Фото Stories injection enabled что это

Именно подобного рода проблемы помогает решить инверсия контроля.

В контексте нашего примера — Локатор оставит знание лишь об интерфейсе Картографа, и позволит внедрять в себя любую его имплементацию, тем самым исчезнет зависимость от конкретной реализации:

Stories injection enabled что это. Смотреть фото Stories injection enabled что это. Смотреть картинку Stories injection enabled что это. Картинка про Stories injection enabled что это. Фото Stories injection enabled что это

При такой организации Локатор весьма независим и его легко использовать как плагин и переносить между проектами:

Теперь можно беспокоиться лишь о том, чтобы картограф в другом проекте поддерживал интерфейс нашего Картографа (обычно такие задачи решает шаблон Адаптер).

Вот так выглядит использование Локатора в итоге:

Остается один вопрос — на каком уровне должно происходить создание сервисов и внедрение в них зависимостей, и можно ли как-то автоматизировать такую «сборку»?

Во многих языках программирования существует достаточное количество библиотек, позволяющих строить приложения по принципам инверсии контроля и внедрения зависимостей. Такие библиотеки позволяют автоматизировать процесс создания и конфигурации объектов-сервисов.

В мире JavaScript таких библиотек меньше, и далеко не все из них полностью автоматизируют создание и внедрение объектов. Так же далеко не многие могут работать независимо от среды исполнения.

Поэтому мне захотелось (и понравилось) написать свою имплементацию — dm.js.

При ее использовании, пример с Локатором мог бы выглядеть следующим образом:

Весь процесс создания, конфигурации и внедрения объектов dm.js берет на себя. Для описания зависимостей используется объект с определенной структурой и синтаксисом.

Dm.js создает сервисы асинхронно, возвращая Promises/A+ обещания. При помощи адаптеров поддерживаются любые загрузчики модулей и библиотеки Promises.

С помощью библиотеки можно описывать зависимость не только от сервисов, но и ресурсов — например, шаблонов или json файлов. Синтаксис конфигураций так же позволяет строить рекурсивные зависимости.

Подробная документация и описание конфигурации библиотеки представлены на странице проекта на github.

P.S. или инверсия в контексте Веб

Приложение, архитектура которого следует принципу инверсии управления, имеет ряд положительных особенностей, которые облегчают его модификации и увеличивают жизненный цикл. Централизованное управление зависимостями позволяет описывать различные конфигурации приложения, тем самым, в совокупности сервисов, меняя его поведение. Например, приложение на тестовом сервере может использовать другие сервисы и/или их конфигурации, чем то же приложение использует на боевом. Внедрение зависимостей облегчает юнит тестирование, позволяя подменять зависимости тестируемого сервиса заглушками. Использование интерфейсов при проектировании позволяет описывать новые функции приложения более изолированно, ограничивая ответственность сервисов.

Помимо внедрения зависимостей, библиотеки (dm.js не исключение) часто реализуют и другой вид инверсии управления, известный как паттерн Сервис Локатор. При таком подходе зависимости не только внедряются в сервис, но и сам сервис может запрашивать объекты у IoC контейнера, который выполняет роль локатора сервисов.

В некоторых статьях была высказана мысль, что такой вид инверсии управления является антипаттерном. С этой мыслью можно согласиться по нескольким причинам. Во-первых, при таком использовании информация о зависимостях размывается и переносится в код сервисов, которые запрашивают у контейнера нужные им объекты. Такое поведение не позволяет контролировать все конфигурации сервисов централизованно. Во-вторых, каждый сервис получает дополнительную зависимость от сервис-локатора. Аналогичное мнение сложилось у меня и про внедрение типов по интерфейсам (Interface Injection в статье Мартина Фаулера) — информация о зависимостях переносится в реализуемые сервисом интерфейсы.

Однако, в контексте веб-разработки в браузере, использовать паттерн Сервис Локатор в целях оптимизации оправданно — ведь далеко не всегда нужно загружать сразу все сервисы приложения и грузить тем самым много килобайт кода.

Спасибо за внимание, вопросы и комментарии приветствуются!

Источник

Повышаем безопасность микросервисов с Istio

Всем привет! Меня зовут Илья, я работаю DevOps-инженером в команде разработки. Мы активно используем микросервисный подход, и, из-за специфики нашей работы, для нас важна безопасность межсервисного взаимодействия. В этой статье я хочу описать принцип работы Istio и на примере показать, как использовать некоторые ее возможности по обеспечению безопасности. Надеюсь, это окажется полезным для решения ваших задач. Приятного чтения!

Stories injection enabled что это. Смотреть фото Stories injection enabled что это. Смотреть картинку Stories injection enabled что это. Картинка про Stories injection enabled что это. Фото Stories injection enabled что это

Для чего вообще нужна сервисная сеть

Service mesh, в данном случае Istio – это обвязка для всего того, что требуется для управления и конфигурирования межсервисного взаимодействия: маршрутизация, аутентификация, авторизация, трассировка, контроль доступа и многое другое. И хотя существует масса открытых библиотек, чтобы реализовать эти функции непосредственно в коде сервиса, с Istio можно получить все то же самое, ничего не добавляя в сам сервис.

Компоненты

Istio логически разбита на плоскость данных (data plane) и плоскость управления (control plane).
Плоскость данных это совокупность прокси-серверов (Envoy), добавленных к pod’у в виде сайдкаров. Эти прокси-серверы обеспечивают и контролируют всю сетевую связь между микросервисами и конфигурируются из плоскости управления.

Плоскость управления (istiod) обеспечивает service discovery, настройку и управление сертификатами. Она конвертирует Istio объекты в понятные для Envoy конфигурации и распространяет их в плоскости данных.

Stories injection enabled что это. Смотреть фото Stories injection enabled что это. Смотреть картинку Stories injection enabled что это. Картинка про Stories injection enabled что это. Фото Stories injection enabled что это

Компоненты Istio service mesh

Добавить envoy в pod приложения можно как вручную, так и настроив автоматическое добавление с помощью Mutating Admission webhook, который Istio добавляет при своей установке. Для этого нужно проставить на необходимый неймспейс метку istio-injection=enabled.

2-3 мс, каждый envoy занимает порядка 40 Мб памяти, и потребление CPU возрастает в среднем на 5%-7% на pod.

Давайте на практике посмотрим, как сайдкар захватывает входящий и исходящий трафик из контейнера. Для этого взглянем на сетевое пространство какого-нибудь pod’а с добавленным Istio сайдкаром подробнее.

Для практических примеров я буду использовать свеже установленный Kubernetes кластер с Istio.
Локально развернуть Kubernetes несложно с помощью minikube:

Istio с demo профилем можно установить по документу с официального сайта:

Для примеров межсервисного взаимодействия я буду использовать два микросервиса: productpage и details. Они оба идут в стандартной поставке Istio для демонстрации ее возможностей.

Посмотрим список контейнеров приложения productpage:

Кроме самого productpage, в pod’е работают sidecar istio-proxy (тот самый envoy) и init контейнер istio-init.

Посмотреть на настроенные в пространстве имена pod’а iptables-правила можно с помощью утилиты nsenter. Для этого нам надо узнать pid процесса контейнера:

Теперь мы можем посмотреть правила iptables, установленные в этом контейнере.

Stories injection enabled что это. Смотреть фото Stories injection enabled что это. Смотреть картинку Stories injection enabled что это. Картинка про Stories injection enabled что это. Фото Stories injection enabled что это

Видно, что практически весь входящий и исходящий трафик теперь перехватывается и перенаправляется на порты, на которых его уже поджидает envoy.

Включаем взаимное шифрование трафика

Объекты Policy и MeshPolicy были удалены из istio 1.6. Вместо них предлагается использовать объект PeerAuthentication

Istio позволяет зашифровать весь трафик между контейнерами, причем сами приложения даже не будут знать, что общаются через tls. Делается это самим Istio из коробки буквально одним манифестом, так как в сайдкары-прокси уже смонтированы клиентские сертификаты.

Stories injection enabled что это. Смотреть фото Stories injection enabled что это. Смотреть картинку Stories injection enabled что это. Картинка про Stories injection enabled что это. Фото Stories injection enabled что это

Stories injection enabled что это. Смотреть фото Stories injection enabled что это. Смотреть картинку Stories injection enabled что это. Картинка про Stories injection enabled что это. Фото Stories injection enabled что это

Все тело и заголовки прекрасно читаемы в plain text.

Включим tls. Для этого создадим объект типа PeerAuthentication в неймспейсе с нашими pod’ами.

Запустим запрос из product page к details опять и посмотрим, что удастся получить:

Stories injection enabled что это. Смотреть фото Stories injection enabled что это. Смотреть картинку Stories injection enabled что это. Картинка про Stories injection enabled что это. Фото Stories injection enabled что это

Авторизация

Объекты ClusterRbacConfig, ServiceRole, and ServiceRoleBinding были удалены вместе с внедрением новой авторизационной политики. Вместо них предлагается использовать объект AuthorizationPolicy.

С помощью политик авторизации Istio может настраивать доступ одного приложения к другому. Причем, в отличие от чистых Kubernetes network policies, это работает на L7 уровне. Например, для http-трафика можно тонко управлять методами и путями запроса.

Как мы уже видели в предыдущем примере, по умолчанию доступ открыт для всех pod’ов всего кластера.

Теперь запретим все активности в неймспейсе default с помощью такого yaml-файла:

И попробуем достучаться до сервиса details:

Отлично, теперь наш запрос не проходит.

А теперь настроим доступ так, чтобы проходил только GET запрос и только по пути /details, а все остальные запросы отклонялись. Для этого есть несколько вариантов:

Для использования политик авторизации на основе сервис аккаунтов необходимо включить взаимную аутентификацию TLS.

Настраиваем новую политику доступа:

И пробуем достучаться вновь:

Все работает. Попробуем другие методы и пути:

Заключение

В заключение отмечу, что рассмотренные возможности это лишь малая толика того, что умеет Istio. Из коробки мы получили и настроили межсервисное шифрование трафика и авторизацию, правда, ценой добавления дополнительных компонентов и, следовательно, дополнительным расходом ресурсов.

Источник

Installing the Sidecar

Injection

In order to take advantage of all of Istio’s features, pods in the mesh must be running an Istio sidecar proxy.

The following sections describe two ways of injecting the Istio sidecar into a pod: enabling automatic Istio sidecar injection in the pod’s namespace, or by manually using the istioctl command.

When enabled in a pod’s namespace, automatic injection injects the proxy configuration at pod creation time using an admission controller.

Manual injection directly modifies configuration, like deployments, by adding the proxy configuration into it.

If you are not sure which one to use, automatic injection is recommended.

Automatic sidecar injection

Sidecars can be automatically added to applicable Kubernetes pods using a mutating webhook admission controller provided by Istio.

When you set the istio-injection=enabled label on a namespace and the injection webhook is enabled, any new pods that are created in that namespace will automatically have a sidecar added to them.

Note that unlike manual injection, automatic injection occurs at the pod-level. You won’t see any change to the deployment itself. Instead, you’ll want to check individual pods (via kubectl describe ) to see the injected proxy.

Deploying an app

Deploy sleep app. Verify both deployment and pod have a single container.

Label the default namespace with istio-injection=enabled

Injection occurs at pod creation time. Kill the running pod and verify a new pod is created with the injected sidecar. The original pod has 1/1 READY containers, and the pod with injected sidecar has 2/2 READY containers.

View detailed state of the injected pod. You should see the injected istio-proxy container and corresponding volumes.

Disable injection for the default namespace and verify new pods are created without the sidecar.

Controlling the injection policy

In the above examples, you enabled and disabled injection at the namespace level. Injection can also be controlled on a per-pod basis, by configuring the sidecar.istio.io/inject label on a pod:

ResourceLabelEnabled valueDisabled value
Namespaceistio-injectionenableddisabled
Podsidecar.istio.io/inject«true»«false»

If you are using control plane revisions, revision specific labels are instead used by a matching istio.io/rev label. For example, for a revision named canary :

ResourceEnabled labelDisabled label
Namespaceistio.io/rev=canaryistio-injection=disabled
Podistio.io/rev=canarysidecar.istio.io/inject=»false»

If the istio-injection label and the istio.io/rev label are both present on the same namespace, the istio-injection label will take precedence.

The injector is configured with the following logic:

Manual sidecar injection

To manually inject a deployment, use istioctl kube-inject :

By default, this will use the in-cluster configuration. Alternatively, injection can be done using local copies of the configuration.

Run kube-inject over the input file and deploy.

Verify that the sidecar has been injected into the sleep pod with 2/2 under the READY column.

Customizing injection

Generally, pod are injected based on the sidecar injection template, configured in the istio-sidecar-injector configmap. Per-pod configuration is available to override these options on individual pods. This is done by adding an istio-proxy container to your pod. The sidecar injection will treat any configuration defined here as an override to the default injection template.

For example, the following configuration customizes a variety of settings, including lowering the CPU requests, adding a volume mount, and adding a preStop hook:

In general, any field in a pod can be set. However, care must be taken for certain fields:

Additionally, certain fields are configurable by annotations on the pod, although it is recommended to use the above approach to customizing settings.

Custom templates (experimental)

Completely custom templates can also be defined at installation time. For example, to define a custom template that injects the GREETING environment variable into the istio-proxy container:

Do you have any suggestions for improvement?

Источник

Назад к микросервисам вместе с Istio. Часть 1

Stories injection enabled что это. Смотреть фото Stories injection enabled что это. Смотреть картинку Stories injection enabled что это. Картинка про Stories injection enabled что это. Фото Stories injection enabled что это

Прим. перев.: Service mesh’и определённо стали актуальным решением в современной инфраструктуре для приложений, следующих микросервисной архитектуре. Хотя Istio может быть на слуху у многих DevOps-инженеров, это довольно новый продукт, который, будучи комплексным в смысле предоставляемых возможностей, может потребовать значительного времени для знакомства. Немецкий инженер Rinor Maloku, отвечающий за облачные вычисления для крупных клиентов в телекоммуникационной компании Orange Networks, написал замечательный цикл материалов, что позволяют достаточно быстро и глубоко погрузиться в Istio. Начинает же он свой рассказ с того, что вообще умеет Istio и как на это можно быстро посмотреть собственными глазами.

Istio — Open Source-проект, разработанный при сотрудничестве команд из Google, IBM и Lyft. Он решает сложности, возникающие в приложениях, основанных на микросервисах, например, такие как:

Менеджер проектов: Как долго добавлять возможность обратной связи?
Разработчик: Два спринта.

МП: Что. Это ведь всего лишь CRUD!
Р: Сделать CRUD — простая часть задачи, но нам ещё потребуется аутентифицировать и авторизовывать пользователей и сервисы. Поскольку сеть ненадёжна, понадобится реализовать повторные запросы, а также паттерн circuit breaker в клиентах. Ещё, чтобы убедиться, что вся система не упала, понадобятся таймауты и bulkheads (подробнее об обоих упомянутых паттернах см. дальше в статье — прим. перев.), а для того, чтобы обнаруживать проблемы, потребуется мониторинг, трассировка, […]

МП: Ох, давайте тогда просто вставим эту фичу в сервис Product.

Думаю, идея понятна: объём шагов и усилий, которые требуются для добавления одного сервиса, огромен. В этой статье мы рассмотрим, как Istio устраняет все упомянутые выше сложности (не являющиеся целевыми для бизнес-логики) из сервисов.

Stories injection enabled что это. Смотреть фото Stories injection enabled что это. Смотреть картинку Stories injection enabled что это. Картинка про Stories injection enabled что это. Фото Stories injection enabled что это

Примечание: Статья предполагает, что у вас есть практические знания по Kubernetes. В ином случае рекомендую прочитать моё введение в Kubernetes и только после этого продолжить чтение данного материала.

Идея Istio

В мире без Istio один сервис делает прямые запросы к другому, а в случае сбоя сервис должен сам обработать его: предпринять новую попытку, предусмотреть таймаут, открыть circuit breaker и т.п.

Stories injection enabled что это. Смотреть фото Stories injection enabled что это. Смотреть картинку Stories injection enabled что это. Картинка про Stories injection enabled что это. Фото Stories injection enabled что это
Сетевой трафик в Kubernetes

Istio же предлагает специализированное решение, полностью отделённое от сервисов и функционирующее путём вмешательства в сетевое взаимодействие. И таким образом оно реализует:

Архитектура Istio

Istio перехватывает весь сетевой трафик и применяет к нему набор правил, вставляя в каждый pod умный прокси в виде sidecar-контейнера. Прокси, которые активируют все возможности, образуют собой Data Plane, и они могут динамически настраиваться с помощью Control Plane.

Data Plane

Вставляемые в pod’ы прокси позволяют Istio с лёгкостью добиться соответствия нужным нам требованиям. Например, проверим функции повторных попыток и circuit breaker.

Stories injection enabled что это. Смотреть фото Stories injection enabled что это. Смотреть картинку Stories injection enabled что это. Картинка про Stories injection enabled что это. Фото Stories injection enabled что это
Как retries и circuit breaking реализованы в Envoy

Отлично! Теперь вы можете захотеть отправиться в вояж с Istio, но всё ещё есть какие-то сомнения, открытые вопросы. Если это универсальное решение на все случаи в жизни, то у вас возникает закономерное подозрение: ведь все такие решения в действительности оказываются не подходящими ни для какого случая.

И вот наконец вы спросите: «Оно настраивается?»

Теперь вы готовы к морскому путешествию — и давайте же познакомимся с Control Plane.

Control Plane

Он состоит из трёх компонентов: Pilot, Mixer и Citadel, — которые совместными усилиями настраивают Envoy’и для маршрутизации трафика, применяют политики и собирают телеметрические данные. Схематично всё это выглядит так:

Stories injection enabled что это. Смотреть фото Stories injection enabled что это. Смотреть картинку Stories injection enabled что это. Картинка про Stories injection enabled что это. Фото Stories injection enabled что это
Взаимодействие Control Plane с Data Plane

Envoy’и (т.е. data plane) сконфигурированы с помощью Kubernetes CRD (Custom Resource Definitions), определёнными Istio и специально предназначенными для этой цели. Для вас это означает, что они представляются очередным ресурсом в Kubernetes со знакомым синтаксисом. После создания этот ресурс будет подобран control plane’ом и применён к Envoy’ям.

Отношение сервисов к Istio

Мы описали отношение Istio к сервисам, но не обратное: как же сервисы относятся к Istio?

Честно говоря, о присутствии Istio сервисам известно так же хорошо, как рыбам — о воде, когда они спрашивают себя: «Что вообще такое вода?».

Stories injection enabled что это. Смотреть фото Stories injection enabled что это. Смотреть картинку Stories injection enabled что это. Картинка про Stories injection enabled что это. Фото Stories injection enabled что это
Иллюстрация Victoria Dimitrakopoulos: — Как вам вода? — Что вообще такое вода?

Таким образом, вы можете взять рабочий кластер и после деплоя компонентов Istio сервисы, находящиеся в нём, продолжат работать, а после устранения этих компонентов — снова всё будет хорошо. Понятное дело, что при этом вы потеряете возможности, предоставляемые Istio.

Достаточно теории — давайте перенесём это знание в практику!

Istio на практике

После создания кластера и настройки доступа к Kubernetes через консольную утилиту можно установить Istio через пакетный менеджер Helm.

Установка Helm

Установите клиент Helm на своём компьютере, как рассказывают в официальной документации. Его мы будем использовать для генерации шаблонов для установки Istio в следующем разделе.

Установка Istio

Для простоты идентификации ресурсов Istio создайте в кластере K8s пространство имён istio-system :

Завершите установку, перейдя в каталог [istio-resources] и выполнив команду:

Теперь мы готовы продолжить в следующем разделе, где поднимем и запустим приложение.

Архитектура приложения Sentiment Analysis

Воспользуемся примером микросервисного приложения Sentiment Analysis, использованного в уже упомянутой статье-введении в Kubernetes. Оно достаточно сложное, чтобы показать возможности Istio на практике.

Приложение состоит из четырёх микросервисов:

На этой схеме помимо сервисов мы видим также Ingress Controller, который в Kubernetes маршрутизирует входящие запросы на соответствующие сервисы. В Istio используется схожая концепция в рамках Ingress Gateway, подробности о котором последуют.

Запуск приложения с прокси от Istio

Для дальнейших операций, упоминаемых в статье, склонируйте себе репозиторий istio-mastery. В нём содержатся приложение и манифесты для Kubernetes и Istio.

Вставка sidecar’ов

Теперь каждый pod, который будет разворачиваться в пространстве имён по умолчанию ( default ) получит свой sidecar-контейнер. Чтобы убедиться в этом, давайте задеплоим тестовое приложение, перейдя в корневой каталог репозитория [istio-mastery] и выполнив следующую команду:

Визуально это представляется так:

Stories injection enabled что это. Смотреть фото Stories injection enabled что это. Смотреть картинку Stories injection enabled что это. Картинка про Stories injection enabled что это. Фото Stories injection enabled что это
Прокси Envoy в одном из pod’ов

Теперь, когда приложение поднято и функционирует, нам потребуется разрешить входящему трафику приходить в приложение.

Ingress Gateway

Лучшая практика добиться этого (разрешить трафик в кластере) — через Ingress Gateway в Istio, что располагается у «границы» кластера и позволяет включать для входящего трафика такие функции Istio, как маршрутизация, балансировка нагрузки, безопасность и мониторинг.

Компонент Ingress Gateway и сервис, который пробрасывает его вовне, были установлены в кластер во время инсталляции Istio. Чтобы узнать внешний IP-адрес сервиса, выполните:

Мы будем обращаться к приложению по этому IP и дальше (я буду ссылаться на него как EXTERNAL-IP), поэтому для удобства запишем значение в переменную:

Если попробуете сейчас зайти на этот IP через браузер, то получите ошибку Service Unavailable, т.к. по умолчанию Istio блокирует весь входящий трафик, пока не определён Gateway.

Ресурс Gateway

Gateway — это CRD (Custom Resource Definition) в Kubernetes, определяемый после установки Istio в кластере и активирующий возможность указывать порты, протокол и хосты, для которых мы хотим разрешить входящий трафик.

В нашем случае мы хотим разрешить HTTP-трафик на 80-й порт для всех хостов. Задача реализуется следующим определением (http-gateway.yaml):

Конфигурация применяется вызовом следующей команды:

Теперь шлюз разрешает доступ к порту 80, но не имеет представления о том, куда маршрутизировать запросы. Для этого понадобятся Virtual Services.

Ресурс VirtualService

VirtualService указывает Ingress Gateway’ю, как маршрутизировать запросы, которые разрешены внутри кластера.

Запросы к нашему приложению, приходящие через http-gateway, должны быть отправлены в сервисы sa-frontend, sa-web-app и sa-feedback:

Stories injection enabled что это. Смотреть фото Stories injection enabled что это. Смотреть картинку Stories injection enabled что это. Картинка про Stories injection enabled что это. Фото Stories injection enabled что это
Маршруты, которые необходимо настроить с VirtualServices

Рассмотрим запросы, которые должны направляться на SA-Frontend:

Применим VirtualService вызовом:

Примечание: Когда мы применяем ресурсы Istio, Kubernetes API Server создаёт событие, которое получает Istio Control Plane, и уже после этого новая конфигурация применяется к прокси-серверам Envoy каждого pod’а. А контроллер Ingress Gateway представляется очередным Envoy, сконфигурированным в Control Plane. Всё это на схеме выглядит так:

Stories injection enabled что это. Смотреть фото Stories injection enabled что это. Смотреть картинку Stories injection enabled что это. Картинка про Stories injection enabled что это. Фото Stories injection enabled что это
Конфигурация Istio-IngressGateway для маршрутизации запросов

Перед тем, как продолжить, поработайте немного с приложением, чтобы сгенерировать трафик (его наличие необходимо для наглядности в последующих действиях — прим. перев.).

Kiali : наблюдаемость

Чтобы попасть в административный интерфейс Kiali, выполните следующую команду:

… и откройте http://localhost:20001/, залогинившись под admin/admin. Здесь вы найдете множество полезных возможностей, например, для проверки конфигурации компонентов Istio, визуализации сервисов по информации, собранной при перехвате сетевых запросов, получения ответов на вопросы «Кто к кому обращается?», «У какой версии сервиса возникают сбои?» и т.п. В общем, изучите возможности Kiali перед тем, как двигаться дальше — к визуализации метрик с Grafana.

Stories injection enabled что это. Смотреть фото Stories injection enabled что это. Смотреть картинку Stories injection enabled что это. Картинка про Stories injection enabled что это. Фото Stories injection enabled что это

Grafana: визуализация метрик

Собранные в Istio метрики попадают в Prometheus и визуализируются с Grafana. Чтобы попасть в административный интерфейс Grafana, выполните команду ниже, после чего откройте http://localhost:3000/:

Кликнув на меню Home слева сверху и выбрав Istio Service Dashboard в левом верхнем углу, начните с сервиса sa-web-app, чтобы посмотреть на собранные метрики:

Stories injection enabled что это. Смотреть фото Stories injection enabled что это. Смотреть картинку Stories injection enabled что это. Картинка про Stories injection enabled что это. Фото Stories injection enabled что это

Здесь нас ждёт пустое и совершенно скучное представление — руководство никогда такое не одобрит. Давайте же создадим небольшую нагрузку следующей командой:

Вот теперь у нас гораздо более симпатичные графики, а в дополнение к ним — замечательные инструменты Prometheus для мониторинга и Grafana для визуализации метрик, что позволят нам узнать о производительности, состоянии здоровья, улучшениях/деградации в работе сервисов на протяжении времени.

Наконец, посмотрим на трассировку запросов в сервисах.

Jaeger : трассировка

Трассировка нам потребуется, потому что чем больше у нас сервисов, тем сложнее добраться до причины сбоя. Посмотрим на простой случай из картинки ниже:

Stories injection enabled что это. Смотреть фото Stories injection enabled что это. Смотреть картинку Stories injection enabled что это. Картинка про Stories injection enabled что это. Фото Stories injection enabled что это
Типовой пример случайного неудачного запроса

Запрос приходит, падает — в чём же причина? Первый сервис? Или второй? Исключения есть в обоих — давайте посмотрим на логи каждого. Как часто вы ловили себя за таким занятием? Наша работа больше похожа на детективов программного обеспечения, а не разработчиков…

Это широко распространённая проблема в микросервисах и решается она распределёнными системами трассировки, в которых сервисы передают друг другу уникальный заголовок, после чего эта информация перенаправляется в систему трассировки, где она сопоставляется с данными запроса. Вот иллюстрация:

Stories injection enabled что это. Смотреть фото Stories injection enabled что это. Смотреть картинку Stories injection enabled что это. Картинка про Stories injection enabled что это. Фото Stories injection enabled что это
Для идентификации запроса используется TraceId

В Istio используется Jaeger Tracer, который реализует независимый от вендоров фреймворк OpenTracing API. Получить доступ к пользовательского интерфейсу Jaeger можно следующей командой:

Теперь зайдите на http://localhost:16686/ и выберите сервис sa-web-app. Если сервис не показан в выпадающем меню — проявите/сгенерируйте активность на странице и обновите интерфейс. После этого нажмите на кнопку Find Traces, которая покажет самые последние трейсы — выберите любой — покажется детализированная информация по всем трейсам:

Stories injection enabled что это. Смотреть фото Stories injection enabled что это. Смотреть картинку Stories injection enabled что это. Картинка про Stories injection enabled что это. Фото Stories injection enabled что это

Этот трейс показывает:

Stories injection enabled что это. Смотреть фото Stories injection enabled что это. Смотреть картинку Stories injection enabled что это. Картинка про Stories injection enabled что это. Фото Stories injection enabled что это
(A) За проброс заголовков отвечает Istio; (B) За заголовки отвечают сервисы

Istio делает основную работу, т.к. генерирует заголовки для входящих запросов, создаёт новые span’ы в каждом sidecare’е и пробрасывает их. Однако без работы с заголовками внутри сервисов полный путь трассировки запроса будет утерян.

Необходимо учитывать (пробрасывать) следующие заголовки:

Это несложная задача, однако для упрощения её реализации уже существует множество библиотек — например, в сервисе sa-web-app клиент RestTemplate пробрасывает эти заголовки, если просто добавить библиотеки Jaeger и OpenTracing в его зависимости.

Заметьте, что приложение Sentiment Analysis демонстрирует реализации на Flask, Spring и ASP.NET Core.

Теперь, когда стало ясно, что мы получаем из коробки (или почти «из коробки»), рассмотрим вопросы тонко настраиваемой маршрутизации, управления сетевым трафиком, безопасности и т.п.!

Прим. перев.: об этом читайте в следующей части материалов по Istio от Rinor Maloku, переводы которых последуют в нашем блоге в ближайшее время. UPDATE (14 марта): Вторая часть уже опубликована.

Источник

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

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