These images vs others
|Official PHP Images||serversideup/php|
|Run latest version of PHP with Docker||✅||✅|
|PHP Compilation||PHP Source Code||Ondřej Surý PPA|
|Base Operating System||Debian, Alpine||Ubuntu 22.04|
|Init System||Basic, built-in with OS||S6-Overlay|
|Production-Ready by default||❌||✅|
|Built-in security optimizations||❌||✅|
|Optimized for Laravel & WordPress||❌||✅|
|NGINX + FPM variation||❌||✅|
|Native health checks||❌||✅|
S6 Overlay is a perfect match for running PHP because it usually requires running multiple processes together.
Serving a PHP application can be broken down into two different components:
- The PHP Application Itself
There are ways to have these components served together with Apache modules like "mod_php". As time moved on, we found this to be very resource inefficient.
PHP-FPM was the answer to make this serving a PHP application more efficient. This allowed PHP apps to be served with a lot less memory and CPU overhead.
Although this method was more efficient, it meant we still need something to serve our static content. This is where we turned to "reverse proxies".
Reverse proxies are servers that route traffic based on the request. To make things more confusing, you can have a web server be a reverse proxy and a web server at the same time (this is how we run NGINX). You can even configure Apache to run as a web server and a reverse proxy too (we run our
php:*-fpm-apache images like this).
In the example above, you can see the web request coming in from the top. NGINX is our first stop where it inspects the request.
If the request is for a static file (jpeg, js, png, etc), NGINX will also serve that file for us without loading PHP-FPM. This makes the request very fast and efficient.
If the request ends in
.php, then it will send the request over to PHP-FPM. PHP-FPM will then execute the PHP file and return a response to the original client, all passed through NGINX.
In a perfect world, that would be ideal -- but this isn't always realistic. You can see in the example above we need two things running:
- NGINX: To serve static files
- PHP-FPM: To serve PHP application
If you want to replicate your application without the added complexity of multiple physical servers, etc -- you need something like S6 Overlay to properly bring up the processes and ensure your application service health is accurately reported.
S6 Overlay's philosophy is a perfect match when it comes to running PHP:
- A container should do one thing (which may contain multiple processes). When that one thing stops, the container should also stop.
When we configure PHP to run with the S6 Overlay system, we get a number of advantages:
- ✅ S6 Overlay was designed from the ground up to run within containers
- ✅ We get explicit control to run small scripts or configurations before/after the main processes start
- ✅ We get a better confidence on answering "Is my container actually healthy?"
Many people flock to Supervisor, which was a very popular option before containerization. Here's some examples why you may want to trade Supervisor for S6 Overlay:
When you bring up Supervisord within a container, it will be assigned
PID 1. Then Supervisor will bring up child processes with it.
During a failure, Supervisor can be configured to restart the child process to attempt recovery, but the container orchestrator thinks the container is still healthy because
supervisord is occupying
PID 1 which is still healthy.
👉 This design can lead to inaccurate container health statuses during a failure.
S6 Overlay was designed to be run in containers from the ground up. S6 Overlay can also attempt recovery, but it is more accurate on determining container health compared to Supervisor.
👍 By design, S6 Overlay can accurately detect a failure and exit (which is what we want when our app fails).
Since S6 Overlay was designed around the idea of containerization, there are also a number of other advantages to properly time your customizations during container startup.
S6 Overlay has a number of options to write our own service script and properly time everything.
In the example above, you can see we have a
runas-user script which helps us customize and set custom UIDs and GIDs for our file permissions. At the same time,
laravel-automations executes to see if there are any automated migrations to run.
Both scripts must finish successfully before S6 Overlay starts our main
php-fpm process, which has both scripts listed as a dependency.
As you can see this structure can be very powerful in making your own customizations. This is great for giving you full control of how you'd like your application to behave.