Taking the Pain Out of PHP Development with Docker Compose
I won’t do PHP for love or money. Since it’s known that I’m a Software
Person, friends and relatives will occasionally ask for help with some random
issues and I’m always happy to take a swing at it. To take some of the pain out
of it, I have a docker-compose setup that makes it easy to run PHP
without polluting my laptop with a lot of dependencies.
Basic Setup
Obviously, you’ll need to have Docker installed.
Presuming you have a directory with your PHP scripts and any supporting HTML,
CSS, assets, etc, you’ll need a docker-compose.yml
file and possibly a Dockerfile
.
If you just need to run a script with no dependencies
Create the following docker-compose.yml
file:
version: "3.8"
services:
php:
image: php:7.2-apache
stdin_open: true
tty: true
ports:
- "80:80"
volumes:
- .:/var/www/html/
Run docker-compose up
. That’s it, you can now connect to http://localhost/, if
your entry point is index.php
or index.html
. Otherwise, you can connect to
http://localhost/filename.php (or filename.html if your working with a
form). Edit, test, repeat. When you’re done, just hit Control-C.
If you need additional PHP Extensions
The PHP Docker image ships with a fair number of extensions preinstalled and enabled. You can see the out of the box configuration with:
docker-compose run php php -i
(The first php is the name of the service, the second is the start of the command.)
However, some extensions, typically ones that require additional libraries are not
installed by default. In this case, you’ll need a Dockerfile
to install
dependencies and enabled the extension. For example, let’s install the PHP GD Image
Processing extension.
Dockerfile:
FROM php:7.2-apache
RUN apt-get update && apt-get -y install libjpeg-dev libpng-dev zlib1g-dev git zip
RUN docker-php-ext-configure gd \
--with-png-dir=/usr/include \
--with-jpeg-dir=/usr/include \
&& docker-php-ext-install gd \
&& docker-php-ext-enable gd
The Dockerfile does the following:
FROM php:7.2-apache
- start with the PHP 7.2 image, anything after will be layered on that.RUN apt-get update && apt-get -y install libjpeg-dev libpng-dev zlib1g-dev git zip
- install the required dependencies to build the GD extension.RUN docker-php-ext-configure gd [...]
- Configure, build, and enable the GD extension.
Obviously, your dependencies and the arguments to docker-php-ext-*
will vary with the extension you are installing, but a little searching should
fine you the right invocation.
Once the Dockerfile
is setup, update docker-compose.yml
to us it by changing:
image: php:7.2-apache
to:
build: .
Now run docker-compose build
followed by docker-compose up
. The
build step is only needed when the Dockerfile
changes.
If you just need to install dependencies with Composer
Composer is a PHP dependency manager for installing packages. For example, I’ve
used it to install PHPMailer. Again, you will need a Dockerfile
:
FROM php:7.2-apache
COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer
COPY . /var/www/html
WORKDIR /var/www/html
RUN composer require phpmailer/phpmailer
ENV PATH="~/.composer/vendor/bin:./vendor/bin:${PATH}"
Walking through this:
FROM php:7.2-apache
- again, start with the PHP 7.2 image an layer on top of that.COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer
install Composer from the composer Docker image.COPY . /var/www/html
andWORKDIR /var/www/html
- copy all of our files to /var/www/html and, in effect,cd
there. This insures Composer will install packages in the right place and find it’s config, if any.RUN composer require phpmailer/phpmailer
- Install the package.ENV PATH="~/.composer/vendor/bin:./vendor/bin:${PATH}"
- Insure that any executables installed by Composer will be found.
Composer can optionally read a composer.json
for a list of dependencies. If
you have one of those, you would call composer install
instead of using the
require command above.
Again docker-compose build
and docker-compose up
get you going.
Need both?
If you need to enable extensions and install packages, simply put both in the
Dockerfile
FROM php:7.2-apache
RUN apt-get update && apt-get -y install libjpeg-dev libpng-dev zlib1g-dev libfreetype6-dev git zip
RUN docker-php-ext-configure gd \
--with-png-dir=/usr/include \
--with-jpeg-dir=/usr/include \
&& docker-php-ext-install gd \
&& docker-php-ext-enable gd
COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer
COPY . /var/www/html
WORKDIR /var/www/html
RUN composer require phpmailer/phpmailer
ENV PATH="~/.composer/vendor/bin:./vendor/bin:${PATH}"
Infrastructure
Once you need databases or other services, you’ve gone beyond a small
favor. Still, it happens… You’ll need to add the additional infrastructure to
the docker-compose.yml
file. Here’s an example for PostgreSQL and Redis:
version: "3.8"
services:
php:
image: php:7.2-apache
stdin_open: true
environment:
- DATABASE_URL=postgres://postgres@database
- REDIS_URL=redis://redis:6379/1
tty: true
ports:
- "80:80"
volumes:
- .:/var/www/html/
database:
image: postgres
environment:
- POSTGRES_HOST_AUTH_METHOD=trust
volumes:
- db_data:/var/lib/postgresql/data
redis:
image: redis
volumes:
db_data:
This sets up Docker containers running Postgres and Redis which can be accessed using the hostnames postgres and redis respectively. Using the environment section of the PHP host, I’ve injected the connection strings. How you’d use/configure them is, of course, totally dependent on your code.
This example doesn’t use a Dockerfile
, but it could. Doing so is left as an
exercise to the reader.
Docker Cheat Sheet
Finally, a few handy commands to help you get by.
docker-compose ps
- See what’s runningdocker-compose stop
- Shut it down. Same as hitting Control-C in the window you ran start in.docker-compose exec php bash
- Get a shell on the running PHP container.docker-compose run php bash
- Start a PHP container and get a shell. Shuts down when you exit.
Hopefully, this will make it a little easier when you want to help a friend with their PHP adventures!
Comments