问题
I'm containerizing a PHP application and would like to modify the Apache configuration based on environment variables. This is done in a script overriding the default ENTRYPOINT
:
FROM php:7.2-apache
# ...
COPY prepare-docker-configs.sh .
RUN chmod +x prepare-docker-configs.sh
ENTRYPOINT ./prepare-docker-configs.sh
After those modifications, Apache doesn't start. apache2-foreground seems to be the missing command, so I run it at the end of prepare-docker-configs.sh
#!/bin/bash
# ... Some config substitution
apache2-foreground
Now Apache got started and everything works as expected. But I noticed that stopping the container is much slower than before. I ran time docker-compose down
for both constellations:
Without my custom overriden ENTRYPOINT
real 0m2,080s
user 0m0,449s
sys 0m0,064
With my custom script as ENTRYPOINT
real 0m12,247s
user 0m0,491s
sys 0m0,067s
So it takes about 10 seconds longer. Especially during development where a lot of testing is done, this would waist a lot of time in total.
Why is my custom ENTRYPOINT
so much slower on stopping and how could it be fixed?
I tried adding STOPSIGNAL SIGWINCH
from the original Dockerfile and also run docker-php-entrypoint
, both doesn't help.
The docker-compose.yml
file is nothing special. It just defines the services and override the default network because of internal conflicts:
version: '2'
services:
app:
build:
context: .
args:
http_proxy: ${http_proxy}
env_file: docker.env
ports:
- 80:80
networks:
default:
driver: bridge
ipam:
config:
- subnet: 10.10.8.0/28
What doesn't work
Ressource issues
I'm running this on my Ubuntu workstation with SSD, i7 Quadcore and 32GB RAM. It doesn't run anything large, the load is quite low. A ressource issue is very unlikely. And the performance issue is reproduceable: On another Ubuntu machine with Ryzen 5 3600 and 48GB memory it took 11 seconds with overriden ENTRYPOINT
. The same result on Debian with a much slower i3.
Calling the original ENTRYPOINT
In my script, I call docker-php-entrypoint
at the end, which executes the original entrypoint script from the PHP image. It doesn't start Apache successfully, I had to call apache2-foreground
instead.
Starting the Apache process with the RUN
statement
I added a CMD
directive to my Dockerfile
ENTRYPOINT ./prepare-docker-configs.sh
CMD apache2-foreground
and an exec
statement at the end of prepare-docker-configs.sh
assuming that the CMD
entry got passed
set -x
exec "$@"
But the container exited because nothing was passed
app_1 | + set -x
app_1 | + exec
test_app_1 exited with code 0
I tested passing the file directly
exec apache2-foreground
Now Apache is started, but it still takes 10+ seconds to stop.
回答1:
A Docker container runs a single process; when you declare an ENTRYPOINT
in the Dockerfile, that is the process. When you docker stop
a container, it sends SIGTERM to that process (only), and if it doesn't stop itself within 10 seconds, it sends SIGKILL to forcibly kill it off. Since the container process has process ID 1, there are also some special conditions on signal handling.
In your case, the bash
instance running the entrypoint script is the root process, and it's running apache2-foreground
as a child process. You can use the Bourne shell exec command to replace the shell with the process you're trying to run; then apache2-foreground
the main container process instead, and the docker stop
signals go straight to that process.
A typical pattern for entrypoint scripts is to honor the Docker "command" part. This gets passed to the entrypoint as additional arguments, so your entrypoint script typically looks like
#!/bin/sh
# ... Some config substitution
exec "$@"
and then in your Dockerfile you need to provide the default command to run
# NOTE! ENTRYPOINT must be JSON-array syntax for this to work
ENTRYPOINT ["./prepare-docker-configs.sh"]
CMD apache2-foreground
Since the entrypoint script still exec
s the command, it replaces the shell command wrapper as process 1 and will receive the docker stop
signals.
来源:https://stackoverflow.com/questions/62596598/stopping-apache2-is-much-slower-when-overriding-entrypoint-in-docker