php
php copied to clipboard
[RFC] enable thread safety (zts) for apache images; drop zts images
If we add --enable-maintainer-zts
to the PHP_EXTRA_CONFIGURE_ARGS
then all three Apache MPMs become available: prefork, worker, and event.
tests:
Apache will start with any of the three MPMs (used event as default).
diff --git a/apache-Dockerfile-block-1 b/apache-Dockerfile-block-1
index a8e0078..630d13c 100644
--- a/apache-Dockerfile-block-1
+++ b/apache-Dockerfile-block-1
@@ -29,9 +29,6 @@ RUN set -ex \
&& chown -R "$APACHE_RUN_USER:$APACHE_RUN_GROUP" "$dir"; \
done
-# Apache + PHP requires preforking Apache for best results
-RUN a2dismod mpm_event && a2enmod mpm_prefork
-
# logs should go to stdout / stderr
RUN set -ex \
&& . "$APACHE_ENVVARS" \
@@ -56,4 +53,4 @@ RUN { \
&& a2enconf docker-php
ENV PHP_EXTRA_BUILD_DEPS apache2-dev
-ENV PHP_EXTRA_CONFIGURE_ARGS --with-apxs2 --disable-cgi
+ENV PHP_EXTRA_CONFIGURE_ARGS --disable-cgi --enable-maintainer-zts --with-apxs2
$ docker run -it --rm df3a4c6a986d
AH00558: apache2: Could not reliably determine the server's fully qualified domain name, using 172.17.0.4. 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.4. Set the 'ServerName' directive globally to suppress this message
[Sat Nov 10 00:37:02.664991 2018] [mpm_event:notice] [pid 1:tid 139860600038592] AH00489: Apache/2.4.25 (Debian) PHP/7.2.12 configured -- resuming normal operations
[Sat Nov 10 00:37:02.665019 2018] [core:notice] [pid 1:tid 139860600038592] AH00094: Command line: 'apache2 -D FOREGROUND'
^C[Sat Nov 10 00:37:03.766817 2018] [mpm_event:notice] [pid 1:tid 139860600038592] AH00491: caught SIGTERM, shutting down
$ docker run -it --rm df3a4c6a986d bash -c 'a2dismod mpm_event && a2enmod mpm_worker && exec docker-php-entrypoint apache2-foreground'
Module mpm_event disabled.
To activate the new configuration, you need to run:
service apache2 restart
Considering conflict mpm_event for mpm_worker:
Considering conflict mpm_prefork for mpm_worker:
Enabling module mpm_worker.
To activate the new configuration, you need to run:
service apache2 restart
AH00558: apache2: Could not reliably determine the server's fully qualified domain name, using 172.17.0.4. 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.4. Set the 'ServerName' directive globally to suppress this message
[Sat Nov 10 00:37:13.585052 2018] [mpm_worker:notice] [pid 1:tid 140705571566784] AH00292: Apache/2.4.25 (Debian) PHP/7.2.12 configured -- resuming normal operations
[Sat Nov 10 00:37:13.585089 2018] [core:notice] [pid 1:tid 140705571566784] AH00094: Command line: 'apache2 -D FOREGROUND'
^C[Sat Nov 10 00:37:14.935140 2018] [mpm_worker:notice] [pid 1:tid 140705571566784] AH00295: caught SIGTERM, shutting down
$ docker run -it --rm df3a4c6a986d bash -c 'a2dismod mpm_event && a2enmod mpm_prefork && exec docker-php-entrypoint apache2-foreground'
Module mpm_event disabled.
To activate the new configuration, you need to run:
service apache2 restart
Considering conflict mpm_event for mpm_prefork:
Considering conflict mpm_worker for mpm_prefork:
Enabling module mpm_prefork.
To activate the new configuration, you need to run:
service apache2 restart
AH00558: apache2: Could not reliably determine the server's fully qualified domain name, using 172.17.0.4. 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.4. Set the 'ServerName' directive globally to suppress this message
[Sat Nov 10 00:37:29.323216 2018] [mpm_prefork:notice] [pid 1] AH00163: Apache/2.4.25 (Debian) PHP/7.2.12 configured -- resuming normal operations
[Sat Nov 10 00:37:29.323244 2018] [core:notice] [pid 1] AH00094: Command line: 'apache2 -D FOREGROUND'
^C[Sat Nov 10 00:37:30.249286 2018] [mpm_prefork:notice] [pid 1] AH00169: caught SIGTERM, shutting down
We'll leave the default on the current mpm_prefork
and note how to swap:
FROM php:7.2-apache
RUN a2dismod mpm_prefork && a2enmod mpm_event
# also a simple one line docker run:
# docker run ... php:7.2-apache bash -c 'a2dismod mpm_prefork && a2enmod mpm_event && exec docker-php-entrypoint apache2-foreground'
We should also be able to do away with the plain -zts
variants, since the cli can still be found in the apache
image.
What effect will this have on Apache mpm_prefork
?
Should we later migrate to mpm_event
?
Other questions, concerns?
notes:
Oh nice; IMO this makes a ton of sense. Does PHP recommend one MPM or another, all other things being equal?
We can also make zts
an alias for apache
in the tags to make this more obvious and hopefully affect less users negatively. 👍
The HTTP/2 guide states:
If your setup can handle it, configuring event mpm is nowadays the best one (if supported on your platform). [src]
So atleast apache recommends mpm_event
https://www.reddit.com/r/PHP/comments/1jo517/multithreading_in_php_with_pthreads/cbhb3ix/ is interesting here -- there's definitely a performance decrease with simply enabling ZTS, and it's non-negligible (I've reproduced those tests, and my machine is significantly faster so the numbers are much lower, but it's still enough difference to make me anxious).
I'm also worried about performance more than usual due to the resurgence of interest on https://github.com/docker-library/php/issues/493, specifically the link to https://medium.com/@uv_d/migrating-our-php-applications-to-docker-without-sacrificing-performance-1a69d81dcafb which shows pretty clearly that we've already got some performance issues compared to Debian that I think we need to dig into and figure out what we're doing different.
In researching more, I found https://blog.remirepo.net/post/2017/11/17/Fedora-27-changes-in-http-and-php (which is interesting by itself), but it links to https://secure.php.net/manual/en/install.unix.apache2.php which has the following warning:
Warning We do not recommend using a threaded MPM in production with Apache 2. Use the prefork MPM, which is the default MPM with Apache 2.0 and 2.2. For information on why, read the related FAQ entry on using Apache2 with a threaded MPM
And from that final link (https://secure.php.net/manual/en/faq.installation.php#faq.installation.apache2):
If you want to use a threaded MPM, look at a FastCGI configuration where PHP is running in its own memory space.
So the official PHP upstream recommendation is to not use mpm_event
, and to instead use PHP-FPM, which is interesting.
(And of course, our own issue about PHP-FPM plus ZTS, https://github.com/docker-library/php/issues/249, which links to https://github.com/krakjoe/pthreads#sapi-support)
Related issue #249 is actually something I'm looking into right now. We have a Zend Application with some console commands that we would like to run through ZTS, while FPM normally deploys with NTS. I understand the use of these versions.
It would've been nice though if there was an image already prepped that contained a executable for ZTS and NTS + FPM for these kind of applications. In #249 the user @j4r3kb is trying to do exactly the same as what I'm trying to realize.
Since PHP's official recommendation with threaded MPMs is to use FPM instead of mod_php
, and distributions have switched to this setup, would a PR for an apache-fpm
variant be accepted?
It'd be a drop-in replacement for apache
, with the limitations of the FPM setup: php_value
/ php_flag
directives not supported in .htaccess
or Apache config.
WDYT?
I'm definitely not keen on seeing more variants here -- we're already pretty out of control here. :confused: :disappointed:
Yes, I understand. There's an easier alternative, we can include FPM in apache
too, and provide an alternate entrypoint that starts both Apache and FPM. The user can then switch from mod_php
to FPM by doing:
RUN a2dismod mpm_prefork php7 && a2enmod mpm_event mod_proxy
CMD ["apache-fpm"]
This gets us the best of both worlds: no performance penalty, while keeping one variant. The only drawback I see is increased image size.
Interesting idea!
I did a really rough build test, and it appears the size difference is ~15MB to enable FPM in the Apache build (~376MB before, ~391MB after), which seems pretty reasonable IMO.
We could probably do that slightly simpler by crafting a configuration file that allows us to simply swap by providing a -D
or an environment variable to our apache2
launch so that users wouldn't have to do a2enmod
/a2dismod
directly. :thinking:
Great, I'll start working on it.
We could probably do that slightly simpler by crafting a configuration file that allows us to simply swap by providing a
-D
or an environment variable to ourapache2
launch so that users wouldn't have to doa2enmod
/a2dismod
directly.
I thought of it (I planned to use -D
to change SetHandler
for FPM) but a2enmod
/a2dismod
create/remove symlinks, so it's not really configuration files. If we want to control modules via -D or an environment variable, I think we'd have to mess with Debian's module loading system thing. Not sure though.
Maybe we could simply add those a2enmod
/ a2dismod
commands to the entrypoint (apache-fpm
), so that only CMD ["apache-fpm"]
is required in the Dockerfile.