Docker images/nginx-php

From Nasqueron Agora

The nasqueron/nginx-php-fpm and nasqueron/nginx-php7-fpm images provide a solution to run PHP applications as a standalone container.

Project goals

While Java, Ruby, Go and Python applications ship with their own server, PHP applications generally needs a webserver to call a FastCGI process, and handle static data. This make harder to adhere to the twelve-factor app methodology.

Meanwhile Docker encourages to run each process in their own container. As such we want to provide 3 options:

  1. Easy deployment of a unique container for the application listening to the port 80: runit, nginx, php-fpm [DONE, IN PROD]
  2. Deployment of a service composed of two containers, one per process: the same image can be used for both nginx and php-fpm containers. [DONE, READY FOR TESTING]
  3. Deployment of only php-fpm, and a standard to publish metadata so a front-end can pick configuration. [UNDER INVESTIGATION]

The PHP offers a fairly comprehensive distribution, providing standard extensions like MySQL and PostgreSQL drivers, XML and internalization ones. We also provide widely used composer and APCu.

Howto

Serve a PHP application located inside a container

Write a Dockerfile deploying your application to /var/wwwroot/default, and start with FROM nginx-php7-fpm:novolume to use our image.

Your files should be readable by the user 'app', with uid 431.

You can find an example for a generic Laravel application at https://github.com/nasqueron/docker-pixelfed.

Serve a PHP application living in a host directory

On your machine, you've a Docker engine, a directory with your PHP application, and you want to quickly run it in a container.

$ docker run -d -it -v '/path/to/your/application:/var/wwwroot/default' -p 8080:80 nasqueron/nginx-php7-fpm

Your application is now ready to http://localhost:8080.

If you need to test a specific nginx configuration, you can also mount a volume with a complete nginx configuration folder as /etc/nginx.

Run standalone nginx and php-fpm containers

If you use docker-compose, Docker Swarm or Kubernetes, you can maintain the application as a set of containers:

  • a container app-backend to host the php-fpm FastCGI process
  • a container app-nginx for nginx to serve static content and call php-fpm
  • the same image for both, to provide them a consistent set of files for your application

To make your image compatible with this method, there are a few preparations to do.

First, your nginx configuration MUST define a hostname to call app-phpfpm: fastcgi_pass app-backend:9000. If you use localhost, for example with fastcgi_pass 127.0.0.1:9000;, it will try to find your php-fpm process in the same container.

Then, your application interacts with user-writable content, your application SHOULD have a separate volume for the content directories, volume shared by both containers. For example if you allow to upload images, this volume could be used by PHP to handle the actual upload and a thumbnail creation, and by nginx to serve the images.

Your containers can then be run with the following commands:

  • app-backend: a bootstrapping script calling /usr/local/sbin/php-fpm --nodaemonize
  • app-nginx: /usr/sbin/nginx

We're interested to document this method ease of use in production and identify pitfalls. You can reach Dereckson for assistance in such a deployment.

Run only php-fpm

If your infrastructure uses configuration as code, you can avoid front-end > nginx > php-fpm, especially if your front-end proxy server is also nginx, or because haproxy added FastCGI support.

As such, you can focus to run the php-fpm process, and delegate configuration to your front-end proxy.

A difficulty of this method is your front-end container needs access to the volume containing static assets like JS or CSS pages, and such assets are often inside a container. The application code should make a clear separation between PHP code and JS/CSS/images/other static assets part, and you need to have a specific volume mounted in your proxy with that content.

Deprecation

PHP 5

We provide a nginx-php-fpm PHP 5 image, but it's still running under Debian Jessie while PHP 7 and 8 images use recent Debian distro, for example Debian Bullseye as of February 2022.

PHP 5.6 reached end of life support in December 2018, and as such doesn't receive security fixes anymore.

runsvdir-init

The Debian package runit offered a runsvdir-init to call runit with a standard service directory, /etc/service. It also cleaned up the environment.

Several PHP applications images depend of it, calling it at the end of their initialization script. To maintain backwards compatibility of those scripts, the docker-php7-fpm image provides an equivalent script, with a deprecation notice.

You can replace your runsvdir-init line by:

/usr/bin/runsvdir -P /etc/service

If you've specified it as entrypoint, CMD ['/usr/bin/runsvdir', '-P', '/etc/service'] could be used, but that's the default entrypoint of the image and as such isn't needed.