The past week I took a closer look at the several options on how to run a PHP app with Docker. In the past I’ve ran a few pre-built containers, but now I wanted to truly get to the bottom of it all as I don’t always need a full blown container with all extensions, but want to start from a rather clean base and build upon that. This post mainly functions as a note to my future self and lists projects that I found interesting during my research.
ℹ️ I was only looking to run a PHP app, without any other services (MySQL, Redis, etc) so these are not covered here. If you’re using docker-compose
it’s “only” a matter of also adding those and exposing them over the (internal) network.
~
mikechernev/dockerised-php
This one uses docker-compose
which starts up a php:fpm
container and an nginx
container with a network between them. Nginx is configured to pass requests for PHP files to php-fpm
. This is how many articles tackle this.
~
TrafeX/docker-php-nginx
This one also uses php-fpm
and Nginx but installs them from scratch and stores them in one single container (e.g. no docker-compose
). Processes are controlled using supervisord
~
php:7.4-apache
Official PHP Image with Apache2 and PHP. Comes with handy utils such as docker-php-ext-configure
, docker-php-ext-install
, and docker-php-ext-enable
. This gist is a good reference to installing many extensions
FROM php:7.4-apache
RUN apt-get update && apt-get install -y \
libfreetype6-dev \
libjpeg62-turbo-dev \
libpng-dev \
&& docker-php-ext-configure gd --with-freetype --with-jpeg \
&& docker-php-ext-install -j$(nproc) gd
RUN apt-get update && apt-get install -y \
zlib1g-dev \
libicu-dev \
g++ \
&& docker-php-ext-configure intl \
&& docker-php-ext-install intl
# …
RUN a2enmod rewrite
Apache Modules are enabled using the common a2enmod
. Log and error files are symlinked to /dev/stdout
and /dev/stderr
~
alfg/docker-php-apache
Starts with an alpine
image and installs Apache and PHP into them without too much cruft. Also symlinks the log and error files on startup (not from the Dockerfile
).
Also installs Composer quite cleverly by leveraging its command line options.
RUN curl -sS https://getcomposer.org/installer | php -- \
--install-dir=/usr/local/bin --filename=composer
~
composer:1.9
This is the official Composer Image which contains PHP and Composer. Instead of installing composer.phar
in your own container, you use this separate container to run composer install
in, and then copy its output (e.g. the vendor
folder) into the “main” container.
This is what Docker calls multi-stage builds:
With multi-stage builds, you use multiple
FROM
statements in yourDockerfile
. EachFROM
instruction can use a different base, and each of them begins a new stage of the build. You can selectively copy artefacts from one stage to another, leaving behind everything you don’t want in the final image.
It goes like this:
# COMPOSER
FROM composer:1.9.1 as composer
COPY composer.json composer.lock /app/
RUN composer install \
--ignore-platform-reqs \
--no-interaction \
--no-plugins \
--no-scripts \
--prefer-dist \
--optimize-autoloader \
-vvv
# WEBSERVER
FROM php:7.4-apache
# …
COPY --chown=www-data:www-data --from=composer /app/vendor/ /var/www/vendor/
# …
This way you don’t pollute your “main” container with Composer itself, as that is not needed to run your application.
~
Thank me with a coffee.
I don\'t do this for profit but a small one-time donation would surely put a smile on my face. Thanks!
To stay in the loop you can follow @bramus or follow @bramusblog on Twitter.
Leave a comment