К примеру, можно передать путь к сертификату и порт прило-жения в виде переменных среды следующим образом: 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 , то это уже будет нарушением интерфейса контейнера и воспрепятствует его корректному применению другими пользователями.
Такой пример, конечно же, очевиден, но нарушить интерфейс контейнера можно гораздо менее явным образом. Допустим, параметр UPDATE_FREQUENCY изначально принимал число секунд.
Со временем, с учетом обратной связи от пользователей, раз-работчик решил, что длительные интервалы (минуты, часы) не-удобно указывать в секундах. Он модифицировал параметр так, Глава 2. Паттерн Sidecar 47
чтобы тот принимал строки (10 минут, 5 секунд и т. п.). Посколь-ку старые значения параметров не смогут быть обработаны но-вым контейнером, такое изменение API окажется критическим. Представьте, что разработчик предусмотрел этот вариант, но сделал так, чтобы значения без единиц измерения интерпрети-ровались как число миллисекунд. Такое изменение, хотя и не приводит к ошибкам, является недопустимым, поскольку при-водит к более частым проверкам конфигурации и, как следствие, большей нагрузке на сервер.
Надеюсь, вы осознали, что для обеспечения настоящей модуль-ности необходимо внимательно относиться к предоставляемому вашим контейнером программному интерфейсу. Критические изменения могут быть вызваны менее очевидными, нежели смена имени параметра, причинами.
Документирование контейнеров На данный момент вы уже умеете параметризовать свои контей-неры, чтобы они были модульными и их можно было повторно использовать. Вы уже знаете, насколько важно поддерживать стабильный программный интерфейс вашего контейнера, чтобы обеспечить его бесперебойную работу у конечных пользовате-лей. Но есть еще один шаг к построению модульных, повторно используемых контейнеров — предоставить пользователям ин-формацию, как их применять в принципе.
Как и в случае с программными библиотеками, ключ к созданию полезной вещи — объяснение, как ею пользоваться. Мало поль-зы в создании гибкого, надежного, модульного контейнера, если никто не может понять, как с ним работать. К сожалению, на сегодняшний день доступно не так много формальных инстру-ментов, позволяющих документировать образы контейнеров, но есть несколько полезных приемов, упрощающих работу. 48Часть I. Одноузловые паттерны проектирования
У каждого контейнера есть конфигурационный файл Dockerfile , на основе которого строится образ контейнера. Именно в нем в первую очередь стоит искать документацию к контейнеру. Некоторые части Dockerfile документируют работу контей-нера сами по себе. Одним из примеров может служить дирек-тива EXPOSE , в которой перечислены сетевые порты, открытые в контейнере. Указывать ее не обязательно, но это считается хорошим тоном. Неплохо также снабдить ее комментарием, поясняющим, какой конкретно сервис прослушивает данный порт. Например:
Читать дальше