Starting with PHP 7.4, PEAR is disabled by default, which means PECL is no longer available to install extensions. There's a number of reason to that decision, so we'll have to make do. It took me a few hours to update my Dockerfile and replace PECL calls with manual installations, that MongoDB one was quite tricky. I wrote this article because I wanted to play with PHP 7.4 but hit a wall with installing extensions. I hope it will be of some help.
EDIT: I think I found a simpler solution using PECL packages.
Initial Dockerfile, with PECL
This is the Dockerfile of the base image of one of my services. It will be our starting point. We
have a bunch of extensions in there. Some are bundled with PHP like sockets
or opcache
. Some
need to be installed manually like apcu
, redis
, or mongodb
.
FROM php:7.3.2-fpm-stretch
RUN apt-get update && \
pecl channel-update pecl.php.net && \
pecl install apcu igbinary mongodb && \
# compile Redis with igbinary support
pecl bundle redis && cd redis && phpize && ./configure --enable-redis-igbinary && make && make install && \
docker-php-ext-install bcmath sockets && \
docker-php-ext-enable apcu igbinary mongodb opcache redis && \
docker-php-source delete && \
rm -r /tmp/* /var/cache/* /var/www/html/*
RUN echo '\
opcache.interned_strings_buffer=16\n\
opcache.load_comments=Off\n\
opcache.max_accelerated_files=16000\n\
opcache.save_comments=Off\n\
' >> /usr/local/etc/php/conf.d/docker-php-ext-opcache.ini
Scripts available in the docker image
Before we get started let's have a quick overview of the scripts available in the Docker image.
First we have docker-php-source
, that extracts PHP source required to build the extensions, and
also deletes it. Next up we have docker-php-ext-configure
, that configures an extension before it
gets installed. And finally we have docker-php-ext-install
, that installs extension(s). Basically,
almost everything we do with extensions needs to happen between docker-php-source extract
and
docker-php-source delete
.
The scripts are described in the How to install more PHP extensions section of the official image README.
Installing extensions
Installing extensions manually follow the same pattern, mostly:
- Create the corresponding directory in
/usr/src/php/ext
. - Extract the source in that directory. The source is usually available on GitHub.
- Invoke
docker-php-ext-install
to install the extension.
Some extensions require a bit more work than others, but this is the gist of it. Let's begging with
a simple installation such as ext-apcu
.
Installing ext-apcu
We'll get ext-apcu
source from GitHub. We'll use ENV
to define the version we want so it's easy
to spot and tweak.
FROM php:7.3.2-fpm-stretch
ENV EXT_APCU_VERSION=5.1.17
RUN docker-php-source extract \
# ext-apcu
&& mkdir -p /usr/src/php/ext/apcu \
&& curl -fsSL https://github.com/krakjoe/apcu/archive/v$EXT_APCU_VERSION.tar.gz | tar xvz -C /usr/src/php/ext/apcu --strip 1 \
&& docker-php-ext-install apcu \
# cleanup
&& docker-php-source delete
Installing ext-redis with ext-igbinary
Now things get a little more complicated, we want to install ext-redis
with ext-igbinary
as
serializer. We'll use docker-php-ext-configure
to configure ext-redis
before its installation.
Other than that, it's the same as ext-apcu
.
FROM php:7.3.2-fpm-stretch
ENV EXT_REDIS_VERSION=4.3.0 EXT_IGBINARY_VERSION=3.0.1
RUN docker-php-source extract \
# igbinary
&& mkdir -p /usr/src/php/ext/igbinary \
&& curl -fsSL https://github.com/igbinary/igbinary/archive/$EXT_IGBINARY_VERSION.tar.gz | tar xvz -C /usr/src/php/ext/igbinary --strip 1 \
&& docker-php-ext-install igbinary \
# redis
&& mkdir -p /usr/src/php/ext/redis \
&& curl -fsSL https://github.com/phpredis/phpredis/archive/$EXT_REDIS_VERSION.tar.gz | tar xvz -C /usr/src/php/ext/redis --strip 1 \
&& docker-php-ext-configure redis --enable-redis-igbinary \
&& docker-php-ext-install redis \
# cleanup
&& docker-php-source delete
Installing ext-mongodb
Now things get a little hairy, compiling ext-mongodb
requires a tad more work. We'll use
multi-stage build to keep our result image as clean as possible. The repository
uses submodules, and sadly they are not included in the archive, so we'll have to clone the
repository, which is not ideal. Regarding the installation, I mostly followed the instructions in
the manual.
FROM php:7.3.2-fpm-stretch AS ext-mongodb
ENV EXT_MONGODB_VERSION=1.5.2
RUN docker-php-source extract \
&& apt-get update && apt-get install git -y \
&& git clone --branch $EXT_MONGODB_VERSION --depth 1 https://github.com/mongodb/mongo-php-driver.git /usr/src/php/ext/mongodb \
&& cd /usr/src/php/ext/mongodb && git submodule update --init \
&& docker-php-ext-install mongodb
FROM php:7.3.2-fpm-stretch
# ext-mongodb
COPY --from=ext-mongodb /usr/local/etc/php/conf.d/docker-php-ext-mongodb.ini /usr/local/etc/php/conf.d/docker-php-ext-mongodb.ini
COPY --from=ext-mongodb /usr/local/lib/php/extensions/no-debug-non-zts-20180731/mongodb.so /usr/local/lib/php/extensions/no-debug-non-zts-20180731/mongodb.so
Note: If your base image is phpdaily/php:7.4.0-dev-fpm-stretch
you need to replace
no-debug-non-zts-20180731
with no-debug-non-zts-20190529
.
Final Dockerfile, without PECL
This is our final Dockerfile, without PECL. It's quite verbose, but now we can play with PHP 7.4 or even PHP 8.0.
FROM php:7.3.2-fpm-stretch AS ext-mongodb
ENV EXT_MONGODB_VERSION=1.5.2
RUN docker-php-source extract \
&& apt-get update && apt-get install git -y \
&& git clone --branch $EXT_MONGODB_VERSION --depth 1 https://github.com/mongodb/mongo-php-driver.git /usr/src/php/ext/mongodb \
&& cd /usr/src/php/ext/mongodb && git submodule update --init \
&& docker-php-ext-install mongodb
FROM php:7.3.2-fpm-stretch
# ext-mongodb
COPY --from=ext-mongodb /usr/local/etc/php/conf.d/docker-php-ext-mongodb.ini /usr/local/etc/php/conf.d/docker-php-ext-mongodb.ini
COPY --from=ext-mongodb /usr/local/lib/php/extensions/no-debug-non-zts-20180731/mongodb.so /usr/local/lib/php/extensions/no-debug-non-zts-20180731/mongodb.so
ENV EXT_APCU_VERSION=5.1.17 EXT_REDIS_VERSION=4.3.0 EXT_IGBINARY_VERSION=3.0.1
RUN docker-php-source extract \
# ext-opache
&& docker-php-ext-enable opcache \
# ext-igbinary
&& mkdir -p /usr/src/php/ext/igbinary \
&& curl -fsSL https://github.com/igbinary/igbinary/archive/$EXT_IGBINARY_VERSION.tar.gz | tar xvz -C /usr/src/php/ext/igbinary --strip 1 \
&& docker-php-ext-install igbinary \
# ext-redis
&& mkdir -p /usr/src/php/ext/redis \
&& curl -fsSL https://github.com/phpredis/phpredis/archive/$EXT_REDIS_VERSION.tar.gz | tar xvz -C /usr/src/php/ext/redis --strip 1 \
&& docker-php-ext-configure redis --enable-redis-igbinary \
&& docker-php-ext-install redis \
# ext-apcu
&& mkdir -p /usr/src/php/ext/apcu \
&& curl -fsSL https://github.com/krakjoe/apcu/archive/v$EXT_APCU_VERSION.tar.gz | tar xvz -C /usr/src/php/ext/apcu --strip 1 \
&& docker-php-ext-install apcu \
# ext-bcmath, ext-sockets
&& docker-php-ext-install bcmath sockets \
## cleanup
&& docker-php-source delete
RUN echo '\
opcache.interned_strings_buffer=16\n\
opcache.load_comments=Off\n\
opcache.max_accelerated_files=16000\n\
opcache.save_comments=Off\n\
' >> /usr/local/etc/php/conf.d/docker-php-ext-opcache.ini