Евгений Горяев
aka floor12

Мой идеальный docker-образ на базе php-fpm

Обложка для статьи Мой идеальный 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