Docker, часть вторая. Полуавтоматическая винтовка с самонаведением на ногу

  • Tutorial
Пожалуйста, начинайте читать с начала серии: habrahabr.ru/post/267441

Как не надо использовать Docker.



Чтобы понимать эту статью надо знать базовые команды Dockerfile для создания изображений и принципы объектно-ориентированного дизайна.

Открываю документацию любого официального образа сервисного ПО — например, Nginx и нахожу раздел «How to use this image». Нам предлагают создать свой образ на базе официального, скопировав в него наши файлы, настроить мапинг порта в мир, и подмонтировать свою папку с конфигами.

FROM ...
COPY  . /usr/src/myapp
WORKDIR /usr/src/myapp

Да, нам предлагают унаследовать Model от View в одном звездном классе и заплатить за хранение на Docker Hub образов наших проприетарных приложений. Business, as usual. Это же нам предлагают сделать в образах PHP, Pyhon, Ruby, и так далее. Для Python и Ruby даже сделаны версии с ONBUILD-триггерами на построение изображений-наследников, которыми приложение из папки будет скопировано в новый образ, «which should be all you need» — как 640 килобайт.

К счастью, решение известно так же давно как проблема. Банда четырех, создатель Java Джеймс Гослинг и Фаулер последние 20 лет твердят: используйте композицию вместо наследования. Поэтому я положу рядом контейнеры с разными сервисами, создам адаптер, data transfer object, и свяжу их через конфиг.

Наследование я использую для расширения существующего функционала в рамках инкапсуляции с учетом принципа подстановки Лисков — например, для подключения к php нужных мне расширений и системных библиотек, которые эти расширения используют.

Продолжение можно найти здесь
Share post

Similar posts

Comments 48

    +2
    Погодите. Т.е. вы считаете, что исходный код внутри контейнера — это трэш и угар?
    Поэтому нужно его выделять в отдельный data container, или что контейнеры-контейнерами, а исходный код на целевой сервер должен поставляться каким-то боком и монтироваться в контейнер через volume с хостовой машины?
      +5
      ага и потом 20 контейнеров и своя система развертывания этих контейнеров, по сложности превышающая настройку сервера без докера, к половине приложений костыли и десяток супервизоров (если что — я так не считаю, это они так считают)
        –2
        Конечно, это нужно немногим. Может быть, кому-нибудь мои статьи будут полезны.
        0
        Glueon, про Data Volume container и распространении приложения в нем есть отдельная статья.
          0
          Вы про свою? понял, что про свою.
          0
          А зачем хранить на сервере исходный код и среду сборки? Да для разработки это удобно, но в продакшне ни то, ни другое не нужно. Там даже шелл не стоит хранить, если он не нужен самому приложению.
          +2
          ИМХО, на статью не тянет. Философия Docker:

          1. Артефакт работы программиста — не исходный код, не дистрибутив приложения, а контейнер, который включается на любой физической машине одной кнопкой «вкл» (при условии, что на машине установлен Docker).
          2. Образ Docker типа Nginx — это не веб-сервер, запакованный в контейнер, а веб-фреймворк, который работает поверх голой ОС. Ваше решение — это не «программа, которая хостится внутри Nginx», а просто «очень сильно кастомизированный Nginx» (иногда настолько кастомизированный, что конфигов не хватило и «пришлось написать плагин»)
            0
            Каждое слово, вроде бы, понятно, но текст в целом не понимаю, простите :)
            Nginx — это веб-серевер, а не фреймворк, и ничем из него фреймворк не сделать. Удобно хранить вместе приложение и runtime — ради бога, эти статьи для тех, кому надо разделять.
              0
              docker.com:
              Package your application, dependencies and configurations together to ensure that your application will work seamlessly in any environment on any infrastructure just like it did on your machine.

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

              Это официальная точка зрения команды Docker на то, что они делают и как это использовать.

              По поводу:
              Nginx — это веб-серевер, а не фреймворк

              Вики:
              A web application framework (WAF) is a software framework that is designed to support the development of dynamic websites, web applications, web services and web resources.

              Вики:
              In computer programming, a software framework is an abstraction in which software providing generic functionality can be selectively changed by additional user-written code, thus providing application-specific software.

              Укажите пожалуйста по каким причинам Nginx нельзя относить к веб-фреймворкам.
                0
                nginx предназначен не для поддержки разработки, а для эксплуатации. Что у него есть возможность расширения функциональности через плагины делает его фреймворком только для разработчиков плагинов.
                  0
                  Смотрите:
                  Port 80 -> Docker -> Nginx -> uWSGI -> Django -> My Code

                  1. Общепринятое мнение, что веб-фреймворк — это Django.
                  2. Мнение в духе Docker: веб-фреймворк — это всё что от Docker и до Django.

                  В первом случае мы говорим о том, что есть какой-то сайт, сделанный на фреймворке Django, и его нужно запускать на каком-то веб-сервере. Во втором случае мы говорим о том, что есть какой-то сайт, сделанный на фреймворке «Docker/Nginx/uWSGI/Django» и его можно запускать на любой «голой» ОС.
                      0
                      Скорее так: Port 80 -> Docker -> Nginx -> uWSGI -> Django -> My Code -> Django -> uWSGI -> Nginx -> Docker -> Port 80

                      То есть c моим кодом взаимодействует (вызывает его и обрабатывает результаты вызовов) только Django, а остальные звенья лишь транслируют запросы и ответы. Мне как разработчику нужно только API Django изучить, если в мои задачи не входит подготовка готового к выкладке на продакшен образа/пакета, а она, как правило, не входит — администрирование связки этих продуктов сама по себе нетривиальная задача, достаточная для выделение под неё «специально обученного человека».
                        0
                        В цепочке еще СУБД, i/o и memcached/redis/etc. Junior-у, который клепает формочки Django хватит, а senior и архитектор обязаны учитывать детали всего стека.
                0
                1. То есть никаких внешних ресурсов типа собственно кода приложения и его баз данных? Контейнер (или набор типа веб-сервер, апп-сервер, БД-сервер) самодостаточен и обеспечивает персистентность? Или в философии Докера персистентность данных приложения не нужна и если контейнер упал или его удалили, то приложение начинает жизнь с ноля?

                2. Разве веб-фреймворк, а не основа для контейнера, который представляет собой (для админа) «чёрный ящик» с несколькими входами и выходами?
                  –1
                  1. Персистентность реализуется через Data Volume container.
                  2. Простите, не понимаю, разве веб-фреймворк что? Уточните, пожалуйста.

                  В целом, Docker размывает границы между админами и разработчиками — разработчики начинают заботиться о настройках системных служб и включают их конфигурацию в контейнер.
                    0
                    1. Я так понимаю работу с помощью докер с типичным веб-приложением: готовим (или берём готовыми) три универсальных образа для веб-, апп- и бд-сервера. Готовим конфиги, исполняемый код (бинарники или скрипты) и данные для них. Готовим сценарий выкладки (с помощью compose, bash, ...) по которому поднимается контейнеры бд с прилинкованными (или скопированными) конфигами и данными, аппа с прилинкованными (или скопированными) конфигами и исполняемым кодом, веба с прилинкованными (или скопированными) конфигами и статикой. Результат работы разработчика — образы или их докерфайлы, исполняемый код, начальные конфиги, данные или ссылки на них и сценарий подъёма всего этого добра. Админы запускают сценарии, при необходимости правя конфиги, пути и т. п., чтобы они соответствовали хосту и окружению в котором поднимаются контейнеры.

                    2. Я засомневался в утверждении «это не веб-сервер, запакованный в контейнер, а веб-фреймворк». Разве фреймворк, а не чёрный ящик?

                    Хм, то есть я как разработчик должен решать, например, сколько воркеров создавать тому же nginx, не зная даже сколько процессоров на хосте, на который решит выложить мой проект админ? Как по мне в конфиги nginx я должен вписать пути и прочие зависимости от проекта, а админ уже должен регулировать параметы, которые зависят от среды, хоста, доступного железа и т. п.
                      0
                      1. Всё верно: программист делает «детский конструктор из кубиков», а «админ из этих кубиков в своей песочнице строит какую-нибудь крепость».
                      2. Вы не должны принимать решения, которые зависят от среды исполнения. Количество воркеров — это такой же конфигурационный параметр, как коннекшн стринг к базе. Совершенно точно будут параметры, которые вы захотите железно захардкодить и запретить админам их изменять, но будут и параметры, которые вы захотите сделать частью интерфейса. Например внутренний параметр «количество воркеров Nginx» вы можете пробросить как внешний параметр «количество ядер для использования». Типа абстракция такая.
                        0
                        Вопрос скорее не в том, что я захочу сделать частью интерфейса для админов, а что хочу от них скрыть, а это, думаю, значительно меньшая часть всех настроек.
                          0
                          Так никто ж не запрещает договориться с админами, чтобы они делали свой «правильный базовый образ» где либо всё уже настроено, либо нужные параметры выставлены наружу, а вы бы на основе этого образа строили свой, включающий собственно приложение. В итоге у вашего образа будут доступны и оригинальные админские параметры, и те, что добавили вы.
                            0
                            Конечно, но у меня другая цель. Все мое приложение, полный стек, включая базу данных, конфиги и библиотеки для runtime и веб-сервера — это один архив размером в пару мегабайт. Все запускается двумя командами из консоли без необходимости настройки системы, но с возможностью настроить все, что угодно. Каждая служба работает независимо, ставится автоматически и не требует участия админа вообще.
                            Админ может доработать конфиги на production, какие захочет.
                            А я могу отдать свой архив заказчику как результат работы.
                    0
                    1. Внешние ресурсы подключаются через «позднее связывание». У типичного веб-приложения, завёрнутого в Dockerfile будет несколько параметров типа коннекшн стринга для БД. Значения для этих параметров указываются при запуске контейнера.
                    2. Всё верно: для админа это действительно чёрный ящик с понятным интерфейсом, у которого с одной стороны, например, открытый серверный сокет, а с другой — несколько конфигурационных параметров типа того же коннекшн стринга. Запускаешь и работает. Но это для админа. А программист отвечает за реализацию того, что внутри этого ящика — за детали реализации. Вот с точки зрения «решения» Nginx — это веб-фреймворк.
                      0
                      В моем случае параметры можно просто указать в файле конфигурации. Конфиг субд и дамп базы распространяются в одном архиве с приложением, все установится и запустится само, без участия админа одной командой, причем, не только на production, но и локально. Админ может поправить параметры на production — все конфиги «торчат» из контейнера.
                        +1
                        все установится и запустится само, без участия админа

                        Очень смелое утверждение, причём особенно касательно production. Без участия админа пробросятся 80 и 443 порт? Без участия админа установится сам докер?
                        0
                        Дополню, что админу ничто не мешает изменить настройки чего-либо у уже работающего контейнера и сделать commit.
                          0
                          commit и push изменят эти настройки у всех в команды разработчиков, а мне совсем не нужно значение innodb_buffer_pool_size=32Gb на локальной виртуалке
                            0
                            commit без push… а зачем? там они потеряются при выкладке новой версии. пусть они лежат все вместе в отдельной папке прямо под рукой у админа и монтируются в контейнер, не надо открывать shell в контейнере чтобы отредактировать конфиг, а в контейнере пусть лежат дефолтные значения,
                      +5
                      Статья ужасна (вернее её нет).

                      Выстрел в ногу это то как использую доскер я:

                      cd /tmp/шото
                      make
                      make install
                      
                        –2
                        в огороде бузина, в городе дядька :)
                          0
                          Что вы пытаетесь этим сказать?
                            –1
                            У меня возникли такие же ощущения, когда я прочитал ваш комментарий, как у вас, когда вы прочитали мой. Предлагаю перейти к осмысленному диалогу с вопросами, предложениями или замечаниями в контексте этой серии статей. Ваши ощущения — это очень важно, но только для вас.
                              0
                              Вот, например:
                              Открываю документацию любого официального образа сервисного ПО — например, Nginx и нахожу раздел «How to use this image». Нам предлагают создать свой образ на базе официального, скопировав в него наши файлы, настроить мапинг порта в мир, и подмонтировать свою папку с конфигами.

                              FROM…
                              COPY. /usr/src/myapp
                              WORKDIR /usr/src/myapp

                              Да, нам предлагают унаследовать Model от View в одном звездном классе и заплатить за хранение на Docker Hub образов наших проприетарных приложений.


                              1. Пример приведён из доков по php, хотя по тексту об nginx речь идёт.

                              2. Предлагают, первым делом, не унаследовать «звёздный класс» типа
                              class DockerNginx extends DockerDebian
                              {
                                  public function __construct()
                                  {
                                      $this->install('nginx');
                                      /// some other init...
                                  }
                              
                                  public function run()
                                  {
                                      $this->cmd('nginx')
                                  }
                              }
                              
                              , а инстанцировать и запустить его, предварительно установив свойство /usr/share/nginx/html. Типа
                              $some_nginx = new DockerNginx();
                              $some_nginx->fs->root->share->nginx->html = $host->fs->pwd->static-html-directory;
                              $some_nginx->run();
                              

                              Во вторую очередь предлагают унаследовать «звёздный класс», переопределив это свойство (относящееся в рамках nginx исключительно к Model, если рассматривать его как MVC приложение) в конструкторе, типа:
                              class SomeContentNginx extends DockerNginx
                              {
                                  public finction __construct()
                                  {
                                      $this->fs->root->share->nginx->html = clone ($host->fs->pwd->static_html_directory);
                                  }
                              }
                              
                              $some_nginx = new SomeContentNginx();
                              $some_nginx->run();
                              

                              То есть продемонстрированы две основные возможности изменения функциональности объекта: инъекция желаемой зависимости в объект вместо дефолтной после инстанцирования объекта перед началом его использования и унаследование класса в котором желаемая зависимость устанавливается при его инстанцировании перед началом использования. За рамками документации класса DockerNginx остаются как другие способы инжектирования Docker, так и свойства, которые можно инжектировать в Nginx, поскольку предполагается, что пользователь, которому они нужны достаточно знаком с обеими системами или хотя бы способен почитать документацию по ним, чтобы максимум за пару часов собрать свой универсальный образ согласно своим практикам использования nginx и Docker, например использования его во всех своих проектах с помощью docker-composer, подключая тома или линки.

                              3. В данной документации вообще ничего не говорится о хранении наших «проприетарных» образов, даже их создание преподносится лишь как один из доступных вариантов решения задачи, а платное хранение на официальном хабе докера тоже лишь как один из вариантов в документации по докеру, который (вариант) хорошо подходит для случая, когда в паблик образ выкладывать нежелательно, шарить образ (или его докерфайл) между разработчиками, админами, тестерами и т. д. универсальными средствами (ОС, шаред в локалке, облачные сервисы хранения файлов и т. д.) неудобно, а поднимать свою инфраструктуру докера нет желания или возможности.
                                0
                                SomeContentNginx extends DockerNginx вносит зависимость от DockerNginx.
                                классический вопрос проектирования, лучше обратиться к Фаулеру www.martinfowler.com/articles/injection.html
                                  0
                                  А без этой зависимости никак не обойтись тут. Ваши скрипты точно так же зависят от DockerNginx в docker pull nginx, просто вы используете не наследование. Но и не композицию, а патчите инстанс $some_nginx класса DockerNginx после его инстанцирования.
                                    0
                                    В моем случае это не зависимость вида «DockerNginx», а реализация интерфейса iNginx. Я могу прозрачно подменить MariaDB на Oracle MySQL в команде запуска, а контейнер с приложением не изменится.
                                      0
                                      Вот что не хватает вашей серии статей — картинки (или хотя бы списка) с описанием конечного результата. Что вы имеете в виду под контейнером с приложением? У вас 4 контейнера в приложении всего? nginx, php, mysql и приложение?
                                        0
                                        Да, я это уже понял.

                                        Конечный результат — образ в виде .tar.xz размером 2-5 мегабайт с приложением и конфигами. На его основе которого я парой команд где угодно поднимаю весь стек целиком: база, nginx/tomcat, php/python/java, mysql/postgres, и мое приложение.
                                        Количество контейнеров не имеет значения. Важно, что один или два маленьких файла автоматизируют создание любого полного стека, не ограничивая в конфигурировании.

                                        Дело в том, что я не планировал писать подробную книгу и объяснять основы построений модульной архитектуры. Я написал это для своих, а хабр неудобен для публикации связанных развернутых материалов, это новостная лента.
                                          0
                                          Стандартный образ Docker? Или просто заархивированный каталог, в котором скрипты сборки и запуска (compose или bash — не суть) веб, апп и бд контейнеров + линковка/копирование к ним конфигов и собственно исполняемого кода (php, python или sql — тоже не суть)?

                                          Я просто не пойму до конца вашу идею: функциональность compose (жонглирование контейнерами и внешними ресурсами после скачивания образов и сздания контейнеров, но до их запуска) через bash или какой-то абсолютно другой подход? Кстати, как в вашем подходе решается задача поднятия веб-, апп- и бд-серверов на разных хостах?
                                0
                                С удовальствием бы с вами поспорил буть бы сейчас время, в замену предлагаю вам ещё раз перечитать коментарии других пользователей и хорошенько над ними помидитировать.
                                  –3
                                  я это писал не для хабра, а для своего террариума :) где люди разбираются в архитектуре, а мнение хабра меня волнует чуть меньше чем почти никак ;)
                                    0
                                    Тогда зачем эта статья здесь?
                                      –2
                                      для тех, кто в теме
                          0
                          А почему нельзя использовать docker compose для таких целей?
                            0
                            можно использовать, а можно и обойтись без него — по правилу Бритвы Оккама
                              0
                              Мне сие непонятно, видимо потому что я приверженец правила KISS.
                                0
                                значит, symphony, hybernate и микросервисная архитектура не для вас :)
                                  0
                                  symphony и doctrine (вроде как клон hybernate на php) как раз исповедуют принцип «напишите простой конфиг, а всю чёрную работу мы сделаем за вас»
                                    0
                                    Какая связь?

                            Only users with full accounts can post comments. Log in, please.