Мой идеальный docker-образ на базе php-fpm
Для всех, кто использует докер в своих веб-проектах на php, встает вопрос сборки контейнера для своего проекта. Кто-то использует контейнеры на базе Apache с php в виде модуля, но я, как и большинство разработчиков, предпочитаю строить свой контейнер для приложения на базе php-fpm.
Основная проблема в том, что оригинальный php-fpm не содержит множества php-модулей для полноценной работы, а также вспомогательного софта, который регулярно требуется.
Ситуация усугубляется, если необходимо поддерживать несколько проектов на одном стеке. Это - как раз мой случай, так как у меня на поддержке и доработках находятся обычно более 10ка проектов на фреймворке Yii2. Все они используют приблизительно один стек: Yii2 framework, php-fpm, nginx, memcached и базу в виде mysql или postgres.
Итак, базовый контейнер с php-fpm необходимо дополнить следующими php-библиотеками:
- GD - обязательно собранный с поддержкой WEBP;
- IMAP - для отправки почты;
- Zip - как минимум, для работы с бэкапами;
- Intl - необходимый модуль для интернационализации;
- Pdo_mysql - для работы с Mysql;
- Pdo_pgsql - для работы с Postgresql;
- Memcached - для организации кэширования;
- Xdebug - его я по умолчанию отключаю и активирую только при разработке.
Помимо этих библиотек, я ставлю дополнительный софт:
- git
- composer
- zip
- ffmpeg
- mysql-client
- postgresql-client
В этом списке git оказался потому, что он необходим для работы composer. Zip я устанавливаю, так как работаю с модулем Yii2 для бекапов, который использует zip для сжатия. FFmpeg я устанавливаю для того, чтобы модуль работы с файлами для Yii2, который я использую, мог конвертировать видео-файлы. Ну а консольные клиенты для mysql и postgresql я ставлю для универсальности, так как мои приложения работают с обеими базами данных, а в некоторых случаях - с двумя одновременно.
В итоге, у меня получается универсальный и достаточно гибкий php-контейнер, в котором есть все необходимое для разработки, запуска в продакшене проекта или создания финального образа на его основе.
Для удобства поддержки двух веток php, которые мне необходимы, я храню их в разных ветках репозитория. Собираю через gitlab CI и храню в открытом доступе там же, в registry гитлаба.
После этапа разработки, когда необходимо собрать проект в отдельный образ для запуска в продакшене, я обычно создаю его на базе образов, указанных выше. Копирую в контейнер:
- необходимые для работы файлы проекта;
- конфиг php.ini, в котором стоят оптимальные параметры для работы проекта (как минимум увеличение
upload_max_filesize
иpost_max_size
, установка временной зоны); - конфиг для nginx, который в будущем будет расшариваться с запущенным рядом контейнером;
- конфиг для базы данных, если ей необходимы какие-то дополнительные настройки.
Потом запускаю установку зависимостей через composer install --no-scripts --prefer-dist --optimize-autoloader
. Но при этом, в финальной сборке у меня находятся и пакеты из dev-зависимостями (codeception, debug и другими компонентами, необходимыми для тестирования). Так как при сборки приложений в CI я тестирую уже контейнер, который непосредственно отправится в продакшн, в нем необходимо иметь dev зависимости. Хотя после тестов их можно и удалять из контейнера. Об этом я расскажу в других статьях.
Если хочется немного уменьшить размер финального образа, то можно не собирать его на базе образов, которым посвящена эта статья а переработать их исходный dockerfile под себя, удалив оттуда лишний софт. Кроме того, можно удалить весь ненужный софт из контейнера и после сборки приложения. Однако, я к такому подходу не прибегаю, так как лично мне удобнее, чтобы образы не отличались друг от друга и для удобства поддержки проектов - иногда требуется подключиться к контейнеру и уже иметь в нем все необходимые инструменты для дебага и просто полезные утилиты.
На момент написания статьи, образ собирается по представленному ниже dockerfile. Однако, его актуальную версию можно найти в репозитории на гитлабе.
FROM php:7.4-fpm
RUN apt-get update
RUN apt-get install -y \
git \
libzip-dev \
libc-client-dev \
libkrb5-dev \
libpng-dev \
libjpeg-dev \
libwebp-dev \
libfreetype6-dev \
libkrb5-dev \
libicu-dev \
zlib1g-dev \
zip \
ffmpeg \
libmemcached11 \
libmemcachedutil2 \
build-essential \
libmemcached-dev \
gnupg2 \
libpq-dev \
libpq5 \
libz-dev
RUN echo 'deb http://apt.postgresql.org/pub/repos/apt/ jessie-pgdg main 9.5' > /etc/apt/sources.list.d/pgdg.list
RUN apt-key adv --keyserver ha.pool.sks-keyservers.net --recv-keys B97B0AFCAA1A47F044F244A07FCC7D46ACCC4CF8
RUN apt-get update && apt-get install -y postgresql-client-9.5
RUN docker-php-ext-configure gd \
--with-webp=/usr/include/ \
--with-freetype=/usr/include/ \
--with-jpeg=/usr/include/
RUN docker-php-ext-install gd
RUN docker-php-ext-configure imap \
--with-kerberos \
--with-imap-ssl
RUN docker-php-ext-install imap
RUN docker-php-ext-configure zip
RUN docker-php-ext-install zip
RUN docker-php-ext-configure intl
RUN docker-php-ext-install intl
RUN docker-php-ext-install pdo_mysql
RUN docker-php-ext-install pdo_pgsql
RUN docker-php-ext-install exif
RUN docker-php-ext-install fileinfo
RUN pecl install xdebug
RUN curl --silent --show-error https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
RUN pecl install memcached
RUN echo extension=memcached.so >> /usr/local/etc/php/conf.d/memcached.ini
ENV COMPOSER_ALLOW_SUPERUSER 1
WORKDIR /app