停止Docker容器后容器内.jar应用仍持续运行的解决方法
问题场景
- 开发栈:Eclipse环境下使用Maven、MicroProfile框架开发OpenLiberty服务,打包为.jar格式Java应用,本地可通过
java -jar name.jar命令直接运行 - 初始镜像配置:基于OpenJDK官方镜像制作容器镜像,初始Dockerfile内容如下:
FROM openjdk:12-oracle COPY projectname.jar /projectname.jar CMD ["java", "-jar", "projectname.jar"]
- 操作流程:执行
docker build -t takemealong .构建镜像,再执行docker run -p 8080:8080 --name TakeMeAlong_Container takemealong创建并启动容器 - 异常现象:容器启动后运行正常,可正常访问服务index.html页面;但执行停止容器操作、甚至完全退出Docker后,Web服务仍在后台持续运行:任务管理器中可见名为Vmmem的相关进程,index.html页面依然可以正常访问。
问题根因
- Vmmem是Windows系统下WSL2子系统的运行进程,Docker Desktop默认基于WSL2后端运行,默认配置下退出Docker Desktop不会主动关闭WSL2实例,未终止的进程、端口映射规则会残留在WSL2运行态中
- 当前Dockerfile直接将Java进程作为容器内PID 1进程运行,OpenJDK12版本在PID 1场景下默认不会响应Docker发出的SIGTERM终止信号,执行
docker stop时JVM收不到退出指令,不会主动终止 - 普通
docker stop操作默认等待10秒超时,超时后如果进程仍未退出,不会强制清理残留,进程会被WSL2实例持有,持续占用端口运行
解决方案
按以下步骤配置调整,即可实现停止容器时同步终止内部jar应用进程:
- 修改Dockerfile,引入tini轻量init进程负责转发系统信号,解决PID 1进程不响应SIGTERM的问题,修改后内容如下:
FROM openjdk:12-oracle RUN microdnf install -y tini COPY projectname.jar /projectname.jar ENTRYPOINT ["/usr/bin/tini", "--"] CMD ["java", "-jar", "/projectname.jar"]
修改完成后重新执行docker build -t takemealong .构建新镜像即可。
2. 停止容器时直接使用强制删除命令,替代普通的stop操作,命令执行后会直接终止容器内所有进程并清理容器实例:
docker rm -f TakeMeAlong_Container
- 后续启动容器时追加
--rm参数,容器停止时会自动清理自身,避免进程残留:
docker run -d --rm -p 8080:8080 --name TakeMeAlong_Container takemealong
- 如果退出Docker Desktop后仍存在Vmmem进程占用、服务可访问的情况,直接在Windows命令行执行以下命令关闭所有WSL2实例,即可彻底清理所有残留进程:
wsl --shutdown
验证标准:完成上述操作后,刷新服务对应页面确认无法访问,任务管理器中Vmmem进程的CPU、内存占用归零,即代表进程已完全终止。
内容的提问来源于stack exchange,提问作者Eve__BC
相关产品推荐
相关产品推荐

