Docker容器执行含SSH的bash脚本后异常锁定问题求助
问题描述
在Windows本地运行的Docker容器用于Web应用开发测试,此前状态稳定。近期在容器内执行含SSH操作的自定义部署脚本deployment.sh后,容器出现异常:
- 无法访问本地Web应用
- 无法运行其他脚本
- 重启容器时报错:
Cannot restart container exampleWebapp: tried to kill container, but did not receive an exit event - 执行
exit、停止/重建容器均无效,仅重启Docker引擎(99%情况恢复,偶尔失效)可临时解决,严重影响工作流程
该脚本在Apache服务器运行正常,仅在Docker Unix虚拟机环境中出现问题,脚本核心片段如下:
for target in $targets; do rsync *checks differences between target and local* read -p "Deploying to $target on $server. Continue with Sync? " -n 1 -r if [[ $REPLY =~ ^[Yy]$ ]]; then rsync *commands to clone my changed webapp content and exclude desired files* else exit fi done
可能的原因分析
- 脚本
exit命令终止容器主进程:Docker容器生命周期绑定主进程,若通过docker exec执行脚本时触发exit,且容器主进程为bash(或脚本意外继承主进程PID),会直接终止主进程导致容器僵死。 - 资源耗尽导致WSL2虚拟机无响应:Docker Desktop依赖WSL2虚拟机,rsync同步大量文件时若占用过高CPU、内存或磁盘IO,会导致虚拟机进程无响应,Docker无法正常控制容器。
- SSH连接未关闭引发资源泄漏:脚本中的SSH操作若未正确关闭连接,会残留僵尸进程或打开的文件描述符,耗尽容器内资源,导致容器无法响应。
- 交互式
read的终端异常:docker exec执行带read的脚本时,可能因TTY缺失、信号处理异常导致进程挂起,引发容器状态异常。
解决与恢复方案
临时恢复容器(无需重启Docker引擎)
- 执行
docker inspect exampleWebapp获取容器的PID信息 - 在Windows命令行中运行
wsl --exec kill -9 <容器PID>(针对WSL2后端),强制终止容器进程 - 之后即可正常执行
docker rm exampleWebapp并重建容器
脚本与流程修复(根源解决)
避免终止容器主进程
将脚本中的exit改为break,仅退出循环而非终止整个会话:for target in $targets; do rsync *checks differences between target and local* read -p "Deploying to $target on $server. Continue with Sync? " -n 1 -r if [[ $REPLY =~ ^[Yy]$ ]]; then rsync *commands to clone my changed webapp content and exclude desired files* else break # 退出循环而非终止进程 fi done优化交互式执行
执行docker exec时添加-it参数确保终端交互正常:docker exec -it exampleWebapp ./deployment.sh也可新增
--force参数跳过确认,实现非交互式运行:force_sync=false if [[ "$1" == "--force" ]]; then force_sync=true fi for target in $targets; do rsync *checks differences between target and local* if $force_sync || (read -p "Deploying to $target on $server. Continue with Sync? " -n 1 -r && [[ $REPLY =~ ^[Yy]$ ]]); then rsync *commands to clone my changed webapp content and exclude desired files* else break fi done优化rsync/SSH操作
- rsync添加
--partial参数避免传输中断残留临时文件 - SSH连接添加超时参数:
ssh -o ConnectTimeout=10 -o ServerAliveInterval=5,防止连接挂起 - 用
--bwlimit=1000限制rsync带宽(单位KB/s),避免耗尽WSL2资源
- rsync添加
分离部署脚本与应用容器
单独创建临时部署容器,挂载应用代码和SSH密钥,执行完成后销毁:docker run --rm -v /path/to/local/app:/app -v ~/.ssh:/root/.ssh alpine:latest sh -c "cd /app && ./deployment.sh"
内容的提问来源于stack exchange,提问作者Powermaster Prime
相关产品推荐
相关产品推荐

