为什么文件在复制到容器后找不到?

huangapple go评论160阅读模式
英文:

Why file cannot be found after being copied to a container

问题

我有一个类似以下的Dockerfile:

FROM golang:1.19 AS builder
WORKDIR /app
COPY . .
RUN CGO_ENABLED=0 go build -v -o "hello-bin"


#FROM scratch
FROM alpine
COPY --from=builder /app/hello-bin /app/hello-bin
COPY --from=builder /app/start.sh /app/start.sh
WORKDIR /app
ENTRYPOINT  [ "./start.sh" ]

它只是从一个hello-world的go文件构建一个二进制文件。然而,当我尝试使用以下docker-compose设置运行这个容器时,它显示exec ./start.sh: no such file or directory

version: "3"

services:
  hello:
    restart: always
    build:
      context: .
      dockerfile: Dockerfile

目录的结构如下:

❯ tree .
.
├── Dockerfile
├── docker-compose.yaml
├── go.mod
├── hello
├── init.go
└── start.sh

所以start.sh应该通过COPY . .行加载到builder容器中,并且应该通过COPY --from=builder /app/start.sh /app/start.sh传递给第二个容器。

为了提供背景,start.sh的内容如下:

#!/bin/bash

_main() {
  echo "start"
}

_main "$@"

我最困惑的部分是,如果我在Dockerfile中将其更改为CMD [ "ls", "-l" ],它实际上会打印出:

awesomeproject3-hello-1  | -rwxr-xr-x    1 root     root       1819562 May 19 02:41 hello-bin
awesomeproject3-hello-1  | -rwxrwxrwx    1 root     root            51 May 19 02:39 start.sh

而且,如果我将其更改为ENTRYPOINT [ './hello-bin' ],二进制文件也会成功运行。我只是无法弄清楚为什么它说没有./start.sh


更新:受到@larsks的启发,我注意到如果我将./start.sh的头部从#!/bin/bash更改为#!/bin/sh,它就神奇地工作了。我仍然困惑于这里的潜在问题是什么,如果我想保留bash头部,我应该如何修复Dockerfile?

英文:

I have a dockerfile like the following:

FROM golang:1.19 AS builder
WORKDIR /app
COPY . .
RUN CGO_ENABLED=0 go build -v -o "hello-bin"


#FROM scratch
FROM alpine
COPY --from=builder /app/hello-bin /app/hello-bin
COPY --from=builder /app/start.sh /app/start.sh
WORKDIR /app
ENTRYPOINT  [ "./start.sh" ]

which simply build a binary from a hello-world go file. However, when I try to run this container with the following docker-compose setting, it showed exec ./start.sh: no such file or directory.

version: "3"

services:
  hello:
    restart: always
    build:
      context: .
      dockerfile: Dockerfile

The structure of the directory is

❯ tree .
.
├── Dockerfile
├── docker-compose.yaml
├── go.mod
├── hello
├── init.go
└── start.sh

So the start.sh should be loaded to the builder container via the COPY . . line as well, and it should be passed to the second container via the COPY --from=builder /app/start.sh /app/start.sh.

For context, the content of start.sh is as follows:

#!/bin/bash

_main() {
  echo "start"
}

_main "$@"

My most confusing part is that, if I change it to CMD [ "ls", "-l" ] in the Dockerfile, it actually prints out

awesomeproject3-hello-1  | -rwxr-xr-x    1 root     root       1819562 May 19 02:41 hello-bin
awesomeproject3-hello-1  | -rwxrwxrwx    1 root     root            51 May 19 02:39 start.sh

and also if I change it to ENTRYPOINT [ './hello-bin' ] in the Dockerfile, the binary runs successfully as well. I just can't figure out why it says there's no ./start.sh.


UPDATE: inspired by @larsks, I noticed if I change the header of ./start.sh from #!/bin/bash to #!/bin/sh, it magically worked. I am still confused what the underlying issue here, and if I want to keep the bash header, how should I fix the docker file?

答案1

得分: 3

发生错误是因为您在start.sh中使用了#!/bin/bash

Alpine Docker镜像默认没有安装bash。它使用Busybox shell。

您可以在容器中安装bash。请参考https://stackoverflow.com/questions/40944479/docker-how-to-use-bash-with-an-alpine-based-docker-image

或者,您可以根据您在问题评论中提到的,将#!/bin/bash更改为#!/bin/sh

英文:

The error happening because you have used #!/bin/bash in your start.sh.

Alpine docker image doesn't have bash installed by default. It uses the Busybox shell instead.

you can install bash in your container. See https://stackoverflow.com/questions/40944479/docker-how-to-use-bash-with-an-alpine-based-docker-image

or you can change #!/bin/bash into #!/bin/sh as you noted in your comment on the question.

huangapple
  • 本文由 发表于 2023年5月19日 10:51:50
  • 转载请务必保留本文链接:https://go.coder-hub.com/76285708.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定