Паттерн Adapter (Адаптер) позволяет привести гетерогенную контейнерную систему в соответствие с единообразным унифицированным интерфейсом, имеющим стандартизованный и нормализованный формат, который может использоваться внешним миром. Паттерн Adapter (Адаптер) наследует все свои характеристики от паттерна Sidecar (Прицеп), но имеет единственную цель — предоставить адаптированный доступ к приложению.
Контейнеры позволяют унифицировать упаковку и запуск приложений, написанных на разных языках и с использованием разных библиотек. В настоящее время многие команды используют разные технологии и создают распределенные системы, состоящие из гетерогенных (разнородных) компонентов. Эта разнородность может вызвать трудности, когда все компоненты должны обрабатываться другими системами единообразным способом. Паттерн Adapter (Адаптер) предлагает решение, помогающее скрыть сложность системы и предоставить унифицированный доступ к ней.
Этот паттерн лучше проиллюстрировать на примере. Основным условием успешной эксплуатации распределенных систем является всеобъемлющий мониторинг и возможность отправки оповещений. Кроме того, если распределенная система состоит из нескольких служб, для их мониторинга можно использовать внешний инструмент, извлекающий и сохраняющий метрики каждой службы.
Однако службы, написанные на разных языках, могут иметь разные возможности и поставлять метрики в разных форматах, отличных от ожидаемого инструментом мониторинга. Такое разнообразие создает проблему для мониторинга разнородных приложений с использованием единого решения, которое ожидает поддержки единого формата всей системой. Паттерн Adapter (Адаптер) позволяет организовать унифицированный интерфейс мониторинга, экспортируя метрики из различных контейнеров приложений в один стандартный формат и протокол. На рис. 16.1 изображен контейнер-адаптер, который преобразует информацию с метриками, хранящуюся локально, во внешний формат, который понимает сервер мониторинга.
Рис. 16.1. Паттерн Adapter (Адаптер)
При таком подходе каждая служба, представленная отдельным подом, кроме основного контейнера приложения будет включать еще один контейнер, который знает, как прочитать метрики приложения и преобразовать их в формат, понятный инструменту мониторинга. Например, мы можем иметь один контейнер-адаптер, который знает, как экспортировать Java-метрики через HTTP, и другой контейнер-адаптер, в другом поде, который знает, как экспортировать Python-метрики через HTTP. Инструменту мониторинга все метрики будут доступны через HTTP в общем нормализованном формате.
Чтобы познакомиться с конкретной реализацией этого паттерна, вернемся к нашему примеру приложения генератора случайных чисел и создадим адаптер, действующий, как показано на рис. 16.1. При соответствующей настройке он читает файл журнала генератора случайных чисел и извлекает из него время создания случайного числа. Предполагается, что мы должны контролировать это время с помощью Prometheus. К сожалению, формат журнала не соответствует формату, который ожидает Prometheus. Кроме того, мы должны открыть доступ к этой информации через конечную точку HTTP, чтобы сервер Prometheus мог получить ее.
Паттерн Adapter (Адаптер) идеально подходит для этого случая: вспомогательный контейнер запускает небольшой HTTP-сервер и при каждом запросе читает файл журнала и преобразует его в формат, понятный для Prometheus. В листинге 16.1 представлено определение развертывания Deployment с таким контейнером-адаптером. Эта конфигурация избавляет основное приложение от необходимости знать что-либо о Prometheus. Полный пример в нашем репозитории GitHub демонстрирует эту конфигурацию вместе с установкой Prometheus.
Листинг 16.1. Адаптер, преобразующий информацию в формат, понятный Prometheus
apiVersion: apps/v1
kind: Deployment
metadata:
name: random-generator
spec:
replicas: 1
selector:
matchLabels:
app: random-generator
template:
metadata:
labels:
app: random-generator
spec:
containers:
- image: k8spatterns/random-generator:1.0
name: random-generator
env:
- name: LOG_FILE
value: /logs/random.log
ports:
- containerPort: 8080
protocol: TCP
volumeMounts:
- mountPath: /logs
name: log-volume
# --------------------------------------------
- image: k8spatterns/random-generator-exporter
name: prometheus-adapter
env:
- name: LOG_FILE
value: /logs/random.log
ports:
- containerPort: 9889
protocol: TCP
volumeMounts:
- mountPath: /logs
name: log-volume
volumes:
- name: log-volume
emptyDir: {}
Главный контейнер приложения со службой, генерирующей случайные числа, доступной через порт 8080.
Путь к файлу журнала с информацией о времени создания случайных чисел.
Каталог, используемый совместно с контейнером-адаптером.
Образ контейнера, экспортирующего информацию в Prometheus через порт 9889.
Путь к файлу журнала, куда основное приложение записывает интересующую нас информацию.
Общий том монтируется также в контейнер-адаптер.
Общие файлы находятся в томе emptyDir, в файловой системе узла.
Этот паттерн может также использоваться для журналирования. Разные контейнеры могут записывать информацию в разных форматах и с разной степенью детализации. Контейнер-адаптер может нормализовать эту информацию, очистить ее, обогатить контекстной информацией с помощью паттерна Self Awareness (Самоанализ), описанного в главе 13, а затем сделать результат доступным для централизованного агрегатора журналов.
Паттерн Adapter (Адаптер) — это специализированный вариант паттерна Sidecar (Прицеп), описанного в главе 15. Он действует как обратный прокси для гетерогенной системы, скрывая ее сложность за унифицированным интерфейсом. Использование отдельного названия, отличного от названия более общего паттерна Sidecar (Прицеп), позволяет более точно обозначить назначение этого паттерна.
В следующей главе вы познакомитесь с еще одним специализированным вариантом паттерна Sidecar (Прицеп): паттерн Ambassador (Посредник), который действует как прокси, для доступа к службам во внешнем мире.
• Пример реализации паттерна Адаптер (http://bit.ly/2HvFF3Y).
• Инструменты распределенных систем: паттерны контейнеров для создания модульных распределенных систем (https://bit.ly/2U2iWD9).