智汇百科
霓虹主题四 · 更硬核的阅读氛围

容器执行Shell脚本常见问题排查

发布时间:2025-12-18 22:00:23 阅读:8 次

容器启动后脚本没反应?先看执行权限

在部署服务时,很多人习惯把初始化逻辑写进 shell 脚本,然后让容器启动时自动运行。但有时候镜像构建完,跑起来却发现脚本压根没执行,日志也没输出。这种情况大概率是脚本没有可执行权限。

比如你写了 init.sh 放进镜像,Dockerfile 里也 COPY 进去了,但忘了加 chmod。容器里一查:

ls -l /opt/init.sh
发现权限是 -rw-r--r--,那就算 CMD 写了执行,也会提示 "Permission denied"。

解决办法很简单,在 Dockerfile 里补上:

RUN chmod +x /opt/init.sh

脚本路径不对,找不到文件

另一个常见问题是路径写错。比如脚本放在项目根目录的 scripts/ 下,COPY 到了容器的 /app/scripts/,但启动命令却写成了:

CMD ["/bin/bash", "scripts/init.sh"]
少了个斜杠,实际找的是相对路径,而容器启动时工作目录不一定是你预期的,自然就报 no such file or directory

建议用绝对路径:

CMD ["/bin/bash", "/app/scripts/init.sh"]
或者确认 WORKDIR 设置正确。

脚本第一行别乱写

有些脚本开头写的是 #!/bin/sh,但某些精简镜像(比如 alpine)里 /bin/sh 是 dash,语法不兼容 bash 扩展功能。如果你用了数组、条件表达式等 bash 特性,就会出错。

稳妥做法是明确指定解释器,比如改成:

#!/bin/bash
同时确保镜像里安装了 bash。alpine 镜像需要额外运行:
apk add --no-cache bash

容器一闪而过,脚本执行完就退出

这是新手最容易懵的场景:容器运行一下就变成 exited 状态。原因在于,容器主进程就是那个 shell 脚本,脚本一跑完,主进程结束,容器自然退出。

比如你在脚本最后只启动了个临时任务,没留常驻进程。如果想让容器持续运行,得在脚本末尾加个阻塞命令:

tail -f /dev/null
或者用 sleep infinity(部分系统支持),也可以改用 supervisord 管理多个进程。

环境变量在脚本里读不到?

有时候在 docker run 时用 -e ENV=prod 传了变量,但脚本里 $ENV 却为空。可能是因为 shell 解释器没加载环境。特别是用 /bin/sh 或直接 exec 的情况。

可以在脚本开头加一行调试:

env
看看变量是否真传进来了。如果 env 能看到但脚本取不到,检查是否用了 source. 加载配置文件时路径错了,或者脚本被子 shell 执行导致环境丢失。

小技巧:手动进容器调试

实在搞不定,可以直接进容器看现场:

docker exec -it container_name /bin/bash
然后手动运行脚本,加 -x 参数看执行过程:
bash -x /opt/init.sh
输出每一步命令,问题通常一眼就能定位。