在 Docker 中覆盖 ENTRYPOINT 时,停止 Apache2 的速度要慢得多 [英] Stopping Apache2 is much slower when overriding ENTRYPOINT in Docker

查看:51
本文介绍了在 Docker 中覆盖 ENTRYPOINT 时,停止 Apache2 的速度要慢得多的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在容器化一个 PHP 应用程序,并想根据环境变量修改 Apache 配置.这是在覆盖默认 ENTRYPOINT 的脚本中完成的:

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

在这些修改之后,Apache 不会启动.apache2-foregrounda> 似乎是缺少的命令,所以我在 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

现在 Apache 启动了,一切都按预期进行.但是我注意到停止容器比以前慢.我为两个星座运行了 time docker-compose down:

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:

real    0m2,080s
user    0m0,449s
sys 0m0,064

使用我的自定义脚本作为 ENTRYPOINT

real    0m12,247s
user    0m0,491s
sys 0m0,067s

因此需要大约 10 秒的时间.尤其是在进行大量测试的开发过程中,这总共会占用大量时间.

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.

我尝试从原始 Dockerfile 添加 STOPSIGNAL SIGWINCH 并运行 docker-php-entrypoint,两者都没有帮助.

I tried adding STOPSIGNAL SIGWINCH from the original Dockerfile and also run docker-php-entrypoint, both doesn't help.

docker-compose.yml 文件没什么特别的.由于内部冲突,它只是定义了服务并覆盖了默认网络:

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

什么不起作用

资源问题

我在配备 SSD、i7 Quadcore 和 32GB RAM 的 Ubuntu 工作站上运行它.它没有运行任何大的东西,负载很低.资源问题的可能性很小.并且性能问题是可重现的:在另一台配备 Ryzen 5 3600 和 48GB 内存的 Ubuntu 机器上,覆盖 ENTRYPOINT 需要 11 秒.Debian 上的结果相同,但 i3 速度要慢得多.

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.

在我的脚本中,我在最后调用 docker-php-entrypoint,它执行 PHP 镜像中的原始入口点脚本.它没有成功启动 Apache,我不得不调用 apache2-foreground 代替.

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.

我在 Dockerfile

ENTRYPOINT ./prepare-docker-configs.sh
CMD apache2-foreground

prepare-docker-configs.sh 末尾的 exec 语句,假设 CMD 条目已通过

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

我测试过直接传文件

exec apache2-foreground

现在Apache已启动,但仍然需要10多秒才能停止.

Now Apache is started, but it still takes 10+ seconds to stop.

推荐答案

Docker 容器运行单个进程;当您在 Dockerfile 中声明 ENTRYPOINT 时,这就是过程.当你 docker stop 一个容器时,它会(仅)向该进程发送 SIGTERM,如果它在 10 秒内没有停止自己,它会发送 SIGKILL 以强行杀死它.由于容器进程的进程ID为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.

在您的情况下,运行入口点脚本的 bash 实例是根进程,它作为子进程运行 apache2-foreground.您可以使用 Bourne shell exec 命令用您尝试运行的进程替换 shell;然后 apache2-foreground 主容器进程代替,docker stop 信号直接进入该进程.

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.

入口点脚本的典型模式是遵守 Docker命令"部分.这将作为附加参数传递给入口点,因此您的入口点脚本通常看起来像

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 "$@"

然后在您的 Dockerfile 中您需要提供要运行的默认命令

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

由于入口点脚本仍然execs命令,它将shell命令包装器替换为进程1,并将接收docker stop信号.

Since the entrypoint script still execs the command, it replaces the shell command wrapper as process 1 and will receive the docker stop signals.

这篇关于在 Docker 中覆盖 ENTRYPOINT 时,停止 Apache2 的速度要慢得多的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆