Docker Compose:exec: "docker-deploy.sh": executable file not found in $PATH: unknown
我的项目的目录结构。
myapp/
src/
Dockerfile
docker-compose.yml
docker-deploy.sh
wait-for-it.sh
.env
其中wait-for-it.sh
是wait-for-it脚本的一个副本。
我的Dockerfile
。
FROM node:16
WORKDIR /usr/src/app
COPY package*.json ./
COPY wait-for-it.sh ./
COPY docker-deploy.sh ./
RUN chmod +x docker-deploy.sh
RUN npm install --legacy-peer-deps
COPY . .
RUN npm run build
ENTRYPOINT ["docker-deploy.sh"]
而docker-deploy.sh
则是。
#!/bin/bash
# make wait-for-it executable
chmod +x wait-for-it.sh
# call wait-for-it with passed in args and then start node if it succeeds
bash wait-for-it.sh -h $1 -p $2 -t 300 -s -- node start
还有我的docker-compose.yml
。
version: '3.7'
services:
my-service:
build: .
postgres:
container_name: postgres
image: postgres:14.3
environment:
POSTGRES_PASSWORD: ${DB_PASSWORD}
POSTGRES_USER: ${DB_USER}
POSTGRES_DB: my-service-db
PG_DATA: /var/lib/postgresql2/data
ports:
- ${DB_PORT}:${DB_PORT}
volumes:
- pgdata:/var/lib/postgresql2/data
volumes:
pgdata:
以及我的.env
是:
DB_PASSWORD=1234
DB_USER=root
DB_PORT=5432
当我从项目根目录运行下面的命令行时。
docker-compose --env-file .env up --build
我得到的是。
Creating myapp_my-service_1 ... error
Creating postgres ...
Creating postgres ... done
ERROR: for my-service Cannot start service my-service: OCI runtime create failed: container_linux.go:380: starting container process caused: exec: "docker-deploy.sh": executable file not found in $PATH: unknown
ERROR: Encountered errors while bringing up the project.
发生了什么事?错误是来自wait-for-it.sh
脚本本身,还是来自Dockerfile
中配置不当的CMD
指令,还是来自以my-service
运行的实际Node/JS应用?
更新信息
应用@ErikMD建议的修改后,出现了最新的错误。
Creating postgres ... done
Creating myapp_my-service_1 ... error
ERROR: for myapp_my-service_1 Cannot start service my-service: OCI runtime create failed: container_linux.go:380: starting container process caused: exec: "./docker-deploy.sh": permission denied: unknown
ERROR: for my-service Cannot start service my-service: OCI runtime create failed: container_linux.go:380: starting container process caused: exec: "./docker-deploy.sh": permission denied: unknown
ERROR: Encountered errors while bringing up the project.
因此,它在启动数据库(postgres
)方面没有问题,但由于某些原因,在docker-deploy.sh
脚本方面仍然出现了与权限有关的问题。
node ./wait-for-it.sh
的东西,你能试着用ENTRYPOINT
而不是CMD
吗?
- derpirscher 2022-08-19
wait-for-it.sh
是否真的是一个可执行文件?如果不是,CMD ["./wait-for-it.sh", ...]
可能不会被正确地解释为CMD的"执行形式",而会被解释为"param from",因此,所有的参数都会传递给容器的默认ENTRYPOINT
,也就是node
可执行文件(这将符合观察到的行为)。
- derpirscher 2022-08-19
docker-deploy.sh
脚本并从ENTRYPOINT
中调用它,这似乎是一种常见的做法,但仍然有问题!我已经尝试了。
- hotmeatballsoup 2022-08-23
ENTRYPOINT
看起来很奇怪,请尝试ENTRYPOINT ["./docker-deploy.sh"]
。
- ErikMD 2022-08-23
正如@derpirscher的评论中所指出的,其中一个问题是你的脚本(s)的权限,以及它们应该作为ENTRYPOINT
(而不是CMD
)被调用的方式。
可以考虑在你的Dockerfile中使用这个替代代码。
FROM node:16
WORKDIR /usr/src/app
COPY package*.json ./
COPY wait-for-it.sh ./
COPY docker-deploy.sh ./
# Use a single RUN command to avoid creating multiple RUN layers
RUN chmod +x wait-for-it.sh \
&& chmod +x docker-deploy.sh \
&& npm install --legacy-peer-deps
COPY . .
RUN npm run build
ENTRYPOINT ["./docker-deploy.sh"]
docker-deploy.sh 脚本。
#!/bin/sh
# call wait-for-it with args and then start node if it succeeds
exec ./wait-for-it.sh -h "${DB_HOST}" -p "${DB_PORT}" -t 300 -s -- node start
请参阅此另一个SO问题,以了解更多关于Docker shell入口中需要exec
内建程序的背景。
另外,请注意,这个exec ...
命令行是在shell脚本中写的(而不是直接在ENTRYPOINT / CMD
exec形式中),这是使用参数扩展的一个关键要素。
换句话说:在你问题的修订版2中,"${DB_HOST}:${DB_PORT}"
参数被理解为字面意思,因为在ENTRYPOINT / CMD
exec形式中没有发生shell插值的情况。
关于docker-compose.yml .NET的问题。
# version: '3.7'
# In the Docker Compose specification, "version:" is now deprecated.
services:
my-service:
build: .
# Add "image:" for readability
image: some-optional-fresh-tag-name
# Pass environment values to the entrypoint
environment:
DB_HOST: postgres
DB_PORT: ${DB_PORT}
# etc.
# Add network spec to make it explicit what services can communicate together
networks:
- postgres-network
# Add "depends_on:" to improve "docker-run scheduling":
depends_on:
- postgres
postgres:
# container_name: postgres # unneeded
image: postgres:14.3
environment:
POSTGRES_PASSWORD: ${DB_PASSWORD}
POSTGRES_USER: ${DB_USER}
POSTGRES_DB: my-service-db
PG_DATA: /var/lib/postgresql2/data
volumes:
- pgdata:/var/lib/postgresql2/data
networks:
- postgres-network
# ports:
# - ${DB_PORT}:${DB_PORT}
# Rather remove this line in prod, which is a typical weakness, see (§)
networks:
postgres-network:
driver: bridge
volumes:
pgdata:
# let's be more explicit
driver: local
注意,在这个Docker设置中,wait-for-it
主机应该是postgres
(你的数据库的Docker服务名称),而不是0.0.0.0
或localhost
。因为wait-for-it
脚本作为一个客户端,试图连接到环境中docker-compose
网络的指定网络服务。
关于0.0.0.0
(一个服务器端的、包罗万象的特殊IP)和localhost
在Docker上下文中的区别的更多细节,请参见例如我的这个其他SO答案。
(§): 最后但并非最不重要的是,ports: [ "${DB_PORT}:${DB_PORT}" ]
行应该被删除,因为它们对于合成器服务的通信并不是必需的(服务只需要属于一个共同的合成器网络并使用其他合成器服务的主机名),而在主机上直接暴露一个这样的端口会增加攻击的表面。
最后但并非最不重要的:
为了跟进我的这个评论,建议在你的myapp/
目录下运行ls -l docker-deploy.sh; file docker-deploy.sh
作为调试步骤(BTW:以后随意做,然后评论,以记录在案)。
假设Docker中可能存在类似于这个的意外错误,正如@Lety所指出的那样。
我建议只需替换(在Docker文件中)这一行
RUN chmod +x wait-for-it.sh \
&& chmod +x docker-deploy.sh \
&& npm install --legacy-peer-deps
与
RUN npm install --legacy-peer-deps
和直接在主机上的终端中运行。
cd myapp/
chmod -v 755 docker-deploy.sh
chmod -v 755 wait-for-it.sh
docker-compose --env-file .env up --build
如果这不起作用,这里有另一个有用的信息,你可能想提供:你的操作系统是什么,你的Docker包名称是什么?(如docker-ce或podman......)。
/usr/bin/env
或bash shell用于容器内环境是不理智的。通常的期望是/bin/sh
的存在(对于linux容器,谁愿意使用其他东西,对吗?)参数扩展在Docker文件中也是可用的,在文件的层面上有构建参数(docker-compose确实发挥得很好),在构建过程中的容器环境也是如此。只是说说而已。
- hakre 2022-08-24
docker-compose --env-file .env up --build
,得到了新的错误,请看我上面的更新!看起来docker-deploy.sh
仍然得到与权限有关的错误。也许也有类似chmod 400
的情况?再次非常感谢!
- hotmeatballsoup 2022-08-24
sudo exec ...
来调用wait-for-it.sh
? 我想知道目前是哪个操作系统的用户在运行exec
?
- hotmeatballsoup 2022-08-24
/bin/sh
总是可用的),也是主观的(事实上我们应该总是避免bash
),的确,鉴于OP对基础图像有完全的控制,很容易检查bash
在node:16
中是否可用。然而,我同意使用/bin/bash
或/usr/bin/env bash
(通常推荐以最大限度地提高可移植性)是相当的,而且前者要简单得多......将相应地编辑我的答案。
- ErikMD 2022-08-24
RUN chmod +x docker-deploy.sh
命令(→然后我得到«docker: Error response from daemon: failed to create shim task:OCI runtime create failed: runc create failed: unable to start container process: exec: "./docker-deploy.sh": permission denied: unknown. »)。所以,你能仔细检查一下,你确实在你的Docker文件中运行了这个命令,而且你测试的是正确的镜像?(BTW,你的操作系统和Docker包的名字是什么?)
- ErikMD 2022-08-24
这有点像在你的电脑上使用的shell。你输入要执行的命令(只是命令的基本名称),如果找不到它,shell会告诉你--只不过它不会告诉你它不在$PATH
的范围内,因为它可能是(比较hash
实用)。
现在,Docker不是一个shell,因此信息要更啰嗦一些(而且docker-compose正在运行docker也会加在前面)。
ERROR: for my-service Cannot start service my-service: OCI runtime create failed: container_linux.go:380: starting container process caused: exec: "docker-deploy.sh": executable file not found in $PATH: unknown
因此,Docker的部分内容是。
OCI runtime create failed: container_linux.go:380: starting container process caused: exec: "docker-deploy.sh": executable file not found in $PATH: unknown
而这实际上是由于Docker文件中的戒律。
ENTRYPOINT ["docker-deploy.sh"]
无论docker-deploy.sh
在容器中的(绝对)路径是什么,它的基名(docker-deploy.sh
,再次)无法在容器环境PATH
参数中找到(比较PATH(在),Pathname Resolution,等等)。
使用可执行文件的基本名称,该文件实际上在容器内的PATH或绝对值(或相对于容器的PWD环境参数,又称工作目录),以便它实际上可以被执行(由Docker执行)。