容器中 sh 脚本明明存在,为何会报"no such file or directory"的错误?
小伙伴碰到一起奇怪的事故,从 gitlab 上拉取的 docker 镜像项目,在本地开发机上进行 docker build 后,启动容器会报错如下:
/app/run.sh 文件是 ENTRYPOINT 启动的,注释掉 ENTRYPOINT,直接进入容器后可以看到 /app/run.sh 好好在那儿,文件的可执行权限也没有问题。那么问题在哪里?
其实这个问题很简单,但由于容器启动时的错误信息不全,产生了误导,让人误以为找不到 sh 脚本文件。
如果先启动容器,在容器内再手工执行 /app/run.sh,会看到报错信息略有不同。实际报错的是 sh 脚本的第一句:
那么是因为容器内缺失 /bin/bash 解释器吗?也不是,基础镜像没有问题,/bin/bash 好好的存在。
最关键的是,同样的 git 项目拉取到的 sh 脚本和 Dockerfile 在另外一台开发机上进行镜像编译和运行是没有问题的。
仔细观察,发现 sh 脚本文件在不同的机器上,有一点点不同:换行符。
出问题的开发机上,脚本换行符是 Windows 换行符 CRLF,所以这个脚本进入 Docker 容器中,第一行变成了:
那执行脚本的时候,LF 会被认为是 Linux 换行符,而解释器名称就成了”/bin/bashCR“,肯定找不到,所以就会报错"no such file or directory"。
这个报错的真实含义是”找不到脚本的解释器“,而不是找不到脚本本身。
那么为什么脚本文件的换行符被改变为 CRLF 呢,其实是 git 的 core.autocrlf 特性搞的鬼。参考 https://blog.upx8.com/3184
为了避免这种问题,有两个建议:
1,所有的开发机上,统一 git 的 autocrlf 设置,避免其为 true。
2,VSCode 上安装 code-eol 插件,显式的体现出每个文件的换行符,这样可以比较直观的察觉到问题。
评论