Паттерн Ambassador (Посредник) — это специализированный вариант паттерна Sidecar (Прицеп), отвечающий за сокрытие сложности и предоставляющий унифицированный интерфейс для доступа к службам за пределами пода. В этой главе мы увидим, как паттерн Ambassador (Посредник) может выступать в качестве прокси и ограждать поды от прямого доступа к внешним зависимостям.
Контейнерные службы существуют не в вакууме и часто обращаются к другим службам, надежный доступ к которым может быть затруднен. Сложность доступа к другим службам может быть обусловлена динамическими и изменяющимися адресами, необходимостью балансировки нагрузки между кластерными экземплярами служб, использованием ненадежного протокола или сложных форматов данных. В идеале контейнеры должны быть узкоспециализированными и допускающими возможность многократного использования. Но если у нас есть контейнер, который реализует некоторую важную функцию и особым образом использует внешнюю службу, он будет нести больше одной ответственности.
Для доступа к внешней службе может потребоваться использовать специальную библиотеку обнаружения служб, которую нежелательно помещать в контейнер. Или может понадобиться заменить одни службы другими и использовать другие библиотеки и методы обнаружения служб. Абстрагирование и изоляция логики доступа к другим службам во внешнем мире как раз и являются целью паттерна Ambassador (Посредник).
Продемонстрируем использование паттерна на примере организации кэша для приложения. Для доступа к локальному кэшу в окружении для разработки может быть достаточно определить некоторые настройки в конфигурации, но в промышленном окружении может понадобиться настроить клиент, подключающийся к разным сегментам кэша. Другой пример — поиск службы в реестре для ее обнаружения на стороне клиента. Еще один пример — взаимодействие с внешней службой по ненадежному протоколу, такому как HTTP, из-за чего для защиты приложения приходится использовать логику обработки обрывов связи, настраивать тайм-ауты, выполнять повторные попытки и многое другое.
Во всех этих случаях можно использовать контейнер-посредник, скрывающий сложность доступа к внешним службам и обеспечивающий упрощенное их представление для основного контейнера приложения через локальное сетевое соединение. На рис. 17.1 и 17.2 показано, как контейнер-посредник помогает отделить прикладную логику от логики доступа к хранилищу пар ключ/значение, принимая запросы через локальный порт. На рис. 17.1 видно, как можно делегировать доступ к данным, хранящимся в удаленном распределенном хранилище, таком как Etcd.
Рис. 17.1. Посредник для доступа к удаленному распределенному кешу
Во время разработки такой контейнер-посредник легко заменить локальным хранилищем пар ключ/значение, таким как memcached (как показано на рис. 17.2).
Этот паттерн предлагает те же преимущества, что и паттерн Sidecar (Прицеп) — оба способствуют узкой специализации контейнеров и пригодности их к многократному использованию. При использовании этого
Рис. 17.2. Контейнер-посредник с локальным хранилищем
паттерна приложение может сосредоточиться на решении бизнес-задач и делегировать ответственность за использование внешней службы другому специализированному контейнеру. Это также позволяет создавать специализированные и повторно используемые контейнеры-посредники, которые можно объединять с другими контейнерами приложений.
В листинге 17.1 показано определение посредника, действующего параллельно REST-службе. Прежде чем вернуть ответ, REST-служба журналирует сгенерированные данные, отправляя их по фиксированному URL: http://localhost:9009. Процесс-посредник прослушивает этот порт и обрабатывает данные. В этом примере он просто выводит данные в консоль, но вообще мог бы делать что-то более сложное, например, переслать данные в полноценную инфраструктуру журналирования. Для REST-службы не имеет значения, что происходит с журналируемыми данными, и вы легко можете заменить контейнер-посредник перенастройкой пода, не касаясь основного контейнера.
Листинг 17.1. Посредник для вывода журналируемых данных
apiVersion: v1
kind: Pod
metadata:
name: random-generator
labels:
app: random-generator
spec:
containers:
- image: k8spatterns/random-generator:1.0
name: main
env:
- name: LOG_URL
value: http://localhost:9009
ports:
- containerPort: 8080
protocol: TCP
- image: k8spatterns/random-generator-log-ambassador
name: ambassador
Главный контейнер приложения содержит REST-службу, которая генерирует случайные числа.
Адрес URL для подключения к контейнеру-посреднику через локальное соединение.
Контейнер-посредник, выполняющийся параллельно и прослушивающий порт 9009 (который не экспортируется за пределы пода).
Фактически паттерн Ambassador (Посредник) — это все тот же паттерн Sidecar (Прицеп). Основное отличие между ними заключается в том, что Посредник не добавляет новых возможностей в основное приложение, а просто действует подобно интеллектуальному прокси-серверу, открывающему выход во внешний мир, из-за чего этот паттерн иногда называют Proxy (Представитель).
• Пример реализации паттерна Посредник (http://bit.ly/2FpjBFS).
• Как использовать паттерн Посредник для организации динамически настраиваемых служб (https://do.co/2HxGIQG).
• Динамическое связывание контейнеров Docker с использованием паттерна Посредник (http://bit.ly/2TQ1uBO).
• Организация взаимодействий через контейнер-посредник (https://dockr.ly/2UdTGKc).
• Варианты базового паттерна Посредник (http://bit.ly/2Ju4zmb).