[英]Docker Compose: 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
脚本仍然会出现与权限相关的问题。
正如@derpirscher和我的评论所指出的那样,问题之一是您的脚本的许可以及它们应该被称为CMD
ENTRYPOINT
。
考虑为您的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
有关在 Docker shell 入口点中需要内置exec
的更多上下文,请参阅此其他 SO 问题。
另外,请注意,这个exec...
命令行是写在 shell 脚本中的事实(不是直接在ENTRYPOINT / CMD
exec 形式中)是使用参数扩展的关键因素。
换句话说:在您的问题的修订版 2 中, "${DB_HOST}:${DB_PORT}"
参数被理解为字面意思,因为在ENTRYPOINT / CMD
执行形式中没有发生 shell 插值。
关于docker-compose.yml :
# 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
网络中的指定 web 服务。
有关 Docker 上下文中0.0.0.0
(服务器端,包罗万象的特殊 IP)和localhost
之间差异的更多详细信息,请参见我的其他 SO 答案。
(§) :最后但同样重要的是, ports: [ "${DB_PORT}:${DB_PORT}" ]
行应该被删除,因为 Compose 服务不需要通信(它们只需要属于一个公共组合网络并使用 Compose 服务主机名),而直接在主机上公开一个这样的端口会增加攻击面。
这有点像您计算机上的 shell :您输入要执行的命令(只是命令的基本名称),shell 会告诉您它是否找不到它 - 除非它不会告诉您它没有$PATH
可能是(比较hash
实用程序)。
Now Docker ain't a shell and therefore the message is a bit more verbose (and that docker-compose is running docker is also adding in front of it):
错误:对于我的服务无法启动服务我的服务:OCI 运行时创建失败:container_linux.go:380:启动容器进程导致:exec:“docker-deploy.sh”:在 $PATH 中找不到可执行文件:未知
所以 Docker 的部分是:
OCI 运行时创建失败:container_linux.go:380:启动容器进程导致:exec:“docker-deploy.sh”:在 $PATH 中找不到可执行文件:未知
这实际上是由于 Dockerfile 中的诫命:
ENTRYPOINT ["docker-deploy.sh"]
无论docker-deploy.sh
的(绝对)路径在容器中,它的基本名称( docker-deploy.sh
,再次)都无法在容器环境PATH
参数中找到(比较PATH (in) , Pathname Resolution , ETC。)。
使用容器内实际位于PATH中的可执行文件的基本名称或绝对名称(或相对于容器PWD环境参数又名工作目录),以便它实际上可以执行(由 Docker 执行)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.