环境信息
AMD EPYC 7551 32-Core Processor 64bit / 452GB / 4.0TB
Kylin Linux Advanced Server V10 (Sword)
Linux-419.90-24.4.v2101.ky10.x86 64-x86 64-with-kylin-10-Sword
Docker 19.03.9
问题现象
Docker容器超过一定数量后无法启动新的容器。
排查和解决
先检查目前正常运行的容器数量,有134个:
> docker ps| wc-l
134
查看了系统可用CPU和内存资源,发现可用16个CPU线程和24GB内存,可用资源还比较宽裕。
考虑到目前运行的容器已经比较多,首先怀疑是打开文件数量(open files)达到上限,检查系统设置值:
> ulimit -n
1024
因为其他类似环境里一般都设置为65535,所以用ulimit -n 65536
将打开文件数上限改大,但问题并没有解决。
既然启动新的容器失败,可能docker daemon日志会有线索,查了一下果然发现有错误信息如下:
> journalctl -ru docker.service
...
04月 26 14:39:35 k2box-211 dockerd[3016]: time="2023-04-26T14:39:35.212798766+08:00" level=error msg="stream copy error: reading from a closed fifo"
04月 26 14:39:35 k2box-211 dockerd[3016]: time="2023-04-26T14:39:35.212674036+08:00" level=error msg="stream copy error: reading from a closed fifo"
04月 26 14:39:26 k2box-211 dockerd[3016]: time="2023-04-26T14:39:26.731792766+08:00" level=warning msg="Health check for container 443a24419f9864ca13a6772c35bb7fe9eabcf317d670d7c73c0383e5473cb397 error: context deadline exceeded"
04月 26 14:39:02 k2box-211 dockerd[3016]: time="2023-04-26T14:39:02.706135654+08:00" level=warning msg="Health check for container d18b85908134d2c45869f68daf825d0c7f6541e77673e8c83a03d34a1c0a3ad9 error: OCI runtime exec failed: exec failed: container_linux.go:318: starting container process caused \"exec: \\\"curl\\\": executable file not found in $PATH\": unknown"
04月 26 14:39:02 k2box-211 dockerd[3016]: time="2023-04-26T14:39:02.699741119+08:00" level=error msg="stream copy error: reading from a closed fifo"
04月 26 14:39:02 k2box-211 dockerd[3016]: time="2023-04-26T14:39:02.699578169+08:00" level=error msg="stream copy error: reading from a closed fifo"
...
日志提示context deadline exceeded
,这个错误信息虽然比较模糊,但从时间上看与尝试创建新容器的时间是吻合的,并且应该是某个阈值的限制。在网上google了一下没有找到相同的问题。
尝试停止了一个正在运行的容器,此时启动新容器能正常成功1个,再启动则会失败,因此确认了是容器数量达到了某个阈值,但为什么是134个?
经过仔细分析,发现这134个容器的启动方式有区别,其中34个是通过docker run
命令行启动的,另外100个是通过docker-java以程序方式启动的(http接口),查看相关代码发现后者果然有限制:
DockerHttpClient httpClient = new ApacheDockerHttpClient.Builder()
.dockerHost(config.getDockerHost())
.sslConfig(config.getSSLConfig())
.maxConnections(100) // 这里对连接数量做了限制
.connectionTimeout(Duration.ofSeconds(30))
.responseTimeout(Duration.ofSeconds(45))
.build();
至此定位到问题原因,解决方法是将maxConnections(100)
改为maxConnections(1024)
并打包更新到问题环境。