Containerising PHP
Tips on containerising Moodle on a LAMP stack, with Docker multistage builds
We start by following this Semaphore CI guide folding in:
- Bret Fisher
- Nick Janetakis
- Phil Redmond
- PHP FPM bloke
Which container base image?
Many guides suggest Alpine in all circumstances
Bret Fisher's Docker Con talk from 2019 covered why he didn't use Alpine for Node.
I find that most instruction guides for Moodle assume Ubuntu or Debian, so that e.g. commands like
apt-get
will work.
In this guide, we'll go for:
- an "official" PHP image
- based off Debian
- with Apache baked in
Moodle requirements for 3.9 - PHP 7.2 is required. PHP 7.3 and 7.4 are supported. I'll therefore choose 7.4
Go to the Docker Hub page for official PHP images
- browse the available tags
- the newest ones are all "rc", suggesting that the Release Candidate for PHP 8.0 is out, so we'll look for the previous release, by filtering.
By looking at the digests, we see that these three tags are all the same underlying image:
- php:7.4-apache
- php:7.4-apache-buster
- php:7.4.9-apache
- php:7.4.9-apache-buster
I'll choose php:7.4.9-apache-buster
Note it looks like for PHP 7.3, there was the option of stretch
images (Debian 9) or buster
(Debian 10), but as of PHP 7.4, this has moved to buster
.
If we click through to the underlying image page we see the 32 commands which comprise the image history, ending in:
WORKDIR /var/www/html
EXPOSE 80
CMD ["apache2-foreground"]
What's in our container?
Run this command to:
- pull down the image (if you don't have it already)
- create a container which will be removed when you exit
- map port 8000 on your local machine to port 70 on the container
- give you an interactive terminal
docker run -it -p 8000:80 --rm php:7.4.9-apache-buster
In your browser, go to http://localhost:8000 and you should see
Forbidden
You don't have permission to access this resource.
Apache/2.4.38 (Debian) Server at localhost Port 8000
And on the command line, you'll see
AH00558: apache2: Could not reliably determine the server's fully qualified domain name, using 172.17.0.2. Set the 'ServerName' directive globally to suppress this message
AH00558: apache2: Could not reliably determine the server's fully qualified domain name, using 172.17.0.2. Set the 'ServerName' directive globally to suppress this message
[Fri Aug 28 20:40:58.698283 2020] [mpm_prefork:notice] [pid 1] AH00163: Apache/2.4.38 (Debian) PHP/7.4.9 configured -- resuming normal operations
[Fri Aug 28 20:40:58.698362 2020] [core:notice] [pid 1] AH00094: Command line: 'apache2 -D FOREGROUND'
172.17.0.1 - - [28/Aug/2020:20:41:10 +0000] "\x16\x03\x01\x02" 400 0 "-" "-"
[Fri Aug 28 20:41:14.282539 2020] [autoindex:error] [pid 19] [client 172.17.0.1:58284] AH01276: Cannot serve directory /var/www/html/: No matching DirectoryIndex (index.php,index.html) found, and server-generated directory index forbidden by Options directive
172.17.0.1 - - [28/Aug/2020:20:41:14 +0000] "GET / HTTP/1.1" 403 493 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:79.0) Gecko/20100101 Firefox/79.0"
Exit the command line with Ctrl + C, and you should see
^C[Fri Aug 28 20:41:27.288194 2020] [mpm_prefork:notice] [pid 1] AH00169: caught SIGTERM, shutting down
The --rm
flag means that when the container stopped, it was deleted.
Now we want to create our first Dockerfile
Create a directory - mkdir docker-php
Initialise git - git init
Make a file Dockerfile
Look at Moodle's PHP dependencies
- Semaphore CI's guide on Dockerfile.development, for the correct local permissions.
- Nick Janetakis on a single Dockerfile, adding bits in.
Reference
- semaphoreci.com/community/tutorials/dockeri..
Excellent guide
install-php-extensions supported extensions.
MariaDB
- github.com/wodby/mariadb has all the environment variables
FPM
- cyberciti.biz/faq/how-to-install-php-7-fpm-..
- stackoverflow.com/questions/60774395/docker..
- WordPress, Nginx FPM: gist.github.com/md5/d9206eacb5a0ff5d6be0
- cloudbooklet.com/install-wordpress-with-doc..
- FPM healthcheck: github.com/twinscom/dockerfiles/blob/master..
Work with Docker
- linuxhandbook.com/remove-docker-images
- Entrypoint sh or bash: stackoverflow.com/questions/51508150/standa..
Alpine
Existing images
Work with full Ubuntu
Docker Compose
docker-compose up -d --force-recreate --no-deps --build nginx
Options description
| -d | Detached mode: Run containers in the background, print new container names. Incompatible with --abort-on-container-exit
|
| --force-recreate | Recreate containers even if their configuration and image haven't changed |
| --build | Build images before starting containers. |
| --no-deps | Don't start linked services. |
github.com/paulredmond/php/blob/master/Dock..
- lots of good style here, particularly the curl command:
RUN curl --silent --show-error --fail --location \
--header "Accept: application/tar+gzip, application/x-gzip, application/octet-stream" -o - \
"https://caddyserver.com/download/linux/amd64?plugins=http.expires,http.realip&license=personal&telemetry=off" \
| tar --no-same-owner -C /usr/bin/ -xz caddy
Paul Redmond's book on LeanPub: leanpub.com/docker-for-php-developers
From Bret Fisher
- use Docker Compose v2 if a single developer (rather than in Swarm / Kubernetes)
- Compose v2: docs.docker.com/compose/compose-file/compos..
- healthchecks
From Nick Janetakis
- log to stdout
stackify.com/docker-for-php-a-start-to-fini..
Performance, S6: uvd.co.uk/blog/migrating-php-docker-perform..
- completely build your own: github.com/wemakewaves/php-docker-bench/blo..
Juan Treminio: jtreminio.com/blog/all-in-one-php-fpm-nginx..
- all in one containers, plus Traefik.
interesting fork: jtreminio.com/blog/all-in-one-php-fpm-nginx..
- github.com/alexrayne/docker-alpine-moodle
- DAMP - Docker, Apache, MariaDB & PHP-FPM
Other interesting
gist.github.com/bgallagh3r/2853221 github.com/sm0k3net/Useful-Scripts/blob/mas..
- github.com/aamnah/bash-scripts/blob/master/.. -- functions for installing Apache on Debian for WordPress