在 Docker 中覆盖 ENTRYPOINT 时,停止 Apache2 的速度要慢得多

Lio*_*ion 0 performance apache2 docker dockerfile docker-compose

我正在对 PHP 应用程序进行容器化,并希望根据环境变量修改 Apache 配置。这是在覆盖默认值的脚本中完成的ENTRYPOINT

FROM php:7.2-apache
# ...
COPY prepare-docker-configs.sh .
RUN chmod +x prepare-docker-configs.sh
ENTRYPOINT ./prepare-docker-configs.sh
Run Code Online (Sandbox Code Playgroud)

进行这些修改后,Apache 不会启动。apache2-foreground似乎缺少命令,所以我在末尾运行它prepare-docker-configs.sh

#!/bin/bash
# ... Some config substitution
apache2-foreground
Run Code Online (Sandbox Code Playgroud)

现在 Apache 已经启动,一切都按预期进行。但我注意到停止容器比以前慢得多。我跑time docker-compose down了两个星座:

没有我的自定义覆盖ENTRYPOINT

real    0m2,080s
user    0m0,449s
sys 0m0,064
Run Code Online (Sandbox Code Playgroud)

我的自定义脚本为ENTRYPOINT

real    0m12,247s
user    0m0,491s
sys 0m0,067s
Run Code Online (Sandbox Code Playgroud)

所以需要大约10秒的时间。特别是在需要进行大量测试的开发过程中,这总共会浪费大量时间。

为什么我的自定义ENTRYPOINT停止速度如此之慢?如何解决?

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

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

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
Run Code Online (Sandbox Code Playgroud)

什么不起作用

资源问题

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

调用原件ENTRYPOINT

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

RUN使用以下语句启动 Apache 进程

CMD在我的中添加了一个指令Dockerfile

ENTRYPOINT ./prepare-docker-configs.sh
CMD apache2-foreground
Run Code Online (Sandbox Code Playgroud)

以及假设条目已通过的exec末尾的声明prepare-docker-configs.shCMD

set -x
exec "$@"
Run Code Online (Sandbox Code Playgroud)

但容器退出了,因为没有传递任何内容

app_1     | + set -x
app_1     | + exec
test_app_1 exited with code 0
Run Code Online (Sandbox Code Playgroud)

我测试过直接传递文件

exec apache2-foreground
Run Code Online (Sandbox Code Playgroud)

现在Apache已经启动了,但是仍然需要10多秒才能停止。

Dav*_*aze 5

Docker 容器运行单个进程;ENTRYPOINT当你在 Dockerfile 中声明一个时,这就是这个过程。当你是docker stop一个容器时,它会(仅)向该进程发送 SIGTERM,如果它在 10 秒内没有停止自己,它会发送 SIGKILL 来强制终止它。由于容器进程的进程ID为1,因此信号处理也有一些特殊条件。

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

入口点脚本的典型模式是遵循 Docker“命令”部分。这将作为附加参数传递给入口点,因此您的入口点脚本通常如下所示

#!/bin/sh
# ... Some config substitution
exec "$@"
Run Code Online (Sandbox Code Playgroud)

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

# NOTE! ENTRYPOINT must be JSON-array syntax for this to work
ENTRYPOINT ["./prepare-docker-configs.sh"]
CMD apache2-foreground
Run Code Online (Sandbox Code Playgroud)

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