Распределенные системы. Паттерны проектирования - страница 15
Модульность и возможность повторного применения, как и до-стижение модульности в разработке высококлассного про-граммного обеспечения, требуют сосредоточенности и дисци-плины. В частности, необходимо сконцентрироваться на таких трех составляющих, как:
> параметризация контейнеров;
> создание программного интерфейса контейнеров; > документирование работы контейнера. Параметризованные контейнеры Параметризация контейнеров — важнейший показатель дости-жения модульности и повторного использования контейнеров, независимо от того, реализуют они паттерн Sidecar или нет. Что я понимаю под параметризацией? Представьте, будто кон-тейнер — это функция в программе. Сколько у нее параметров? Каждый параметр представляет собой входные данные, которые помогают подстроить обобщенный контейнер под конкретную ситуацию. Рассмотрим, к примеру, контейнер-прицеп с SSL, который мы развернули ранее. Чтобы быть полезным в общем случае, он должен иметь по меньшей мере два параметра: имя сертификата, обеспечивающего функциональность SSL, и порт унаследованного сервера приложений, запущенного на ло-кальной машине. Без этих параметров трудно сказать, что он будет полезен для широкого спектра приложений. Похожие параметры есть во всех контейнерах-прицепах, рассмотренных в данной главе.
Глава 2. Паттерн Sidecar 45
Теперь, когда мы знаем, какие параметры предоставить, остает-ся вопрос: как их, собственно, предоставить и использовать их значения в рамках контейнера. Параметры контейнеру можно передавать двумя способами — через переменные среды или через командную строку. И хотя оба они допустимы, в общем случае я предпочитаю передавать параметры с помощью пере-
менных среды. Пример передачи параметра контейнеру: docker run -e=PORT=<порт> -d <образ>
Передача значений в контейнер — только половина успеха. Другая половина — собственно использование значений пере-менных внутри контейнера. Обычно это реализуется в рамках сценариев оболочки. Такой сценарий подгружает переменные среды, переданные контейнеру-прицепу, и на их основе либо корректирует конфигурационные файлы, либо параметризует базовое приложение.
К примеру, можно передать путь к сертификату и порт прило-жения в виде переменных среды следующим образом: docker run -e=PROXY_PORT=8080 \
-e=CERTIFICATE_PATH=/путь/к/сертификату.crt ... Сценарий в контейнере воспользуется значениями этих перемен-ных для формирования конфигурационного файла nginx.conf , который укажет серверу, где искать файл сертификата и куда переадресовывать запросы.
Определение API всех контейнеров Если учитывать, что вы параметризуете свои контейнеры, будет очевидно, что каждый из них определяет некую «функцию», кото-рая вызывается при запуске контейнера. Эта функция является ча-стью API, определяемого вашим контейнером, но у него есть и дру-гие составляющие, включая вызовы к внешним по отношению 46 Часть I. Одноузловые паттерны проектирования
к контейнеру сервисам и предоставляемые контейнером API-услуги, доступные по HTTP или любым другим способом. Думая о модульности и повторном использовании контейнеров, важно понимать, что программный интерфейс (API) контейнера определяется всеми его аспектами взаимодействия с внешней средой. Как и в среде микросервисов, микроконтейнеры рас-считывают на наличие некоторого программного интерфейса, который бы четко разделил основное приложение и контей-нер-прицеп. Кроме того, наличие API гарантирует, что все по-требители контейнера-прицепа будут работать корректно даже после выхода последующих его версий. В то же время наличие четкого API у контейнера-прицепа позволяет его создателю более эффективно работать, поскольку в этом случае у него есть четкое определение услуг, предоставляемых контейнером (а желательно и юнит-тестов для них).
Чтобы понять, насколько важно уделять внимание API кон-тейнера, рассмотрим упомянутый ранее контейнер-прицеп для управления конфигурацией. Для него мог бы оказаться полез-ным параметр UPDATE_FREQUENCY , задающий частоту, с которой необходимо синхронизировать конфигурацию с файловой си-стемой. Очевидно, что если название параметра потом поменя-ется на, скажем, UPDATE_PERIOD , то это уже будет нарушением интерфейса контейнера и воспрепятствует его корректному применению другими пользователями.