Пожалуйста, начинайте читать серию заметок с начала, здесь: habrahabr.ru/post/267441

Настройка локально



В этой статье я предполагаю, что служба docker запущена на той же машине, на которой выполняются команды, и у процесса есть доступ на чтение к текущей папке. Еще я подразумеваю, что вы умеете настраивать связку PHP-FPM и Nginx.

Беру образы Nginx и PHP 7.

~$ docker pull nginx
...
~$ docker pull php:7-fpm
Status: Downloaded newer image for php:7-fpm

Теперь у меня есть два чужих класса, которые надо связать вместе через внедрение зависимостей. Самый простой способ добавлять зависимости в чужой код, конечно же, monkeypatching! Сначала создаю контейнеры. Помню о второй сложности программирования — даю контейнерам вразумительные имена, они будут нужны, чтобы контейнеры могли взаимодействовать между собой.

~$ docker create --name=php7 php:7-fpm
3d1b737edfcc3f1102fa54c91f9120da4b86d8cbba3092b6f80156c0e31b4d8f
~$ docker create --name=nginx nginx
80be81b27e012fd061ff4b682f0b7b8803500bc38a4b9f787f91661603b2d4b7


PHP


Начну с PHP — его настроить сложнее. Где лежат конфиги для PHP — можно увидеть в его Dockerfile:
    ENV PHP_INI_DIR /usr/local/etc/php
       --with-config-file-scan-dir="$PHP_INI_DIR/conf.d"     WORKDIR /var/www/html
    COPY php-fpm.conf /usr/local/etc/

Копирую себе из контенера содержимое каталога с файлами конфигурации php
~$ mkdir monkeypatch
~$ cd monkeypatch/
$ docker cp php7:/usr/local/etc localetc
$ ls localetc/
pear.conf        php            php-fpm.conf        php-fpm.conf.default    php-fpm.d
$ ls localetc/php
conf.d

Мейнтейнеры положили в образ php-fpm.conf, но не положили дефолтный php.ini. Придется взять его из исходников php.
$ docker cp "$PHP7:/usr/src/php/php.ini-development" localetc/php/php.ini

Правлю конфиги, как обычно. В какой папке PHP ищет расширения? Узнать можно, запустив php, например, во временном контейнере.

$ docker run --rm php:7-fpm php -i |grep extension_dir
extension_dir => /usr/local/lib/php/extensions/no-debug-non-zts-20141001 => /usr/local/lib/php/extensions/no-debug-non-zts-20141001
$ docker run --rm php:7-fpm ls /usr/local/lib/php/extensions/no-debug-non-zts-20141001
opcache.a
opcache.so

В расширениях только opcache, можно подключить его.
$ echo extension_dir = "/usr/local/lib/php/extensions/no-debug-non-zts-20141001" >>  localetc/php/php.ini
$ echo zend_extension = opcache.so >> localetc/php/php.ini

Пересоздаю контейнер php и монтирую в него папку с конифгами. Путь к монтируемой папке должен быть от корня — служба не знает, из какой папки вызывается клиент docker.
$ docker rm php7
php7
$ docker run -v "$(pwd)/localetc:/usr/local/etc" --name=php7 php:7-fpm php -i |grep Configuration
Configuration File (php.ini) Path => /usr/local/etc/php
Loaded Configuration File => /usr/local/etc/php/php.ini

Теперь можно пересоздать контейнер php7 с тестовым приложением на php. Создатели образа не позаботились о том, чтобы php-fpm работал как демон, так что надо самим запускать его фоном, не освобождая стандартные каналы ввода-вывода.
$ docker rm php7
$ mkdir scripts
$ echo " scripts/test.php
$ docker run -v "$(pwd)/localetc:/usr/local/etc"     -v "$(pwd)/scripts:/scripts"     --name=php7 php:7-fpm &
[29-Aug-2015 15:19:25] NOTICE: fpm is running, pid 1
[29-Aug-2015 15:19:25] NOTICE: ready to handle connections

Пока что для удобства отладки я оставляю вывод из контейнера php-fpm в свою консоль.

NGINX


С Nginx всё просто и стандартно. Копирую на диск папку конфигов:
$ docker cp nginx:/etc/nginx .

В папке nginx/ надо отредактировать nginx.conf, fastcgi_params по вкусу, и создать конфигурационный файл для своего сайта в nginx/conf.d/. Основное для связи nginx с php — это указать в имени хоста имя контейнера с php, а директивы root и SCRIPT_FILENAME должны указывать на путь, который php поймёт в своём контейнере php7.
    location ~ \.php$ {
        fastcgi_pass   php7:9000;
        fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;

Монтирую конфиги в контейнер nginx и запускаю с маппингом 80-го порта контейнера на локальный 8080.
$ docker rm nginx
$ docker run -v "$(pwd)/nginx:/etc/nginx" -p 8080:80 --name=nginx nginx &
$ curl 127.0.0.1:8080/test.php
172.17.0.65 -  29/Aug/2015:15:50:29 +0000 "GET /test.php" 200
Hello world! 7.0.0RC1

Rock'n'Roll!

В версии 1.7 в команде docker run надо указывать параметр --link чтобы в контейнере резолвилось имя другого контейнера. В версии 1.8.1 все работает и без этого параметра.

Логи


Мейнтейнеры образа php решили писать все логи fpm в /proc/self/fd/2, он же STDERR — как error_log, так и access.log. Однако, лог запросов у меня будет писать nginx, а в работе php меня интересуют только ошибки, поэтому предлагаю отредактировать localetc/php-fpm.conf и написать что-то привычное:
error_log = /var/log/php/php-fpm.error.log
;access.log = /proc/self/fd/2 

В Nginx обошлись без самодеятельности, так что включаю access log в конфиге сайта nginx/conf.d/site.ru.conf
access_log  /var/log/nginx/host.access.log  main;

Теперь можно создать папку для логов c правом записи для демона docker и подмонтировать ее в контейнеры. В эту же папку можно писать и вывод контейнеров, при этом контейнеры можно детачить:
$ mkdir log
$ sudo chgrp docker log/
$ sudo chmod g+rwx log/
$ docker stop nginx php7
$ docker rm nginx php7
$ docker run -d --name=php7     -v "$(pwd)/localetc:/usr/local/etc"     -v "$(pwd)/scripts:/scripts"     -v "$(pwd)/log:/var/log/php"     php:7-fpm >>log/docker.php.log 2>&1
$ docker run -d --name=nginx     -v "$(pwd)/nginx:/etc/nginx"     -v "$(pwd)/log:/var/log/nginx"     -p 8080:80     nginx >>log/docker.nginx.log 2>&1
$ curl 127.0.0.1:8080/test.php
Hello world! 7.0.0RC1

Когда надо поменять конфигурацию — можно дать команду перезагрузки php и nginx.
$ docker exec php7 pkill -o -USR2 php-fpm
$ docker exec nginx service nginx reload
Reloading nginx: nginx.

Когда php 7 будет включен в дистрибутив Debian в образе php:7 появится init-скрипт. При желании, можно добавить его самостоятельно из дистрибутива по выбору.

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

Дополнение от 23 сент.
Учитывая уровень баттхерта, который вызвали мои заметки, уточню: у нас разные цели. В моем случае полный стек из приложения, базы, библиотек и всех конфигов поднимается из одного архива размером несколько мегабайт. Я могу его передать по почте, залить на google drive, предоставить заказчику как результат работы, приаттачить к тикету и деплоить на серверах.
Админы хотят поставить registry, зациклить на нем и разработку, и деплоймент, делать его бекапы, мониторить, поднимать когда когда он упадет, быть очень нужными. Нормально, но можно лучше.
Когда у меня приложение с базой и конфигами в одном небольшом файле, весь стек поднимается одной командой, и при этом все службы работают независимо, у меня нет SPOF, бекап может быть хоть прямо в git.
Для транспорта при выкладке я могу использовать и registry, и git, и rsync, и ssh, и vagrant — я не ограничен, и это отдельная тема.
Если мы собрали все в один большой образ — у нас нет выбора, только молиться на registy.

Мне не нужна зависимость приложения от версии php. При каждом изменении в любой части стека надо пересобрать весь образ и заливать в registry? Мне это не подходит. Если я обновил версию php — приложение я не пересобираю. Если я обновил MySQL — php я не трогаю.

Да, это рвет шаблон, такого раньше не было. Эта статья для тех, кому нужен модульный дизайн системы. Если вы признаете один единственный правильный путь — эта статья не для вас.

Комментарии (43)


  1. Googolplex
    22.09.2015 17:06
    +6

    Мне кажется, что для работы с такими связками сервисов типа nginx+php-fpm или подобного имеет смысл использовать docker-compose. Пишется простенький yaml-файл, затем docker-compose up, и всё, сервисы запущены и соединены.


    1. Grikdotnet
      22.09.2015 19:20

      Я не хочу загромождать тему. Будет и про mysql, и про compose.


      1. symbix
        22.09.2015 19:47
        +5

        Не получится ли с такой мелкой нарезкой на серии повторение проблем документации на докер — попали на страницу из гугла, увидели простейший пример, скопипастили, а до docker-compose и data volumes так и не добрались никогда?


        1. Grikdotnet
          22.09.2015 22:53
          -1

          Что делать, habrahabr не позволяет структурировать материал. Здесь много чего не хватает.
          Читайте на gitbooks


          1. symbix
            23.09.2015 14:12
            +1

            Можно делать в каждом посте оглавление вручную — так, например, оформлена серия постов про vim-библиотеку юзера Delphinum.


            1. Grikdotnet
              23.09.2015 14:30
              -1

              понятно, спасибо! жаль, что это не описано в правилах хабра :)


  1. ivlis
    22.09.2015 18:42
    +4

    Вот если взялись объяснять технологию, то хотя бы best practices прочитайте. Не нужно ничего копировать в контейнер, нужно создавать Dockerfile. Не нужно монтировать директорию $(pwd), нужно создавать data volume container. И про docker-compose вам правильно написали.


    1. Grikdotnet
      22.09.2015 19:22
      -2

      «Не читал, но осуждаю» :) Прошлая статья серии — об этом.


      1. ivlis
        22.09.2015 20:00
        +1

        У вас ссылка «начало» ведет на другую статью, а на вот эту habrahabr.ru/post/267451 вообще невозможно попасть. К сожалению, у меня не так много времени, что отлеживать все ваши публикации. И если вы знаете, что так делать нельзя, то зачем пишите? Или вот там же пишите про композицию. И как вы её в докере будете делать, эту композицию?


        1. Grikdotnet
          22.09.2015 22:57
          -4

          Да, к сожалению, я не могу удобно структурировать материал, простите. У меня тоже не настолько много времени чтобы придумывать обход проблем формата хабра.
          Вариант решения — в ответе выше. Уточните, пожалуйста что нельзя делать и как?


  1. umputun
    22.09.2015 22:16
    +7

    Самый странный способ неправильного использования docker, что я видел. Я бы не называл это «рецептом Docker» но анти-рецептом. Вместо вменяемого создания Dockerfile автор всю кастомизацию стандартных контейнеров делает через volumes. То, что после этого контейнер будет прибит гвоздями к именно этому хосту видимо его не волнует. Причина этих странных телодвижений видимо должна быть понятна из habrahabr.ru/post/267451, но я не в состоянии ее понять. Единственное, что я смог там увидеть, это ошибочная уверенность автора в том, что при обычном, вменяемом использовании контейнеров и расширения иx функциональности для себя конвенциональными способами, надо «заплатить за хранение на Docker Hub».


    1. Grikdotnet
      22.09.2015 23:07
      -4

      Способ полностью противоречит документации. Нет никакой ложки.
      1. Официальные образы docker — аналог rpm/dev, собирать приложение в одном образе с runtime — аналогично сборке php, nginx, mysql и приложения в одном rpm. Сделать можно, но никто так не делает.
      PHP, Nginx, MySQL удобно ставить из официальных репозиториев, и подключать свои конфиги, чтобы этот официальный пакет без проблем обновить. Аналогично, я хочу ничего трогать в официальных образах.
      2. Когда мы собрали свой образ, мы можем сделать или save, или push. Если сделать save образу, созданному на базе nginx — дамп будет весить пару сотен мегабайт. Раздавать это в команде некомфортно. Если мы делаем push — мы выкладываем наш код всему миру, что для серьезных проектов недопустимо.
      Третьего способа передать наш образ на другой компьютер не существует. Ошибочность, к сожалению, не у меня.


      1. umputun
        22.09.2015 23:22
        +5

        А теперь как оно на самом деле:

        1. Официальные образы это всего лишь образы, никакой особой мистики в них нет. Они могут кому-то подойти «как-есть», кому-то послужить базовыми а кому-то как источник информации о том, как сделать нечто свое из них.
        2. Когда мы собрали свой образ то ему можно сделать push. Но его вовсе не обязательно делать в публичный или даже приватный docker hub. Поднимаем docker-registry и пушим туда, как все нормальные люди, которым надо приватный репозиторий для докера.
        3. Кроме того, когда сборка включает в себя все, что надо и Dockerfile является тем, чем он обычно является, ничего не мешает раздавать не образ, но именно этот самый Dockerfile с тем, что надо для его сборки. Это прекрасно сохраняется в любой системе контроля версий.


        1. Grikdotnet
          22.09.2015 23:49
          -3

          1. аналогично rpm и deb. Кто-то собирает свои пакеты, кто-то ставит официальные. Собирайте, поддерживайте свои, я не против.

          2. приватный репозиторий сделать можно, но надо заплатить :) О том и речь. У нас же не магазин на битриксе, а несколько микросервисов, и каждому нужен репозиторий. Мы же облачное масштабируемое приложение обсуждаем?

          3. Да, можно поднять registry. Можно настроить Vagrant. Можно работать образами виртуальных машин и забыть про docker.
          Я не проповедь читаю ;)


          1. umputun
            22.09.2015 23:55
            +5

            Я дал ссылку на docker-registry, за него не надо ничего платить. То, что вы показали это их сервис для корпораций. По моей ссылке есть простая и ясная инструкция, как поднять registry у себя. Ну вот еще одна, которая прямо так и называется «Deploying a registry server».

            И при чем тут «когда приложение в hub»? Что мешает сделать build без хаба из своих исходных Dockerfile?


            1. umputun
              23.09.2015 00:03
              +2

              хмм, это как минимум «неспортивно» редактировать свой ответ после того, как на него пришел комментарий. Я даже удивлен что хабр такое позволяет. И нет, «и каждому нужен репозиторий» это ерунда. Ну на самом деле, стоит почитать про docker registry а не придумывать себе что оно такое и станет понятно, что он нужен один, а не на приложение.


            1. Grikdotnet
              23.09.2015 00:05
              -5

              Я не состязаюсь, простите, но мне все равно прав я или нет. Если у вас есть вопрос — я могу пояснить. Могу забить :)
              Эта заметка не про registry, не про compose, не про swarm. Могу написать о registry отдельную заметку.


              1. umputun
                23.09.2015 00:06
                +3

                у меня нет вопросов и я знаю ответы. Единственная цель моих комментариев это оградить незрелые в докер умы, от вредных советов.


                1. Grikdotnet
                  23.09.2015 00:12
                  -5

                  лучше всего — напишите свою статью как правильно и запостите здесь ссылку на нее


                  1. novoxudonoser
                    23.09.2015 16:42
                    +1

                    лучше всего вы не пишите, а идите читайте доки, думайте мозгом, набивайте шишки на реальных задачах, пробуйте и иксперементируйте, и избавляйтесь от своего чсв (я слышал что выкидывание макбука в окно неплохо помогает). Потому как уже и сказал umputun для неопытного ваши статьи сделают только плохо, для тех кто разобрался неплохое развлечение их почитать но не более того.


            1. Grikdotnet
              23.09.2015 00:10
              -2

              Сделать build из своих исходных Dockerfile на другом компьютере мешает необходимость дополнительных телодвижений: или передавать отдельно свое приложение, или поднимать registry, или платить.


              1. Magot
                23.09.2015 00:28

                Каких таких телодвижений?


                1. Grikdotnet
                  23.09.2015 04:23
                  -2

                  Вы предложили настраивать и поддерживать внутренний registry. Это значит, что надо решать проблему SPOF этого registry, а именно: организовывать бекап его данных, мониторить, делать репликацию, чтобы не останавливать выкладки. Нужны все обычные телодвижения для дополнительного сервиса в полноценной инфраструктуре.


                  1. lazycommit
                    23.09.2015 09:08
                    +3

                    Достаточно навести порядок с версиями (читай — системами контроля версий) и даже если вы «потеряли» свой registry, то восстановить его не проблема.
                    Да и вообще, вся соль докера в том, что даже бэкап реестра билдов (ежели таков необходим) вам провернуть очень просто.
                    Можно вопрос, а вы программист?


                    1. Grikdotnet
                      23.09.2015 09:58
                      -3

                      Вы оперируете субъективными критериями: «не проблема», «очень просто». Конечно, запустить ракету в космос — тоже не проблема. Я описываю альтернативное решение без проблем вообще.


                  1. Fesor
                    23.09.2015 09:41
                    +1

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

                    Расходы на поддержание инфраструктуры для докера в принципе не особо велики, по сравнению с профитом который он дает.


                    1. Grikdotnet
                      23.09.2015 10:02
                      -2

                      Конечно, но определение «не велики» относительное. У моего друга из Ebay дневной лимит на добавление серверов 50 тысяч долларов, ему все проблемы в рунете — мышинная возня, он просто добавляет десяток серверов в любой момент. Все относительно.


                  1. Magot
                    23.09.2015 10:00

                    И все же. Что конкретно вам мешает?

                    Сделать build из своих исходных Dockerfile на другом компьютере мешает необходимость дополнительных телодвижений


                    1. Grikdotnet
                      23.09.2015 12:06

                      Необходимость передавать на другой компьютер отдельно Dockerfile и само приложение. Я предпочитаю передавать один маленький .tar.xz, и из него одной командой разворачивать работающую систему с базой, веб-сервером, runtime, библиотеками и конфигами.


              1. Glueon
                23.09.2015 14:43

                Почему, если так не хочется поднимать registry, не использовать docker save/load и при этом все-таки делать кастомизацию через Dockerfile (который можно версионировать)? Проблема в размере?


                1. Grikdotnet
                  23.09.2015 16:16
                  -1

                  Конечно. Работать с архивами полного стека своего приложения размером 2 мб без требований доступности стороннего репозитория намного удобнее, чем с архивами размером 70 мегабайт или обязательной хорошей быстрой связью с интернет. Я работаю с ноута в поездках.


  1. Fesor
    23.09.2015 09:43

    Я правильно понимаю что вы используете Docker исключительно для dev окружения, то есть вы не билдите контейнеры и не деплоите их на сервер… то есть… это такая вот странная замена Vagrant? Зачем вам докер тогда? С тем же успехом можно было бы взять vagrant + ansible и вышло бы удобнее в плане поддержки. Весь профит докера в управлении инфрастуктурой, версионизации, возможность уже проверенную на стэйджинге инфрастуктуру без изменений и быстро выкатить на прод например. А с таким подходом этот профит теряется. А что до разработчиков, те из них что сидят на маках будут слегка грустить, ибо что бы добиться производительности файловой системы нормальной приходится много поплясать с бубном для того что бы настроить хотя бы NFS.


    1. Grikdotnet
      23.09.2015 10:08

      Наоборот, мой подход позволяет на лету подменять любую часть стека приложения без нужны пересобирать образ с runtime, web-сервером и базой данных. В разработке преимущества большие, конечно — можно запустить 5 версий php и быстро между ними переключаться.


  1. felix0id
    23.09.2015 10:57
    +2

    Знаете, docker начал использовать совсем недавно, собрал на его основе среду для сборки деб-пакетов. Главное, но не единственное, конечно же, что понял из штудирования информации за десяток часов: «Use DOCKERFILE, Luke»

    Всё то, что Вы делаете (docker cp, docker foobar |, docker foobar >) как то вызывает вопрос: мы одну литературу читали?

    Судя по комментариям, не просто так у меня возникают такие вопросы. Рейтинга статей тоже символизирует. Про обещанную оркестрацию в гитбуке ничего не нашёл.


    1. Grikdotnet
      23.09.2015 12:01
      -3

      Господа, это оригинальное исследование с фатальным недостатком. Похоже, оно рвет шаблоны — вы привыкли делать иначе :)
      Мой алгоритм работает, и он удобен.
      Буду рад если вы опишите недостатки не новизны восприятия информации, а технические.


      1. Fesor
        23.09.2015 12:18
        +2

        оно рвет шаблоны

        Да нет, я так тоже делал, когда я только только разбирался с докером. Это особенно удобно когда докер используется частично.

        недостатки не новизны восприятия информации, а технические

        Даже с применением docker-compose сильно усложняется деплоймент. что бы было проще подменять на сервере контейнеры можно конечно замутить data-волумы для кода и конфигов, но это сильно усложнит docker-compose. С Dockerfile и регистри/дистрибьюшен что бы задеплоиться мне надо только сделать pull на сервере и подменить контейнеры на новые, благо docker-compose это уже умеет относительно удобно делать.

        Из недостатков… был у меня проектик с вендорной утилиткой для обработки видео, которая собиралась через раз. С вашим подходом докер мне никак не поможет, с Dockerfile я могу сборку запихнуть туда, и как только у меня контейнер собрался и работает, повесить на него стабильный тег и больше не беспокоиться о том что оно может отвалиться из-за другой версии библиотеки и т.д.


        1. Grikdotnet
          23.09.2015 14:00

          Эта дискуссия повторяет холивары десятилетней давности относительно официальных репозиториев пакетов, собственных репозиториев, сборки софта из исходников, и смешанных вариантов по типу gentoo :)
          Каждому свое.

          Ни в коем случае я не против распространения своих утилит вместе с библиотеками в образах. Я это делаю.
          Безусловно, registry — это удобно, и, возможно, я в будущем напишу об этом. Вряд ли опубликую здесь при подобной доброжелательности аудитории :)
          При желании можно обойтись и без него, и без composer. Единого православного способа не существует.


        1. Grikdotnet
          23.09.2015 14:15
          -1

          К слову, для деплоймента приложения, структуры СУБД и конфигов нужен только один образ в виде одного небольшого .tar.xz-файла. Все разворачивается из него и compose-конфига одной единственной командой.
          При этом, можно подменять модули на лету — php, python, nginx, перепрыгивать с mariadb на percona, развернуть локально репликацию, и откатиться при сбое. Удобно для stage и разработки.

          Да, админам это не нужно, это ломает привычный development-deployment cycle. Мне так удобно.


      1. felix0id
        27.09.2015 14:38
        -1

        банальное распространение изменений. Что мне делать на кластере из 20 машин с Вашими знаниями о том, как менять контейнеры?
        Именно в этом месте DOCKERFILE является логичным применением. А то, что предлагаете Вы — весьма, весьма оригинальным

        решением.
        image


        1. Grikdotnet
          27.09.2015 15:18
          -2

          Тема сисиек не раскрыта :) Поменьше аргументов, побольше картинок! И котиков, котики хороши на любую тему.


        1. Grikdotnet
          27.09.2015 15:42

          Если серьезно, ответ такой.
          Разложить сервисы на группу серверов так, чтобы с фронта автоматом резолвилась база, и при failover переключался мастер, как это умеет compose локально, не выйдет. Ip надо прописывать ручками — как минимум, в конфиге swarm. Серебрянная пуля отменяется, Dokcerfile и registry ничем не помогут. Когда мы выкладываем на кластер, нам в обоих случаях нужны дополнительные инструменты и ручная настройка.


  1. grossws
    25.09.2015 23:39
    +1

    habrahabr.ru/info/help/rules, правило 2:

    Хабрахабр — не ЖЖ и не центр мирового кросспостинга. Не нужно копировать публикации из других блогов и сайтов, указывая, что ранее они были опубликованы в другом месте.


    1. Grikdotnet
      27.09.2015 15:22

      надо было узнать чего не хватает перед публикацией на серьезных ресурсах, спасибо, теперь доработаю