Building a minimal docker image with Nginx Unit and PHP

Yesterday I told you about Nginx Unit. And just a day earlier I published this post: Runit vs Supervisor.

The problem I was solving with Supervisor & Runit, is as follows. I have a project at hands, a typical web application: Nginx, PHP-FPM, MySQL. In Google Cloud, it is very convenient to deploy dockerized applications with Cloud Run, so you don’t have to care about scaling (automatic) and deployments (zero-downtime, completely managed with a single command). Obviously, these benefits come at a certain price. A container that you deploy to Cloud Run, must listen to web loads on HTTP/HTTPS ports. That is, you can’t deploy PHP-FPM service with cloud run. Instead, in our case, we simply chose to pack Nginx together with PHP-FPM in one container - hence the need for process supervision.

However, for this simple case, there’s another solution which conforms to process-per-conmtainer rule, and it is Nginx Unit. So I decided to experiment, and added Nginx Unit Dockerfile to the same repository. Nginx Unit combines the well-known Nginx with application server which can be a variety of languages, including PHP. Nginx-unit image in this repo is built FROM alpine:edge, and is amazingly small: only 17Mb. Remember, the other two images were 80Mb and 126Mb I wanted to start from the official php:cli-alpine but found out that this image doesn’t support embed SAPI which is required to build the Nginx Unit PHP module. If you choose not the bleeding-edge but the latest stable ALpine version, then you will not be able to install php7.4 from repositories, only 7.3.24 is available ATM. Of course, you can always choose to compile PHP from source for your own image. Given you clean up after building, you will probably get an even smaller resulting image, and you’ll be able to statically compile the extensions you need, for the best performance.

If all you need is a decent web-server + an application server, you might want to pay attention to Nginx Unit.