Docker Compose执行down操作前能否运行自定义前置停止命令?
解决方案
核心思路
Docker 停止容器时默认会向容器内 PID 1 进程发送 SIGTERM 信号,等待指定的宽限期后未退出则发送 SIGKILL 强制终止。我们可以通过自定义启动脚本捕获该信号,在容器停止前先执行 screen 内进程的优雅退出逻辑,避免 docker-compose down 卡住。
具体实现步骤
第一步:编写自定义启动脚本
在 docker-compose 项目目录下新建启动脚本 start.sh,内容如下:
#!/bin/bash # 优雅退出处理逻辑 cleanup() { # 向指定screen会话发送Minecraft服务停止指令(会自动保存存档后退出,比直接退出screen更安全) screen -S mc_screen -p 0 -X stuff "stop$(printf \\r)" # 等待screen会话完全退出后再结束脚本 while screen -list | grep -q "mc_screen"; do sleep 1 done exit 0 } # 捕获docker stop默认发送的SIGTERM信号 trap cleanup SIGTERM # 后台启动screen运行Minecraft进程,mc_screen为自定义的screen会话名 screen -dmS mc_screen java -Xmx4G -Xms2G -jar server.jar nogui # 保持脚本前台运行,持续接收信号 while true; do sleep 1 done
本地执行以下命令给脚本添加执行权限:chmod +x start.sh
第二步:修改docker-compose.yml配置
调整服务配置,使用自定义脚本启动,同时配置停止宽限期:
version: '3' services: minecraft: build: . # 如果你需要预装screen,搭配下方Dockerfile使用 # 如无需自定义镜像,可直接用预装screen的openjdk镜像替换上方build配置 # image: 你的自定义镜像名 working_dir: /data volumes: - ./mc-world:/data # 映射Minecraft存档目录 - ./start.sh:/start.sh # 映射自定义启动脚本 command: /start.sh # 替换默认启动命令为自定义脚本 # 配置优雅停止宽限期,根据存档大小调整,避免存档未保存完被强制停止 stop_grace_period: 2m ports: - "25565:25565" # 保留tty和stdin配置,保证screen正常运行 tty: true stdin_open: true
可选:配置Dockerfile预装screen
如果使用的基础镜像没有screen,在项目目录下新建Dockerfile:
FROM openjdk:17-jdk-slim RUN apt update && apt install -y screen && rm -rf /var/lib/apt/lists/*
验证效果
- 后台启动服务:
docker-compose up -d - 接入Minecraft终端:
docker exec -it <容器名> screen -r mc_screen,按Ctrl+A+Ddetach不会杀死进程 - 停止服务:
docker-compose down,会先触发脚本内的cleanup逻辑,等Minecraft存档保存、screen退出后再正常停止容器,不会出现卡住的问题。 - 如果确实需要直接退出screen而非发送MC的stop命令,把cleanup函数内的stuff参数替换为
exit$(printf \\r)即可。
内容的提问来源于stack exchange,提问作者Nur1
相关产品推荐
相关产品推荐

