簡體   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