繁体   English   中英

Docker 撰写:$PATH 中未找到可执行文件:未知

[英]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.0localhost 因为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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM