docker容器中sh脚本明明存在,启动容器时却一直报错:no such file or directory


先说结论:这个报错的真实含义是 找不到脚本解释器,而不是找不到脚本文件本身!!!

1. 问题产生的背景

我的初衷是将jar包打成docker镜像并部署在Linux上(感兴趣的可以看一下我的另一篇文章:将jar包打成docker镜像并部署在Linux上

刚开始一切都很顺利,但在启动容器时却报了以下错误

exec /tmp/start.sh: no such file or directory

Dockerfile 文件和 start.sh 文件都存放在 /tmp/docker 目录下

Dockerfile文件的内容如下

# 指定基础镜像
FROM java:8-alpine

# 复制文件到镜像中
COPY ./docker-demo-0.0.1-SNAPSHOT.jar /tmp/docker-demo-0.0.1-SNAPSHOT.jar
COPY ./start.sh /tmp/start.sh

# 暴露端口
EXPOSE 16256

# 赋予脚本文件执行权限
RUN chmod +x /tmp/start.sh

# 指定容器启动时运行的指令
ENTRYPOINT ["/tmp/start.sh"]

start.sh脚本文件的内容如下

#!/bin/bash

# 第一个命令
java -jar /tmp/docker-demo-0.0.1-SNAPSHOT.jar

# 第二个命令(如果需要的话)
echo "Hello, World"

2. 排查

我在网络上搜索了各种解决方法,都没有解决问题,我甚至还多次怀疑过Dockerfile文件中的文件复制语句是不是写错了、Dockerfile文件是不是不能使用多条COPY指令,在这个方向上浪费了不少时间。。。

直到我看到这篇文章才有了明确的方向:容器中sh脚本明明存在,为何会报"no such file or directory"的错误?

按照上述文章的方法,我开始逐步排查问题

  • 我将 Dockerfile 文件中的 ENTRYPOINT ["/tmp/start.sh"] 改成了 ENTRYPOINT ["java", "-jar", "/tmp/docker-demo-0.0.1-SNAPSHOT.jar"] ,先将容器启动起来
  • 容器成功启动,说明Dockerfile文件中的文件复制语句没问题
  • 接着进入容器内部,在容器内手动执行 ./start.sh,看到报错信息还是 ./start.sh: not found
  • 但我通过ls命令确实可以查看到start.sh脚本文件的存在
  • 接着我通过cat命令查看start.sh脚本文件的内容,结果如下

在这里插入图片描述

  • 不看不知道,一看吓一跳,一堆乱码
  • 但是,这并不是问题产生的根本原因,即使是乱码,也不影响脚本文件的执行,因为乱码都被注释掉了
  • 我猛然想起,当时创建文件之后,为了方便,就没有使用Linux环境下的vim编辑器,而是通过FinalShell软件将脚本文件下载到本地,接着使用Windows环境下的NodePad++软件编辑脚本
  • 我再次通过FinalShell软件将脚本文件下载到本地,查看文件的换行符和编码格式,发现文件的换行符竟然是Windows环境下的CRLF,编码竟然是GBK

在这里插入图片描述

  • 因为我最开始用NodePad++编辑这个文件时,文件是空的,NodePad++应该是根据我当时的地理位置和电脑的操作系统自动帮我修改了换行符和文件的编码(真是血与泪的教训o(╥﹏╥)o,花了我将近两个小时)

  • 当我修改了文件的换行符和文件的编码后,以为问题已经解决了,再次运行容器,没想到还是报以下错误

    exec /tmp/start.sh: no such file or directory

    o(╥﹏╥)oo(╥﹏╥)oo(╥﹏╥)oo(╥﹏╥)oo(╥﹏╥)o

  • 但是,已经有了排查经验的我,看到同样的报错,觉得肯定是脚本文件的第一行出了问题

  • 我突然回想起,不同的Linux系统,默认使用的脚本解释器可能不一样(CentOS使用的是bash)

  • 于是我再次进入容器内部,查看容器内部默认使用的脚本解释器

在这里插入图片描述

  • 没想到,容器内部使用的脚本解释器竟然是ash

  • 将start.sh文件的第一行改成 #!/bin/ash 后,重新构建容器并运行,终于成功了o(╥﹏╥)oo(╥﹏╥)oo(╥﹏╥)o

  • 至此,问题终于解决(总耗时将近3个小时)

3. 问题产生的原因

  • 在不同的操作系统上,换行符有所差别
    • Windows环境下的换行符是CRLF
    • Linux环境下的换行符是LF
  • 不同的Linux系统默认使用的脚本解释器可能不同

当这个使用了CRLF换行符(Windows环境下的换行符)的脚本文件进入到Docker容器中,第一行就变成了

#!/bin/bash[看不见的CRLF]

而在Linux系统上执行脚本时,LF会被认为是Linux换行符,那么解释器的名称就变成了 bin/bashCR,系统肯定找不到这个文件,所以就会报错 no such file or directory

综上所述,这个报错的真实含义是找不到脚本解释器,而不是找不到脚本文件本身!!!

4. 解决方法

  • 删除脚本文件,用Linux的vim编辑器重新编写脚本,重新构建容器
  • 将脚本文件的第一行换成 #!/bash/容器的脚本解释器
  • 如果你确实想用Windows环境下的文本编辑器,建议先在脚本文件中编写一些内容,接着通过FinalShell等软件将脚本下载到本地,再用Windows环境下的文本编辑器修改脚本,同时要确保文件的换行符为UNIX环境下的LF,编码使用的是UTF-8!!!
  • 脚本文件的第一行可以统一使用 #!/bash/sh ,因为Linux系统一般都会有一个sh软连接,这个软连接指向的就是真正的脚本解释器
  • 13
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

聂 可 以

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值