What does docker php ext install do?

I'm trying to set up a LAMP web server using docker and was delighted to discover that the good folks over at php have put together a docker container for php.

Reading through the documentation I found three functions that will ostensibly assist me with the installation of php extensions;

  • docker-php-ext-configure
  • docker-php-ext-install
  • docker-php-ext-enable

Being a complete newcomer to php and having tried and failed to enable php modules using a combination of apk add and php.ini hackery (resulting in .so not found errors), I'm ready to admit defeat and do it the proper way.

Unfortunately, the documentation is remarkable vague about what these commands do and how to use them:

We provide the helper scripts docker-php-ext-configure, docker-php-ext-install, and docker-php-ext-enable to more easily install PHP extensions.

I tried to google it as well, but couldn't find any useful resources online either.

I'm now completely confused between what it means to install, configure and install a php extension, and how commands like apk add php7-* relate to all of this.

Please explain what these functions do, and how you would use them to enable php extensions.

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:

  1. Create the corresponding directory in /usr/src/php/ext.
  2. Extract the source in that directory. The source is usually available on GitHub.
  3. 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

What is FPM Docker?

FPM (effing package manager) Docker Images cdrx/fpm-{$distro} are a series of Docker images to quickly get packages building in fpm on different Linux distributions. Each distro has fpm installed and all the required dependencies to build packages for that platform. All images are 64bit.

Does Docker install PHP?

You don't even need to install PHP or NGINX on the server itself. They'll be automatically installed by Docker when you launch the application. You can run the exact same image on your development machine.

What are PHP extensions?

php file extension refers to the name of a file with a PHP script or source code that has a ". PHP" extension at the end of it. It's similar to a Word file with a . doc file extension.

How do you check if PHP extension is installed?

If your server only has a single PHP version installed, you can run this PHP command anywhere, and it will give you the same list of modules. The general command we will be using is php -m. This command will give you the full list of installed PHP modules/extensions.