在设置docker-compose的entrypoint时出现"/bin/sh: No such file or directory"的错误信息。

3

我有一个运行数据库迁移的容器(源代码):

FROM golang:1.12-alpine3.10 AS downloader
ARG VERSION

RUN apk add --no-cache git gcc musl-dev

WORKDIR /go/src/github.com/golang-migrate/migrate

COPY . ./

ENV GO111MODULE=on
ENV DATABASES="postgres mysql redshift cassandra spanner cockroachdb clickhouse mongodb sqlserver firebird"
ENV SOURCES="file go_bindata github github_ee aws_s3 google_cloud_storage godoc_vfs gitlab"

RUN go build -a -o build/migrate.linux-386 -ldflags="-s -w -X main.Version=${VERSION}" -tags "$DATABASES $SOURCES" ./cmd/migrate

FROM alpine:3.10

RUN apk add --no-cache ca-certificates

COPY --from=downloader /go/src/github.com/golang-migrate/migrate/build/migrate.linux-386 /migrate

ENTRYPOINT ["/migrate"]
CMD ["--help"]

我希望将其集成到docker-compose中,并使其依赖于Postgres数据库服务。但是,由于我必须等待数据库完全初始化,因此我必须在脚本中包装migrate命令,并替换迁移容器的入口点。我正在使用wait-for脚本来轮询数据库,这是一个纯shell(而不是bash)脚本,因此应该可以在alpine容器中工作。

以下是在docker-compose中定义该服务的方式:

services:
    database:
        # ...
    migration:
        depends_on:
            - database
        image: migrate/migrate:v4.7.0
        volumes:
            - ./scripts/migrations:/migrations
            - ./scripts/wait-for:/wait-for
        entrypoint: ["/bin/sh"]
        command: ["./wait-for database:5432", "--", "./migrate", "-path", "/migrations", "-database", "postgres://test:test@database:5432/test?sslmode=disable",  "-verbose", "up"]

运行docker-compose up失败并出现以下信息:

migration_1           | /bin/sh: can't open './wait-for database:5432': No such file or directory

使用下列命令在容器中运行迁移(migrate):

docker run -it --entrypoint /bin/sh -v $(pwd)/scripts/wait-for:/wait-for  migrate/migrate:v4.7.0

这个脚本可以通过使用/bin/sh ./wait-for命令来执行,但是在docker-compose中为什么会失败呢?

3个回答

4

仔细阅读错误信息,您会发现找不到的文件不是./waitfor,而是./wait-for database: 5432。这与您的输入文件一致,其中整个内容作为command列表的第一个元素给出:

        command: ["./wait-for database:5432", "--", "./migrate", "-path", "/migrations", "-database", "postgres://test:test@database:5432/test?sslmode=disable",  "-verbose", "up"]

我不清楚你实际想要的是什么,因为提供的可行替代方案似乎并不完全类似,但可能是

        command: ["./wait-for", "database:5432", "--", "./migrate", "-path", "/migrations", "-database", "postgres://test:test@database:5432/test?sslmode=disable",  "-verbose", "up"]

谢谢,这确实解决了问题。我从来没有真正理解过这个数组语法,但似乎我应该这样做。 - gmolau
@gmolau,每个数组元素都作为单独的命令行单词提供。它们不会被扩展、分割等等。空格字符和其他对shell特殊的字符在这种情况下并不是特殊的,尽管它们对运行的命令具有其通常的意义。 - John Bollinger

0
在自己的迁移容器中运行是完美无缺的。当您像这样运行它时:docker run -it --entrypoint /bin/sh -v $(pwd)/scripts/wait-for:/wait-for migrate/migrate:v4.7.0,entrypoint /bin/sh 将被执行。当您使用docker-compose运行它时:entrypoint (/bin/sh) + command (./wait-for database:5432) ...将被执行。./wait-for database:5432作为整体代表将要运行的可执行文件,但找不到它,这就是为什么会出现错误No such file or directory的原因。尝试在command:中指定wait-for的绝对路径,并将./wait-for database:5432拆分成"./wait-for","database:5432"。拆分可能已经足够了。

作为替代方案,您可以遵循CMD语法文档并使用不带数组的不同命令语法:command: ./wait-for database:5432 ...


1
你的意思是绝对路径是/wait-for,但是这样会得到相同的结果吗? - gmolau

0

ENTRYPOINT ["/bin/sh"] 不够,你还需要 -c 参数。

例如(在此处使用 docker-compose run --rm MYSERVICENAMEFROMTHEDOCKERCOMPOSEFILE bash 测试 docker-compose.yml):

entrypoint: ["/bin/sh"]

抛出:

/bin/sh: 0: cannot open bash: No such file
ERROR: 2

还有一些错误的语法示例,例如

entrypoint: ["/bin/sh -c"]

(错误!)

或者

entrypoint: ["/bin/sh, -c"]

(错误!)

抛出错误:

starting container process caused: exec: "/bin/sh, -c": stat /bin/sh, -c: no such file or directory: unknown
ERROR: 1


starting container process caused: exec: "/bin/sh -c": stat /bin/sh -c: no such file or directory: unknown
ERROR: 1

在docker-compose或Dockerfile中,对于一个entrypoint,你需要使用-c参数。 这是正确的:
entrypoint: "/bin/sh -c"

或者:

entrypoint: ["/bin/sh", "-c"]

-c 的作用是明确这是一个在命令行中执行的命令,等待在该命令行中使用额外的命令。但不会自行启动bash /bin/sh。你可以在What is the difference between CMD and ENTRYPOINT in a Dockerfile?中读到其中的差别。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接