Docker PHP 7 Tutorial (7, 7.1, and higher)
In the previous two videos we have laid the foundation required for running Docker, PHP, and Symfony all together.
We saw how we could quickly create a brand new MySQL database container allowing us to spin up a DB in a matter of seconds.
Then we saw how we could add in a nginx web server container, which would accept incoming requests and then forward them on to somewhere that really handled the PHP part of the job.
That somewhere is here.
However, yet again, things get a little more complicated than you might first expect.
We covered how it's a good idea to separate nginx from PHP. This way we could re-use the majority of the nginx configuration for other projects - WordPress, Node JS apps, Laravel, Rails, whatever. All we need to do is provide a different site configuration, and COPY
that into the resulting nginx image.
Well, it's somewhat similar for PHP.
We're going to first create a PHP 7.1 image, and then use that as the base for any PHP applications we might need. Again, this could be Symfony, or WordPress, or some standalone PHP app, or whatever.
It's extra work upfront, but it is easier this way on a day-to-day basis, I have found.
Creating a Custom Docker PHP 7.x Image
Our first task is to create a custom Docker PHP 7.1 image.
At the time of writing / recording, PHP 7.1 is the latest minor release, and PHP 7.1.9 is the latest patch release.
Check on the Docker Hub PHP page for the latest for you.
There are a bunch of versions such as:
7.1.9-cli
7.1.9-fpm
7.1.9-alpine
7.1.9
7.1-cli
7.1.9-zts
As you may have guessed based on all the PHP-FPM hi-jinx we went through in the previous video, the image we need is 7.1.9-fpm
.
This image comes with PHP-FPM pre-configured and ready to go. This is why we could add in php:9000
in our nginx configuration.
PHP 7.1 Dockerfile
The Dockerfile
for our PHP base image is large:
FROM php:7.1.9-fpm
# Install any custom system requirements here
RUN apt-get update \
&& apt-get install -y --no-install-recommends \
curl \
libicu-dev \
libmemcached-dev \
libz-dev \
libpq-dev \
libjpeg-dev \
libpng12-dev \
libfreetype6-dev \
libssl-dev \
libmcrypt-dev \
libxml2-dev \
libbz2-dev \
libjpeg62-turbo-dev \
php-pear \
curl \
git \
subversion \
&& rm -rf /var/lib/apt/lists/*
# Install various PHP extensions
RUN docker-php-ext-configure bcmath --enable-bcmath \
&& docker-php-ext-configure pcntl --enable-pcntl \
&& docker-php-ext-configure pdo_mysql --with-pdo-mysql \
&& docker-php-ext-configure pdo_pgsql --with-pgsql \
&& docker-php-ext-configure mbstring --enable-mbstring \
&& docker-php-ext-configure soap --enable-soap \
&& docker-php-ext-install \
bcmath \
intl \
mbstring \
mcrypt \
mysqli \
pcntl \
pdo_mysql \
pdo_pgsql \
soap \
sockets \
zip \
&& docker-php-ext-configure gd \
--enable-gd-native-ttf \
--with-jpeg-dir=/usr/lib \
--with-freetype-dir=/usr/include/freetype2 && \
docker-php-ext-install gd \
&& docker-php-ext-install opcache \
&& docker-php-ext-enable opcache
# AST
RUN git clone https://github.com/nikic/php-ast /usr/src/php/ext/ast/ && \
docker-php-ext-configure ast && \
docker-php-ext-install ast
# ICU - intl requirements for Symfony
# Debian is out of date, and Symfony expects the latest - so build from source, unless a better alternative exists(?)
RUN curl -sS -o /tmp/icu.tar.gz -L http://download.icu-project.org/files/icu4c/58.2/icu4c-58_2-src.tgz \
&& tar -zxf /tmp/icu.tar.gz -C /tmp \
&& cd /tmp/icu/source \
&& ./configure --prefix=/usr/local \
&& make \
&& make install
RUN docker-php-ext-configure intl --with-icu-dir=/usr/local \
&& docker-php-ext-install intl
# Install the php memcached extension
RUN curl -L -o /tmp/memcached.tar.gz "https://github.com/php-memcached-dev/php-memcached/archive/php7.tar.gz" \
&& mkdir -p memcached \
&& tar -C memcached -zxvf /tmp/memcached.tar.gz --strip 1 \
&& ( \
cd memcached \
&& phpize \
&& ./configure \
&& make -j$(nproc) \
&& make install \
) \
&& rm -r memcached \
&& rm /tmp/memcached.tar.gz \
&& docker-php-ext-enable memcached
# Copy opcache configration
COPY ./opcache.ini /usr/local/etc/php/conf.d/opcache.ini
# Install xDebug, if enabled
ARG INSTALL_XDEBUG=false
RUN if [ ${INSTALL_XDEBUG} = true ]; then \
# Install the xdebug extension
pecl install xdebug && \
docker-php-ext-enable xdebug \
;fi
# Copy xdebug configration for remote debugging
COPY ./xdebug.ini /usr/local/etc/php/conf.d/xdebug.ini
# Copy timezone configration
COPY ./timezone.ini /usr/local/etc/php/conf.d/timezone.ini
# Set timezone
RUN rm /etc/localtime
RUN ln -s /usr/share/zoneinfo/Europe/London /etc/localtime
RUN "date"
# Short open tags fix - another Symfony requirements
COPY ./custom-php.ini /usr/local/etc/php/conf.d/custom-php.ini
# Composer
ENV COMPOSER_HOME /var/www/.composer
RUN curl -sS https://getcomposer.org/installer | php -- \
--install-dir=/usr/bin \
--filename=composer
RUN chown -R www-data:www-data /var/www/
RUN mkdir -p $COMPOSER_HOME/cache
VOLUME $COMPOSER_HOME
As instructed here, there are other files COPY
'd in. Be sure to check out the GitHub repo for a full run down.
Building a Docker PHP, and Symfony Image
Now the above PHP 7.x Dockerfile
needs to be built before it can be used.
Ideally we want to store the resulting image file somewhere so that it can be accessed both by ourselves, and if needed by others, without having to complete a build (which takes ages in this case) every time we need to use it. And we will use it a lot, because this is our PHP base image.
For the purposes of this video I will push
my image up to Docker Hub.
In reality, I store all my own images in a Private Docker Registry. We will get on to this a little later on, but for now a publicly accessible registry such as Docker Hub is fine for our needs.
If you haven't already done so, please create an account at Docker Hub before continuing. If you would prefer, you can skip this step as you can make use of my image as needed.
Next, create a new repository.
I'm calling mine "php-7".
You can see my repository here.
Next we need to docker build
this Dockerfile
into a docker image, and then docker push
this image up to Docker Hub.
First, let's build the image:
docker build -t codereviewvideos/php-7 .
This will build the image based on the Dockerfile
contents, and -t
(tag) the image as codereviewvideos/php-7:latest
.
You can specify a better tag name, if needed. For base images I rarely do.
The resulting output from this command is incredibly verbose, so I have omitted it for the sake of brevity. Also this command takes a while to run - so feel free to go grab a coffee. Thankfully you don't need to do this very often - only if make a change, for example such as bumping to the latest PHP minor or patch release.
After a short - or long - period, you should hopefully have something akin to this:
...
Step 20/21 : RUN mkdir -p $COMPOSER_HOME/cache
---> Running in 8d9573855707
---> 57132b991359
Removing intermediate container 8d9573855707
Step 21/21 : VOLUME $COMPOSER_HOME
---> Running in aa50c819bc8b
---> 5589317017f8
Removing intermediate container aa50c819bc8b
Successfully built 5589317017f8
Successfully tagged codereviewvideos/php-7:latest
This image now resides only, in this case, on my machine.
This image is also quite large:
docker image inspect 5589317017f8 | grep Size
"Size": 993292369,
993292369
is in bytes = ~993mb.
To share this with my others I need to push
this image up from my machine out onto a repository. In this case I will use Dockerhub which is a public registry. In most cases I would use my own GitLab server, making use of its private Registry instead.
docker push codereviewvideos/php-7
The push refers to a repository [docker.io/codereviewvideos/php-7]
58858b9ac822: Pushed
ff494e26803e: Pushed
21954226c0a2: Pushed
86775dacda53: Pushed
01505d689972: Pushed
6631144d58cd: Pushed
4e4c5c63576f: Pushed
e29936a0ea85: Pushed
1eabc97271f1: Pushed
25ef4dbaf88d: Pushed
02a669b9f23b: Pushed
13542cf90a94: Pushed
eb3f743b1b32: Pushed
6c88c973ebdc: Pushed
d5c29d26b17f: Pushed
d2cae5519c63: Mounted from library/php
d8ff7331f387: Mounted from library/php
00170637a65c: Mounted from library/php
0ee3463bd959: Mounted from library/php
a4dff7f421b9: Mounted from library/php
a6cdd2fcc357: Mounted from library/php
57277ee24969: Mounted from library/php
69bff829a46c: Mounted from library/php
18f9b4e2e1bc: Mounted from library/php
latest: digest: sha256:89294691302aeb8c2e91d1502e3dd458a7550366f66969686655a01129e19bfb size: 5340
Depending on your upload speed this part may take some time.
The good news is we now have the base image for all our PHP tasks.
In the next video we will use this image as the basis for a brand new Symfony 3 project.