Docker, PHP, Apache, the wrong way

So yah, we’ve been “busy”. Part of it being in ways with docker now, yay?

Если не шутя, то докер штука приятная, а с некоторых пор еще и с поддержкой вин10, что может пойти не так?

Задача на сегодня – пожамкать докер и создать контейнер (о них позже) для классики в виде PHP, Apache и WordPress. Зачем? Потому что переезжать всегда весело, а иметь чемодан с отделениями приятнее.

О Docker, container, и image

С простым просто, докер это система контейнеризации. Все ¯\_(ツ)_/¯.

Контейнеризация же это процесс разделения блоков сервисов в независимые друг от друга элементы связанные интерфейсом третьего лица. Напоминает decoupling, не правда ли? Вот что получается когда пускаешь программистов к сисадминам

Зачем нужны эти напряги? В детском случае незачем, в случае адекватном как обычно – чем слабее связаны блоки в наборе, тем легче их пристроить куда-нибудь, и тем легче делать копии. Плюс в горизонтальном масштабировании без него сейчас никуда.

И о обещанных контейнерах и картинках: все достаточно просто, картинки – image – и правильнее образы – это небольшие “виртуальные машины” в которых содержатся все файлы, библиотеки, и настройки необходимы для работы сервиса, будь то БД, прокся на nginx, или отдельное node-приложение.

Помимо образов сервисов, которые как правило писать придется тебе, есть “базовые” образы. Отличия незначительные – базовые образы предоставлены другими людьми как правило официально распространяющими библиотеку, сервис или что-либо. Базовые образы точно так же держат в себе некоторые файлы, библиотеки и настройки, и либо используются для создания кастомного образа под нужды, либо в случае какого-нибудь redis-а запускаются самостоятельно как сервисы.

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

Куда совать и что делать

После оперативной (и страдательной, если у тебя не дай Ишвар нет Hyper-V или еще чего) установки Докера можно приступать:

FROM php:apache

WORKDIR /var/www/html
COPY index.html ./

CMD ["apache2ctl", "-D", "FOREGROUND"]

Это содержимое так называемого Docker-файла, в нем описан процесс создания образа через набор простеньких команд. Почему “Docker-файл”? Потому что “расширение” у этого файла Dockerfile, но как правило файл не имеет названия (расширения) и получается просто Dockerfile без лишних названия и точки.

  • FROM указывает какой базовый образ использовать. Выбрать можно из огромного перечня, ознакомится с которым можно в докер-хабе. Синтакс php:apache указывает что я хочу дернуть официальный образ php тегированный apache. Теги это метки которые указывают версию и другие мета-данные образа, в варианте php тег определяет flavour of php, прям как линукс;

  • WORKDIR как трудно догадаться, указывает в какой папке создаваемого образа производить махинации;

  • COPY (либо устаревший ADD) как опять же трудно догадаться копирует файл(ы) с хоста (твоего ПК/машины где создается образ) на создаваемый образ относительно рабочей папки (либо абсолютного пути, если ты извращенец). Рабочая папка может быть указана предварительно, как сделал я, либо (я думаю) быть указана создателем базового образа;

  • CMD указывает какую команду исполнит докер при старте контейнера созданного из этого образа. Тут нужно быть чутка внимательным – жизнь контейнера зависит от жизни созданного командой процесса. Если процесс одноразовый – сделал Х и (не)успешно завершился, докер стопанет контейнер. Что в большинстве случаев нежеланный исход. Помимо прочего любой вывод процесса отправится в лог контейнера.

Как ни страшно, но это только пол дела – мы написали как Докеру создать образ, но чтобы почувствовать мощь, нам нужно 1. создать, 2. запустить контейнер из получившегося образа. Для этого берем в руки терминал или консоль и пишем (из папки с созданным Dockerfile-ом):

docker image build . -t test:whatever
docker container create --name abc -p 80:80 test:whatever
docker container start abc

При успешном выполнении докер скачает необходимые для нашего докерфайла образы: php, apache, что-либо что решили использовать их авторы, после чего создаст новый кастомный локальный образ именованный test с меткой “версии” whatever. Далее из этого образа создастся контейнер именованный (--name) abc и с привязкой порта хоста:к порту контейнера. В конце мы запустим созданный контейнер.

Если все прошло успешно, зайдя на localhost ты увидишь содержимое index.html заранее расположенного рядом с докерфайлом, либо 404 ошибку апача.

Ура. Успех. Уэффективность.

Опять же – а в чем прикол?

“Не проще ли скачать апач, положить этот файлик, и забыть про все эти контейнеры, образы, буэ!”

Да, но нет. Какая фишка – владея созданным выше образом, мы можем создать N апач серверов с идентичной конфигурацией, замороженной в момент создания образа. Каждый раз скачивая установщик апача, пхп, и т.д. и т.п. со временем будет возрастать энтропия, туннельный синдром и ненависть к ctrl+c и ctrl+v.

Создав один раз шаблончик образа, можно использовать его сколь угодно, меняя (если необходимо) некоторые параметры. Помнишь -p 80:80 параметр при создании контейнера? Если использовать -p 81:80 у тебя будет вторая абсолютная копия сервера.

“Но на ней будет тот же самый index.html, нафига мне десять копий его?”

Технически почему бы и нет, в случае тяжелых обработок, т.д. т.п. Но я понимаю – городить огород ради огорода не очень весело.

Поэтому можно сделать чуть лучше:

docker container stop abc && docker container rm abc
docker container create --name abc -p 80:80 -v ./data:/var/www/html test:whatever
docker container start abc

In case you’re a pervert Windows(tm, copy, whatev) user:

Докер и винда ругнутся в унисон: доступ не расшарен, папки нет, путь не существует. Расширить(разрешить) доступ можно в настройках Docker Desktop либо в applicable thingy. Папку нужно создать предварительно. Путь необходимо использовать абсолютный.

Да, все очень грустно.

-v (--volume) это специальный флажок который указывает докеру при создании контейнера закрепить (или в реалиях linux сделать mnt) его “жесткий диск” в некое пространство на хосте. Пространство может быть разных типов, но как правило для начала используют два:

  • Physical mount, который я только что проделал – он цепляет папку внутри контейнера на папку на хосте. С таким креплением можно подкидывать файлы для обработки, сохранять состоянии контейнера между пересозданиями и прочие прелести обеспеченные доступом в “реальную” хостовую файловую систему. Применяются ограничения т.д. т.п.
  • Docker mount, это почти тоже самое, только папкой управляет докер и что-то положить напрямую туда довольно проблематично и ненадежно. Но это лучший вариант для создания persistence между пересозданиями\перезапусками контейнера. Как правило go-to вариант для хранилищ БД и подобного.

Второй тип крепления создается в один либо два шага, отличающий их подтип:

Для создания анонимного крепления, которое управляется полностью докером:

docker container create --name abc -p 80:80 -v /full/container/path/to/mount test:whatever

И именованного, которым нужно управлять:

docker volume create the-volume-name
docker container create --name abc -p 80:80 -v the-volume-name:/full/container/path/to/mount test:whatever

Я бы сказал париться со вторым особо незачем, есть куда более удобные способы креплять хранилище предназначенное для persistence-а.

Таким образом прелести докера становятся более понятны:

Допустим у нас классическое веб-приложение на PHP (боль ну да ладно) – из исходников мы создаем образ (при этом его можно создать и из специальной оптимизированной prod версии). Для разработки мы создаем контейнер – одну из копий этого образа – и крепляем в него папку исходников, которые можем редактировать. А для размещения мы создаем точно такой же контейнер но без крепления.

Что дает нам избавление от возни с фтп, версиями, частичными перезаписями, и потенциально недобросовестным редактирование вживую на проде – любые изменения там будут перезаписаны и это известно всем.

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


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

See ya, and have fun.

nil commento load