通过入口点启动时 Docker 容器的 100% CPU

100% CPU for Docker Container when started via entrypoint

我们编写了一个小型 C++ 应用程序,主要通过 ZeroMQ 对其他进程进行一些监督。所以大部分时间,应用程序空闲并周期性地发送和接收一些请求。

我们基于 ubuntu 构建了一个 docker 映像,其中仅包含此应用程序、一些依赖项和一个 entrypoint.sh。入口点基本上以 /bin/bash 运行,根据环境变量操作一些配置文件,然后通过 exec.

启动应用程序

现在是奇怪的部分。当我们在没有 docker 的情况下手动启动应用程序时,我们得到的 CPU 使用率接近 0%。当我们启动与 docker 图像相同的应用程序时,CPU 使用率上升到 100% 并恰好阻塞一个 CPU 核心。

为了找出发生了什么,我们将图像的入口点设置为 /bin/yes(只是为了确保容器保持 运行),然后在内部启动一个 bash 运行 容器。从那里我们开始手动 entrypoint.sh,CPU 再次为 0%。

所以我们想知道,是什么导致了这种情况。我们需要在 Dockerfile 中添加什么来防止这种情况发生吗?


这是使用 strace 生成的一些输出。我使用了 strace -p <pid> -f -c 并等待了五分钟以收集一些见解。

1。 运行 docker run (100% CPU)

strace: Process 12621 attached with 9 threads
strace: [ Process PID=12621 runs in x32 mode. ]
[...]

% time     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ----------------
 71.26   17.866443         144    124127           nanosleep
 14.40    3.610578       55547        65        31 futex
 14.07    3.528224        1209      2918           epoll_wait
  0.10    0.024760        4127         6         1 restart_syscall
  0.10    0.024700           0     66479           poll
  0.05    0.011339           4      2902         3 recvfrom
  0.02    0.005517           2      2919           write
  0.01    0.001685           1      2909           read
  0.00    0.000070          70         1         1 connect
  0.00    0.000020          20         1           socket
  0.00    0.000010           1        18           epoll_ctl
  0.00    0.000004           1         6           sendto
  0.00    0.000004           1         4           fcntl
  0.00    0.000000           0         1           close
  0.00    0.000000           0         1           getpeername
  0.00    0.000000           0         1           setsockopt
  0.00    0.000000           0         1           getsockopt
------ ----------- ----------- --------- --------- ----------------
100.00   25.073354                202359        36 total

2。 运行 虚拟入口点和 docker exec (0% CPU)

strace: Process 31394 attached with 9 threads
[...]
% time     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ----------------
 67.32   12.544007         102    123355           nanosleep
 14.94    2.784310       39216        71        33 futex
 14.01    2.611210         869      3005           epoll_wait
  2.01    0.373797           6     66234           poll
  1.15    0.213487          71      2999           recvfrom
  0.41    0.076113       15223         5         1 restart_syscall
  0.09    0.016295           5      3004           write
  0.08    0.014458           5      3004           read
------ ----------- ----------- --------- --------- ----------------
100.00   18.633677                201677        34 total

请注意,在第一种情况下,我 strace 稍早开始,因此有一些不同的调用都可以追溯到初始化代码。

我能找到的唯一区别是使用 docker run 时的行 Process PID=12621 runs in x32 mode.。这可能是个问题吗?

另请注意,在这两个测量中,总运行时间约为 20 秒,而该过程 运行 持续了五分钟。


对 100% CPU 案例的一些进一步调查。我用 top -H -p <pid> 检查了进程,只有父进程使用了​​ 100% CPU 而子线程大部分都在空闲。但是当在父进程上调用 strace -p <pid> 时,我可以验证该进程没有做任何事情(没有生成输出)。

所以我确实有一个进程正在使用我的 CPU 的整个核心,什么都不做。

事实证明,软件的某些遗留部分正在 while 循环中等待控制台输入:

while (!finished) {
  std::cin >> command;
  processCommand(command)
}

所以这在 运行 本地和 docker exec 时工作正常。但是由于可执行文件是作为 docker 服务启动的,因此不存在控制台。因此 std::cin 是非阻塞的并立即返回。通过这种方式,我们创建了一个没有任何休眠的无限循环,这自然会导致 100% CPU 使用率。

感谢@Botje 指导我们完成调试过程。