【无标题】
解决Docker部署springboot项目遇到的failed to start thread的java创建GC线程权限问题
报错背景
使用docker在服务器上部署springboot项目时服务器上日志出现报错如下
failed to start thread
“Gc Thread#0”
failed(EPERM)pthread createfor attributes:
stacksize:1024k,guardsize: 4k,detached.
There is insufficient memory for the Java Runtime Environment to continue.
Cannot create worker Gc thread. Out of system resources.
容器内的日志报错如下:
docker容器的日志报错futexwakeup addr=0xfc0030 returned -1
fatal error: unexpected signal during runtime execution
[signal SIGSEGV: segmentation violation code=0x1 addr=0x1006 pc=0x42d18b]
runtime stack:
runtime.throw(0xadfe47, 0x2a)
runtime/panic.go:774 +0x72
runtime.sigpanic()
runtime/signal_unix.go:378 +0x47c
runtime.futexwakeup(0xfc0030, 0x7f7c00000001)
runtime/os_linux.go:68 +0x8b
runtime.notewakeup(0xfc0030)
runtime/lock_futex.go:136 +0x42
runtime.exitsyscallfast_pidle(0x7f7cac42e0c8)
runtime/proc.go:3106 +0xce
runtime.exitsyscallfast.func1()
runtime/proc.go:3059 +0x41
runtime.systemstack(0x45ae84)
runtime/asm_amd64.s:370 +0x66
runtime.mstart()
原因和解释
这个报错大概意思就是,启动线程失败,Java 运行环境内存不足,无法继续。无法创建垃圾回收工作线程。系统资源不足。
出现这个内存不足的原因其实是docker的默认的 seccomp(安全计算模式)策略会限制容器内进程可调用的系统调用 ,导致jvm不能正常创建线程所以我们的java项目就跑不起来。
解决方案
方案一,临时解决方案,添加参数-security-opt seccomp=unconfined有安全风险,不推荐生产环境使用。
只需要在docker的启动命令添加参数-security-opt seccomp=unconfined禁用seccomp即可
# 比如
docker run --security-opt seccomp=unconfined -d -p 8080:8080 my-java-app
方案二,使用自定义的seccomp 策略,生产环境推荐,比较安全
原理
基于 Docker 官方默认模板,仅放开 Java 所需的系统调用(如 pthread_create),而非完全禁用 seccomp
1.下载官方默认 seccomp 模板
终端执行以下命令
wget https://raw.githubusercontent.com/moby/moby/master/profiles/seccomp/default.json -O java-seccomp.json
若从官网无法获取 java-seccomp.json可以私聊我把这个java-seccomp.json文件发给你们,或者评论一下,这个文件字符太多就不放出来了
2.编辑生成的java-seccomp.json在 “syscalls” 数组中新增以下内容(找同级别 syscall 节点插入)
{
"names": ["pthread_create"],
"action": "SCMP_ACT_ALLOW"
}
3.重新启动docker容器,添加参数–security-opt seccomp
#比如
docker run --security-opt seccomp=刚才下载json的绝对路径/java-seccomp.json -d -p 8080:8080 my-java-app
扩展
通过上面两个方案可以解决docker运行springboot项目时出现的报错
Java Runtime Environment to continue.
Cannot create worker Gc thread. Out of system resources
下列措施可以帮助更好的排查这些问题
限制物理机 / 虚拟机线程数限制
# 临时生效(重启失效)添加docker参数
ulimit -u 65535
# 永久生效(修改配置文件)
echo "* soft nproc 65535" >> /etc/security/limits.conf
echo "* hard nproc 65535" >> /etc/security/limits.conf
Java 启动参数优化
# 添加环境变量参数参数和启动选项
docker run -e "JAVA_OPTS=-XX:ParallelGCThreads=8 -XX:ConcGCThreads=2" \
镜像名字 sh -c 'java $JAVA_OPTS -jar app.jar'
进入docker容器
# 进入容器执行相关命令,
docker exec -it 容器名 bash 或者 sh
进入docker容器后查看java启动命令
ps -ef | grep java
进入docker容器后查看启动容器时的环境变量是否生效
比如
docker exec -it 容器名 env | grep -E "变量名1|变量名2"
检查镜像架构是否与宿主机兼容
docker inspect 镜像名 | grep Architecture
seccomp 策略验证
#查看被拒绝的 syscall
strace -f java -jar app.jar 2>&1 | grep -iE 'denied|EPERM'
查看docker配置
docker inspect 镜像名
检查系统端口
netstat -tulpn | grep 想要查看的端口
更多推荐


所有评论(0)