Размышлизмы о контейнерах: Крупноблочное строительство

puzzel-stukСтатья-размышление о прекрасном мире крупноблочного проектирования софта, где нет (почти) проблем совместимости системных библиотек, «оторванного» канала связи во время деплоя, хитромудрых вопросов администрирования ОС.

Постановка

Началась история с того, что решил я настроить Sonatype Nexus для репозитория Docker-образов. Ну коль Docker, то почему бы заодно и не потренироваться в этом самом крупноблочном проектировании софта.

nginx-nexus-ansible-docker

Имеем исходные:

  • Docker Registry (х.з. как там срастётся с Nexus’ом, пока решили образа складировать в родной Docker-репозитарий)
  • Sonatype Nexus Repository (Nexus будет настроен для проксирования запросов к внешним и внутренним репозитариям, при этом он будет кэшировать все запрашиваемые образы, чтобы в следующий раз за ними далеко, скажем, на DockerHub не лазить)
  • Nginx (накручивает поверх Nexus’овских портов всякие SSL, TLS, HTTPS и пр.)

В общем и целом схема нашего приложения могла бы выглядеть так:

Software repository (principal schema)Для иллюстрации процедуры запуска нашего мультиконтейнерного приложения будем использовать нотацию Ansible (да, можно и Swarm).

docker-1024x347

Docker Registry

Запуск контейнера в Ansible мог бы выглядеть так:

Обратим внимание на restart_policy: always. Эта настройка заставляет Docker-демона перезапускать контейнер каждый раз, как он по какой-либо причине «упадёт». Это свойство может быть полезно тем, кто своей работе привык использовать решения на базе supervisord.

Параметр ports перечисляет, какие порты внутри контейнера (справа от «:») «прокинуть» на порты (слева от «:») хостовой системы. К примеру:

в этом примере приложение, слушающее внутри контейнера 43ий порт, станет доступным на порту 4343 в хостовой системе.

volumes — если необходимо, что часть хостовой файловой системы была примонтирована внутрь контейнера, например, чтобы иметь доступ к файлам, в которых Docker Registry хранит физически образы контейнеров, без необходимости каким-либо образом взаимодействовать с Docker.

 

Sonatype Nexus Repositorysonatype-nexus_logo-stacked_whiteBG

При запуске Nexus помимо выше описанных параметров будут использоваться ещё пара

  • links — сообщает Docker’у, что необходимо доменное имя registry внутри контейнера (справа от «:») наделить свойствами необходимыми для сетевого взаимодействия с Docker-контейнером с именем (name) registry (слева от «:»). В моём простом примере два этих имени одинаковые (registry), но, в принципе, они могут не совпадать. links — позволяет далее, при настройке репозитариев в Nexus, так и писать в панели управления — registry. DNS внутри контейнера (внутри которой исполняется и панель управления Nexus) будет давать верный IP-адрес нужного контейнера registry, который мы создали перед этим.
  • name — этот параметр, как мы только что выяснили, позволяет посредством links разным контейнерам на одной хостовой системе «видеть» друг друга в сети.
  • expose — приложение внутри контейнера может использовать такие сетевые порты, про которые и думать не могли разработчики Docker-образов. Чтобы они могли быть доступны извне, необходимо их перечислить с помощью параметра expose (ports автоматически этого не делает).

Nginxnginx

Ansible-код для nginx ничем не примечателен кроме того, что содержит в себе пример того, как можно передавать настройки контейнеру путём монтирования папки с конфигурационными файлами. Для этого используется уже известный по первому примеру параметр volumes.

Ещё можно привести кусок конфига nginx для демонстрации взаимодействия name и links:

внутри контейнера registry будет резолвиться в адрес контейнера с именем (name) registry, об этом мы и сообщаем параметром links, затронутым в этом тексте ранее.

Внимание!!!

Помните про expose при конфигурации сервисов типа nginx и HAproxy!!! Буквально сегодня потратил пару часов с непривычки, разбираясь с чего это сервис недоступен снаружи 🙂

Заключение

Использование Docker через Ansible конечно интересно, но на самом деле эта статья не об этом, а о том, что в представленном выше коде совсем отсутствует информация о том, что же внутри контейнеров находится, из чего они состоят, какие технологии и ядра операционок используют. В общем случае, ваша платформа должна позволить установить Docker-демон и клиента, чтобы начать собирать приложения состоящие из взаимодействующих контейнеров.

Пространные размышления

Сборка приложения из контейнеров, очень для меня, как радиофизика по базовому образованию :-), напоминает разработку электронных устройств из микросхем.

Действительно, микросхемы — это эдакие чёрные ящички, и, чтобы начать работать с ними, инженеру совсем не обязательно знать, какие внутри этих чёрных ящичков p-n-p переходы, сколько там миллионов транзисторов, и как эти транзисторы там внутри соединены.

микросхемыНаличие готовых микросхем, скрывающих за своим невзрачным корпусом весьма навороченные структуры и логику взаимодействия, позволяет после прочтения сравнительно простой документации (простой по сравнению с тем путём, что прошла научная и инженерная мысль за последние лет 50) начать проектировать достаточно сложные и, вместе с тем, достаточно надёжные устройства.

Позволяет перейти от ручного создания таких вот плат с паяльником в руках (php, pip, npm, bower, bash scripts, java, и пр. фарш с его конфигами и нетривиальным деплойментом):

страшная-плата

К очень технологичному процессу проектирования из готовых блоков:

kicadи автоматическому производству (Mesos, Docker Swarm, Kubernetes, etc.?)

монтаж-печатных-плат

∗∗∗

Другая ассоциация: в каких-то случая проектирование из готовых блоков Docker-контейнеров подобна игре в пазл, когда необходимо повернуть части таким образом, чтобы они наилучшим образом подошли друг к другу. И, поскольку края частей имеют единообразный рисунок обреза, можно в какой-то степени абстрагироваться от формы каждой из частей, и больше сконцентрироваться на общей картине.

puzzel-stuk∗∗∗

Попробовал донести, что меня особенно возбудило в использовании контейнеров. Не знаю, получилось ли, но я старался 🙂