通过入口点启动时 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 指导我们完成调试过程。
我们编写了一个小型 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 指导我们完成调试过程。