容器启动后脚本没反应?先看执行权限
在部署服务时,很多人习惯把初始化逻辑写进 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输出每一步命令,问题通常一眼就能定位。