![](https://habrastorage.org/getpro/habr/upload_files/fd7/36a/383/fd736a383573b6346781ae1cd97a0331.png)
В настоящее время все работает лучше при использовании Docker для настройки локальных сред, а не при локальной установке PHP и других зависимостей. Когда начинаются новые PHP-проекты, Dockerfiles (Docker-файлы) копируются из одной кодовой базы в другую, поскольку для запуска каждого проекта требуются схожие базовые зависимости. Это существенно затрудняет поддержку изменений в контейнерах.
Чтобы избежать этого, в TeleSoftas возникла идея иметь простой базовый образ, который упростил бы разработку и сопровождение наших проектов. Этот образ опубликован на DockerHub, что облегчает запуск нового проекта за счет сокращения объема необходимого кода.
Решение
Давайте рассмотрим базовый образ PHP Dockerfile, необходимый для запуска приложения Symfony:
FROM php:8.1-fpm-alpine
RUN addgroup -g 1000 -S app && \
adduser -u 1000 -S app -G app
RUN apk add \
autoconf \
build-base \
git
RUN docker-php-ext-install pdo_mysql
RUN pecl install apcu-5.1.21
RUN docker-php-ext-enable apcu opcache
COPY --from=composer:2.1 /usr/bin/composer /usr/local/bin/composer
Мало того, эта простая конфигурация работает и для обычных PHP-проектов, и для Laravel. Копировать один и тот же Dockerfile и поддерживать его во всех проектах становится немного сложно и запутанно, так почему бы не сделать это проще?
Публикация образа на Dockerhub
Чтобы не создавать новый Dockerfile для каждого проекта, вы можете опубликовать его на DockerHub и потом получить через docker-compose.yml прямо оттуда. А создание образа не сложнее нескольких команд — войдите в свой аккаунт на DockerHub, соберите образ и отправьте его.
docker login -u <YOUR_DOCKERHUB_USERNAME> -p <YOUR_DOCKERHUB_TOKEN> docker.io
docker build -t index.docker.io/<YOUR_DOCKERHUB_USERNAME>/php:8.1 .
docker push index.docker.io/<YOUR_DOCKERHUB_USERNAME>/php:8.1
Использование только что созданного образа
Сначала создайте файл docker-compose.yml со следующей конфигурацией службы:
version: '3.7'
services:
php:
image: <YOUR_DOCKERHUB_USERNAME>/php:8.1
user: app
volumes:
- ./app:/srv/app
Теперь вы можете просто игнорировать сборку образа локально, он будет извлекаться из DockerHub. Таким образом, вы избежите дублирования Dockerfile в разных проектах и упростите его поддержку.
Это полезно при создании нового проекта Symfony/Laravel с нуля или, например, при локальном выполнении PHP-кода, поскольку Docker в настоящее время более популярен, чем наличие всех библиотек на вашей хост-машине.
Расширение Dockerfile для каждого проекта
Иногда вам нужны некоторые зависимости в одном проекте и не нужны в другом. Это также легко сделать, используя новый опубликованный образ. Например, в некоторых проектах при локальной разработке вам может понадобиться XDebug или другие дополнительные библиотеки. Для решения этого можно создать небольшой Dockerfile, который будет извлекать базовый образ и добавлять поверх него необходимые библиотеки.
FROM <YOUR_DOCKERHUB_USERNAME>/php:8.1
RUN pecl install xdebug-3.1.1
RUN docker-php-ext-enable xdebug
Далее разверните свою конфигурацию docker-compose.yml:
version: '3.7'
services:
php:
build: .
user: app
volumes:
- ./app:/srv/app
И все предельно просто. Нет дублирования кода, а основные зависимости легко поддерживать во всех проектах. Вы можете добавить столько пользовательских настроек в этот локальный Dockerfile, сколько вам нужно.
Автоматизация публикации в Dockerhub
Допустим, вам нужно обновить Composer (пакетный менеджер для PHP) до более новой версии в вашем базовом образе. Для этого нужно обновить наш Dockerfile, зайти на DockerHub, собрать образ и опубликовать его. Вы можете упростить эту задачу, автоматизировав этапы сборки и публикации вашего пайплайна.
Для этого руководства я выбрал GitLab в качестве репозитория исходного кода и создал файл .gitlab-ci.yml со следующей конфигурацией для автоматизации всего процесса
stages:
- build
variables:
IMAGE_VERSION: '8.1'
build:
stage: build
image: docker:latest
before_script:
- docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" "$CI_REGISTRY"
script:
- docker build --pull -t $CI_REGISTRY_IMAGE:$IMAGE_VERSION .
- docker push $CI_REGISTRY_IMAGE:$IMAGE_VERS
Остался только один шаг — определить переменные в настройках CI/CD проекта:
CI_REGISTRY=docker.io
CI_REGISTRY_IMAGE=index.docker.io/<YOUR_DOCKERHUB_USERNAME>/php
CI_REGISTRY_USER=<YOUR_DOCKERHUB_USERNAME>
CI_REGISTRY_PASSWORD=<YOUR_DOCKERHUB_TOKEN>
Когда вы отправляете обновленный образ на GitLab, он будет собран и помещен в DockerHub после завершения пайплайна. Эту конфигурацию можно легко адаптировать к Bitbucket или Github, руководствуясь их инструкциями по настройке пайплайна.
Резюме
Осталось только выполнить один большой шаг — решить, что требуется в вашем базовом образе, собрать его и опубликовать на DockerHub. И вот что мы сделаем:
Создайте два репозитория для Docker-образов PHP 8.0 и 8.1.
Создайте Dockerfile и добавьте конфигурацию CI, чтобы автоматизировать весь процесс.
Тегируйте образ и отправьте его в реестр образов в DockerHub после завершения пайплайна. И все. Вот так вы можете значительно упростить свою разработку.
Это принесет пользу не только существующим, но и новым проектам. Облегчается поддержка всех приложений - если для работы последней версии Symfony требуется новая библиотека или пакет, достаточно один раз обновить базовый образ и он уже будет доступен во всех проектах.
Идем дальше
В дополнение к ранее упомянутым улучшениям можно еще больше упростить конфигурацию всего стека разработки. Этот пример относится к PHP, но тот же процесс можно адаптировать и к другим контейнерам, таким как Nginx. Например, в большинстве проектов возникает потребность в сокращении логирования. Для этого можно создать новый базовый образ Nginx с выключением лога и использовать его повторно.
Работая с PHP продолжительное время, мы рано или поздно сталкиваемся с задачами, которые выходят за рамки обработки HTTP-запросов здесь и сейчас, а требуют более комплексных решений. Это могут быть обработки большого объема данных, прослушивание событий и так далее. Конечно, можно взять и внедрить ещё один язык в стек, но это подходит далеко не всем. Приглашаем на открытое занятие, на котором разберемся с тем, как PHP может решать задачи подобного рода. Регистрация — по ссылке.