Ответы рабочей системы возвращаются пользователю, а ответы новой версии сервиса игнорируются. Чаще всего такое деление запросов применяется, когда необходимо сымитировать реаль-ную рабочую нагрузку на сервис, не рискуя повлиять на работу пользователей текущей версии.
С учетом предыдущих примеров становится очевидным то, как делитель запросов может взаимодействовать с контейнером приложения для выполнения своей функции. Как и ранее, контейнер приложения просто подключается к сервису, работающему на локальном компьютере. Контей-нер-посол, в свою очередь, получает запросы, проксирует их как рабочей, так и экспериментальной системам, а затем воз-вращает ответы рабочей системы так, как будто сам сделал всю работу.
60Часть I. Одноузловые паттерны проектирования
Такое разделение ответственности позволяет четко ограничить функциональность и размер кода приложений, содержащихся в контейнерах. Разделение приложения на модули дает возмож-ность использовать контейнер с делителем запросов во многих разных приложениях и с различными настройками. Практикум. Реализация 10%-ных экспериментов
Для эксперимента с разделением запросов воспользуемся веб-сервером nginx. Nginx — мощный, многофункциональный веб-сервер с открытым исходным кодом. Чтобы сконфигурировать nginx для применения в контейнере-после, воспользуемся сле-дующей конфигурацией (обратите внимание, что она рассчита-на на HTTP, но ее легко адаптировать под HTTPS): worker_processes 5;
error_log error.log;
pid nginx.pid;
worker_rlimit_nofile 8192;
events {
worker_connections 1024;
}
http {
upstream backend {
ip_hash;
server web weight=9;
server experiment;
}
server {
listen localhost:80;
location / {
proxy_pass http://backend;
}
}
Глава 3. Паттерн Ambassador 61
так, вы добавляете еще один сервис, который нужно поддерживать, масштабировать, мониторить и т. д. Если есть вероятность, что экспериментирование укоренится в вашей архитектуре, в таком решении может быть смысл. Если оно применяется скорее время от времени, то более осмысленным будет использование контейнера-посла на Обратите внимание, что в данной конфигурации я использую хеширование IP. Оно необходимо для того, чтобы пользователь не задействовал попеременно то основную, то тестовую версию сервиса. Благодаря этому пользователи будут взаимодейство-
вать с приложением единообразно.
Весовой коэффициент используется, чтобы 90 % трафика при-ходилось на основное приложение, а 10 % — на тестовую версию. Как и в других примерах, мы будем разворачивать данную кон-фигурацию как объект ConfigMap в Kubernetes. kubectl create configmaps --from-file=nginx.conf Она исходит из того, что сервисы web и experiment уже опре-делены. Если это не так, то вам необходимо их создать до создания контейнера-посла, поскольку nginx не запустится корректно, если не сможет найти сервисы, которым он про-ксирует запросы.
Вот несколько примеров конфигурации:
# Сервис 'experiment'
apiVersion: v1
kind: Service
metadata:
name: experiment
62Часть I. Одноузловые паттерны проектирования
labels:
app: experiment
spec:
ports:
- port: 80
name: web
selector:
# Установите значение данного селектора в соответствии # с метками вашего приложения
app: experiment
---
# Сервис 'prod'
apiVersion: v1
kind: Service
metadata:
name: web
labels:
app: web
spec:
ports:
- port: 80
name: web
selector:
# Установите значение этого селектора в соответствии # с метками вашего приложения
app: web
Затем разворачиваем nginx в роли посла в рамках контейнера: apiVersion: v1
kind: Pod
metadata:
name: experiment-example
spec:
containers:
# Сюда необходимо подставить имя контейнера приложения, # например:
# - name: some-name
# image: some-image
# Здесь указываем имя контейнера-посла
- name: nginx
image: nginx
Глава 3. Паттерн Ambassador 63
volumeMounts:
- name: config-volume
mountPath: /etc/nginx
volumes:
- name: config-volume
configMap:
name: experiment-config
Чтобы воспользоваться контейнером-послом в полной мере, в группу можно добавить еще один или несколько контейнеров. 4 Адаптеры
В предыдущих главах мы рассмотрели, как с помощью паттерна Sidecar расширять и дополнять существующие контейнеры приложений. Мы также разобрали, как контейнеры-послы мо-гут опосредовать и даже изменять способ взаимодействия кон-тейнера с внешним миром. В этой главе описывается последний одноузловой паттерн — Adapter . В его рамках контейнер-адап-тер модифицирует программный интерфейс контейнера прило-жения таким образом, чтобы он соответствовал некоему заранее определенному интерфейсу, реализация которого ожидается от всех контейнеров приложений. К примеру, адаптер может обеспечивать реализацию унифицированного интерфейса мони-торинга. Или же он может обеспечивать то, что файлы журнала всегда выводятся в stdout, а также требовать соблюдения любых других соглашений.
Читать дальше