Docker add extension to php ini

In order to resolve an issue, I am now trying install the mysql pdo via

docker-php-ext-install

as pointed out in the README of the php image.

Yet my call fails stating:

Libraries have been installed in:
   /usr/src/php/ext/mysqli/modules

If you ever happen to want to link against installed libraries
in a given directory, LIBDIR, you must either use libtool, and
specify the full pathname of the library, or use the `-LLIBDIR'
flag during linking and do at least one of the following:
   - add LIBDIR to the `LD_LIBRARY_PATH' environment variable
     during execution
   - add LIBDIR to the `LD_RUN_PATH' environment variable
     during linking
   - use the `-Wl,--rpath -Wl,LIBDIR' linker flag
   - have your system administrator add LIBDIR to `/etc/ld.so.conf'

See any operating system documentation about shared libraries for
more information, such as the ld(1) and ld.so(8) manual pages.
----------------------------------------------------------------------

Build complete.
Don't forget to run 'make test'.

Installing shared extensions:     /usr/local/lib/php/extensions/no-debug-non-zts-20131226/
Installing header files:           /usr/local/include/php/
find . -name \*.gcno -o -name \*.gcda | xargs rm -f
find . -name \*.lo -o -name \*.o | xargs rm -f
find . -name \*.la -o -name \*.a | xargs rm -f 
find . -name \*.so | xargs rm -f
find . -name .libs -a -type d|xargs rm -rf
rm -f libphp.la       modules/* libs/*
+ cd /usr/src/php/ext/mysqlnd
+ phpize
Cannot find config.m4. 
Make sure that you run '/usr/local/bin/phpize' in the top level source directory of the module

ERROR: Service 'phlaconapp' failed to build: The command '/bin/sh -c docker-php-ext-install mysqli mysqlnd pdo pdo_mysql zip' returned a non-zero code: 1

This is my docker-compose.yml:

phlaconapp:
    hostname: phaclonapp
    dockerfile: Dockerfile
    build: ./
    ports:
        - "1080:80"
        - "1043:433"
    environment:
        TERM: xterm-color
        ENVIRONMENT: dev
    volumes:
        - ./:/var/www/html/
    links:
        - mysql
mysql:
    image: mysql:5.6
    volumes:
        - ./docker/mysql.d:/etc/mysql/conf.d
    ports: ["3306:3306"]
    environment:
        MYSQL_ROOT_PASSWORD: 'root'

This is my Dockerfile:

FROM php:5.6-apache

RUN php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');" && \
    php -r "if (hash_file('SHA384', 'composer-setup.php') === '070854512ef404f16bac87071a6db9fd9721da1684cd4589b1196c3faf71b9a2682e2311b36a5079825e155ac7ce150d') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;" && \
    php composer-setup.php && \
    php -r "unlink('composer-setup.php');"


RUN apt-get update && \
    apt-get install vim git -y
RUN docker-php-ext-install mysqli mysqlnd pdo pdo_mysql zip 

RUN  cd /  && \
    git clone --depth=1 git://github.com/phalcon/cphalcon.git && \
    cd cphalcon/build && \
    ./install

RUN echo "extension=phalcon.so" > /usr/local/etc/php/conf.d/phalcon.ini
RUN a2enmod rewrite

and running docker-compose build won't finish.

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 does docker PHP ext install do?

docker-php-ext-install This command is used to install and start PHP extensions. Note: The "source package" needs to be placed under / usr/src/php/ext. By default, the PHP container does not have the directory / usr/src/php, which needs to be generated using docker PHP source extract.

How do I Dockerize a PHP application?

How to Dockerize PHP Applications.
In the root of the project, create a file and name it docker-compose.yml. ... .
In this code, two services with the names php and db are defined these two will connect to run the final application..
'volume' mounts the project directory as a volume on the container at /var/www/html..

Can docker run PHP?

You can use docker run to create a container and execute PHP. You just need to add some volumes to the container. These volumes should include the paths to your code.

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.