问题描述
创建了一个用于启动 jar 包的 Docker 容器,启动后自动退出:
[icexmoon@192 ~]$ docker run --name jw -d -p 8090:8090 javaweb:1.0
ef2ae3996f2209c30fbb928ed8def438014d8028ea2d24ec55b40bd9a6fef602
[icexmoon@192 ~]$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
ef2ae3996f22 javaweb:1.0 "/bin/sh -c 'java -j…" 7 seconds ago Exited (134) 3 seconds ago jw
查看容器日志显示:
[icexmoon@192 ~]$ docker logs jw
library initialization failed - unable to allocate file descriptor table - out of memoryAborted (core dumped)
问题排查
查看宿主机的系统日志:
[icexmoon@192 ~]$ sudo tail -n 100 /var/log/messages
...
Jul 28 13:11:38 localhost systemd-coredump[3424]: Process 3410 (java) of user 0 dumped core.#012#012Stack trace of thread 8:#012#0 0x00007f624cc99438 n/a (/lib/x86_64-linux-gnu/libc-2.23.so + 0x35438)#012#1 0x00007f623090fc86 n/a (/usr/local/java8/jre/lib/amd64/libnet.so + 0x12c86)#012#2 0x00007f623090133b n/a (/usr/local/java8/jre/lib/amd64/libnet.so + 0x433b)#012ELF object binary architecture: AMD x86-64
...
我这里的宿主机是 RockyLinux 9,RHEL 系列的日志文件都类似。但其他的发行版日志文件可能会有所不同。
只能说明调用函数库时出错,没有更多的错误信息。
问题解决
在往上查找类似问题的时候,发现可能是 ulimit 的限制导致类似问题的发生。
先修改宿主机的 ulimit 限制:
[icexmoon@192 ~]$ sudo vim /etc/security/limits.conf
添加以下内容:
* soft noproc 65535 * hard noproc 65535 * soft nofile 65535 * hard nofile 65535 * soft core unlimited
这里* soft noproc 65535
的意思是修改所有用户的进程数上限为65535。
关于 ulimit 的更多介绍可以阅读。
查看修改结果:
[icexmoon@192 ~]$ ulimit -a
real-time non-blocking time (microseconds, -R) unlimited
...
open files (-n) 65535
pipe size (512 bytes, -p) 8
POSIX message queues (bytes, -q) 819200
real-time priority (-r) 0
stack size (kbytes, -s) 8192
cpu time (seconds, -t) unlimited
max user processes (-u) 30402
virtual memory (kbytes, -v) unlimited
file locks (-x) unlimited
比较重要就是open files
,即上面修改的nofile
配置项,这里已经变为65535
。
如果没有改变,重启宿主机。
光宿主机修改还不够,还需要修改容器的这个选项,这点可以在启动容器时通过参数指定:
docker run --name jw --entrypoint bash -p 8090:8090 --ulimit nofile=65535:65535 --ulimit nproc=65535:65535 -it javaweb:1.0
为了方便起见,这里先用 bash 作为容器的启动入口启动容器,以防止容器直接启动失败。这样可以方便进行调试。
因为要进入容器进行调试,所以这里没有加
-d
参数以后台服务方式启动容器。不要忘记加
-it
参数,否则不能将宿主机的标准输入输出(屏幕和键盘)接入容器。
进入容器的 Bash 环境后,查看容器的 ulimit 限制:
root@9e1365a86947:/# ulimit -a
...
open files (-n) 65535
pipe size (512 bytes, -p) 8
POSIX message queues (bytes, -q) 819200
real-time priority (-r) 0
stack size (kbytes, -s) 8192
cpu time (seconds, -t) unlimited
max user processes (-u) 65535
...
很明显,这里的最大文件打开数(open files)和最大用户进程数(max user processes)已经修改为65535。
要验证我们的修改有没有用,可以在容器中直接启动 jar 包:
root@9e1365a86947:/# java -jar /tmp/app.jar
能看到 Spring Boot 的欢迎信息说明程序已经可以正常启动。
现在其实已经解决了问题,每次启动运行 jar 包的镜像时加上相关参数即可,比如:
[icexmoon@192 ~]$ docker run --name jw -p 8090:8090 -d --ulimit nofile=65535:65535 --ulimit nproc=65535:65535 javaweb:1.0
但这样会显得很麻烦,我们可以修改默认的 Docker 镜像启动参数:
[icexmoon@192 ~]$ locate docker.service
/etc/systemd/system/multi-user.target.wants/docker.service
/usr/lib/systemd/system/docker.service
[icexmoon@192 ~]$ cd /usr/lib/systemd/system/
[icexmoon@192 system]$ sudo vim docker.service
内容修改如下:
[Service] # ... ExecStart=/usr/bin/dockerd --default-ulimit nofile=65535:65535 -H fd:// --containerd=/run/containerd/containerd.sock # ...
在ExecStart
中添加参数--default-ulimit nofile=65535:65535
。
重新加载并启动 Docker 服务:
[icexmoon@192 system]$ sudo systemctl daemon-reload
[icexmoon@192 system]$ sudo systemctl restart docker
现在可以不带 ulimit 相关参数启动容器了:
[icexmoon@192 system]$ docker run --name jw -p 8090:8090 -d javaweb:1.0
The End,谢谢阅读。
文章评论