В публикации опишу подход к использованию контейнеров docker и make который я практиковал последние несколько лет в своих рабочих командах и личных pet-проектах. Подход сформировался в процессе поиска минималистичного и унифицированного способа запуска проектов на php. Чтобы любой разработчик мог в пару простейших команд получить рабочую копию для разработки, располагая только доступом к репозиторию, без бубнов, обновляемых инструкций и тимлида на соседнем стуле.
Требования:
docker
make
debian-based distro
Файл .env
Файл .env
широко используется многими инструментами для определения переменных окружения. Преимущества файла и формата — его легко читать и модифицировать, в том числе программно, добавляя строки, переопределяя тем самым нужные переменные, например в рамках CI.
Чтобы сохранить свободу изменений локального окружения и гибкость версионирования, в репозитории хранится dev.env
с минимальным набором переменных для запуска проекта на машине разработчика, сам .env
добавлен в .gitignore
. При необходимости, помимо dev.env
можно добавить аналогичные шаблоны для других окружений: ci.env
, test.env
, stage.env
, etc. В рабочем флоу разработчика dev.env
копируется в .env
.
Makefile
Утилита make широко распространена, включена во множество дистрибутивов. Её легко использовать как основную точку входа в проект. В описанном подходе, после клонирования репозитория предполагается выполнение одной инструкции: make install
, после чего можно запускать тесты. Т.о. проект готов к разработке в два простых шага: git clone...
+ make install
.
Чтобы это было возможно, используется пара простых трюков в Makefile. Внимание на первые его строки:
PATH := $(shell pwd)/bin:$(PATH)
$(shell cp -n dev.env .env)
include .env
Первой строкой в путь для поиска исполняемых команд добавляет директория /bin
проекта. О ней отдельно будет ниже.
Вторая строка — упомянутое копирование файла .env
для окружения разработки.
Третья - включение файла, для использования переменных окружения в инструкциях make.
Сам рецепт install
содержит минимум необходимый для получения рабочего проекта локально:
install: build
composer install
cp -n phpunit.xml.dist phpunit.xml
build:
docker build -t $(PHP_DEV_IMAGE):$(REVISION) .
Директория /bin и контейнеризированные команды
Здесь располагаются скрипты, которые позваляют запускать необходимые разработке команды в контейнерах. В нашем случае это php и composer.
Листинг с пояснениями
/bin/php
#!/bin/bash
source .env # считываем переменные из файла, для их использования в сценарии
test -t 1 && USE_TTY="--tty" # проверяем наличие tty (для корректного запуска на CI-сервере)
docker run --rm --interactive ${USE_TTY} \ # запускаем одноразовый контейнер, который будет удалён после выполенения команды, с возможностью интерактивного ввода при необходимости
--init \
--user `id -u`:`id -g` \ # передаём текущего пользователя и его группу, для выставления корректных прав при работе с ФС
--volume $PWD:/var/www \ # прокидываем директорию проекта в том контейнера, являющейся рабочей директорией
--env-file .env \ # делаем доступными переменные окружения проекта внутри контейнера
${PHP_DEV_IMAGE}:${REVISION} php "$@" # используем образ и тэг заданные в переменных окружения, где собственно и вызываем интерпретатор с переданными аргументами
/bin/composer
Примерно тоже что и php, со спецификой необходимой composer.
#!/bin/bash
source .env
mkdir -p $HOME/.composer/cache/ # подготовка ФС для кэша composer, при необходимости
test -t 1 && USE_TTY="--tty"
docker run --rm --interactive ${USE_TTY} \
--init \
--user `id -u`:`id -g` \
--volume $PWD:/var/www \
--volume $HOME/.composer:/tmp/.composer \ # монтирование директории для кэширования
--env COMPOSER_HOME=/tmp/.composer \ # указание директории для использования composer
${PHP_DEV_IMAGE}:${REVISION} composer "$@"
Таким образом, находясь в корне репозитория, мы можем работать с нужной версией php и composer, обращаясь к ним как ./bin/php ...
, ./bin/composer ...
, либо напрямую, предварительно добавив в PATH, например на уровне сессии терминала. В Makefile это добавление релизовано, и мы можем легко добавлять необходимые рецепты, как будто это прямой вызов локального интерпретатора.
Всё описанное в статье собрано вместе в шаблоне-репозитории https://github.com/samizdam/php-project-skeleton. Этот минимум можно использовать для библиотек или простейших сервисов на php.
Что дальше
Описанные приёмы хорошо переиспользуются и дают базу для реализации запуска составных проектов из нескольких контенеров: docker-compose сам умеет работать с .env
. В сценариях для CI аналогично с Makefile, можно приготовить и импортировать .env
и расширить PATH. Также контейнеризация приложения на раннем этапе — полезный задел для построения дальнейших процессов CI/CD.
Ограничения - описанный стек и debian-like дистрибутивы, где все описанные инструкции будут работать. На универсальность не претендую. Для кроссплатформенного запуска — нужен напильник, либо описанный способ, как есть, может не работать ¯_(ツ)_/¯