Docker Compose:在 $PATH 中找不到可执行文件:未知

hot*_*oup 9 node.js docker dockerfile docker-compose

我的项目目录结构:

myapp/
    src/
    Dockerfile
    docker-compose.yml
    docker-deploy.sh
    wait-for-it.sh
    .env
Run Code Online (Sandbox Code Playgroud)

wait-for-it.sh著名的等待脚本的副本在哪里?

我的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"]
Run Code Online (Sandbox Code Playgroud)

并且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
Run Code Online (Sandbox Code Playgroud)

和我的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:
Run Code Online (Sandbox Code Playgroud)

我的样子.env

DB_PASSWORD=1234
DB_USER=root
DB_PORT=5432
Run Code Online (Sandbox Code Playgroud)

当我从项目根目录运行以下命令行时:

docker-compose --env-file .env up --build
Run Code Online (Sandbox Code Playgroud)

我得到:

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.
Run Code Online (Sandbox Code Playgroud)

到底是怎么回事?错误是来自脚本本身、来自 中wait-for-it.sh配置不当的指令,还是来自实际运行的 Node/JS 应用程序?CMDDockerfilemy-service

更新

应用@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.
Run Code Online (Sandbox Code Playgroud)

因此,它正在旋转数据库(postgres)没有问题,但由于某种原因,脚本仍然存在与权限相关的问题docker-deploy.sh

Eri*_*kMD 6

正如@derpirscher的评论和我的评论中所指出的,问题之一是脚本的许可以及它们应该被称为ENTRYPOINT(not CMD) 的方式。

\n

考虑您的Dockerfile的替代代码:

\n
FROM node:16\n\nWORKDIR /usr/src/app\n\nCOPY package*.json ./\nCOPY wait-for-it.sh ./\nCOPY docker-deploy.sh ./\n\n# Use a single RUN command to avoid creating multiple RUN layers\nRUN chmod +x wait-for-it.sh \\\n  && chmod +x docker-deploy.sh \\\n  && npm install --legacy-peer-deps\n\nCOPY . .\n\nRUN npm run build\n\nENTRYPOINT ["./docker-deploy.sh"]\n
Run Code Online (Sandbox Code Playgroud)\n

docker-deploy.sh脚本:

\n
FROM node:16\n\nWORKDIR /usr/src/app\n\nCOPY package*.json ./\nCOPY wait-for-it.sh ./\nCOPY docker-deploy.sh ./\n\n# Use a single RUN command to avoid creating multiple RUN layers\nRUN chmod +x wait-for-it.sh \\\n  && chmod +x docker-deploy.sh \\\n  && npm install --legacy-peer-deps\n\nCOPY . .\n\nRUN npm run build\n\nENTRYPOINT ["./docker-deploy.sh"]\n
Run Code Online (Sandbox Code Playgroud)\n

有关Docker shell 入口点中内置的需求的更多背景信息,请参阅另一个 SO 问题。exec

\n

另请注意,该exec ...命令行是在 shell 脚本内编写的(而不是直接以ENTRYPOINT / CMDexec 形式),这是使用参数扩展的关键因素。
\n换句话说:在问题的修订版 2中,该"${DB_HOST}:${DB_PORT}"参数是按字面意思理解的,因为ENTRYPOINT / CMDexec 形式中没有发生 shell 插值。

\n

关于docker-compose.yml

\n
#!/bin/sh\n\n# call wait-for-it with args and then start node if it succeeds\nexec ./wait-for-it.sh -h "${DB_HOST}" -p "${DB_PORT}" -t 300 -s -- node start\n
Run Code Online (Sandbox Code Playgroud)\n

请注意,在此 Docker 设置中,wait-for-it主机应该是postgres(数据库的 Docker 服务名称),而不是0.0.0.0nor localhost。因为该wait-for-it脚本充当客户端,尝试连接到环境docker-compose网络中的指定 Web 服务。

\n

0.0.0.0有关(服务器端、包罗万象的特殊 IP)和localhostDocker 上下文之间差异的更多详细信息,请参阅我的另一个 SO 答案

\n

(\xc2\xa7):最后但并非最不重要的一点是,ports: [ "${DB_PORT}:${DB_PORT}" ]应该删除这些行,因为 Compose 服务不需要它们进行通信(这些服务只需要属于一个公共 Compose 网络并使用其他 Compose 服务的主机名),同时直接在主机上暴露一个这样的端口会增加攻击面。

\n

最后但并非最不重要的:

\n

为了跟进我的评论ls -l docker-deploy.sh; file docker-deploy.sh,建议在您的目录中运行myapp/作为调试步骤(顺便说一句:稍后可以随意执行此操作,然后评论记录):

\n

假设 Docker 中可能存在与@Lety指出的类似的意外错误:

\n

我建议只替换(在 Dockerfile 中)该行

\n
# version: \'3.7\'\n# In the Docker Compose specification, "version:" is now deprecated.\n\nservices:\n  my-service:\n    build: .\n    # Add "image:" for readability\n    image: some-optional-fresh-tag-name\n    # Pass environment values to the entrypoint\n    environment:\n      DB_HOST: postgres\n      DB_PORT: ${DB_PORT}\n      # etc.\n    # Add network spec to make it explicit what services can communicate together\n    networks:\n      - postgres-network\n    # Add "depends_on:" to improve "docker-run scheduling":\n    depends_on:\n      - postgres\n\n  postgres:\n    # container_name: postgres # unneeded\n    image: postgres:14.3\n    environment:\n      POSTGRES_PASSWORD: ${DB_PASSWORD}\n      POSTGRES_USER: ${DB_USER}\n      POSTGRES_DB: my-service-db\n      PG_DATA: /var/lib/postgresql2/data\n    volumes:\n      - pgdata:/var/lib/postgresql2/data\n    networks:\n      - postgres-network\n    # ports:\n    #   - ${DB_PORT}:${DB_PORT}\n    # Rather remove this line in prod, which is a typical weakness, see (\xc2\xa7)\n\nnetworks:\n  postgres-network:\n    driver: bridge\n\nvolumes:\n  pgdata:\n    # let\'s be more explicit\n    driver: local\n
Run Code Online (Sandbox Code Playgroud)\n

\n
RUN chmod +x wait-for-it.sh \\\n  && chmod +x docker-deploy.sh \\\n  && npm install --legacy-peer-deps\n
Run Code Online (Sandbox Code Playgroud)\n

直接在主机上的终端中运行:

\n
RUN npm install --legacy-peer-deps\n
Run Code Online (Sandbox Code Playgroud)\n

如果这不起作用,您可能需要提供另一个有用的信息:您的操作系统是什么,您的 Docker 包名称是什么?(例如 docker-ce 或 podman\xe2\x80\xa6)

\n