如何从 docker-compose 传递端口号并在 Entrypoint 中使用它?

How to pass Port number from docker-compose and use it in Entrypoint?

我想针对同一个镜像构建一个镜像和 运行 多个容器,容器 运行 在不同的端口上连接

我有以下 docker 文件

FROM python:3.9
ARG port
RUN mkdir /code
RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt
COPY ./mock_s /code/mock_s
ENTRYPOINT ["uvicorn", "mock_s.main:app", "--port", "$port"]

和docker组成文件

version: "3"
services:
  mock-server-1:
    container_name: mock-s1
    build: 
      context: .
      args:
        port: ${MOCK_SERVER_HOST_PORT_1}
      ports:
        - "${MOCK_SERVER_HOST_PORT_1}:8003"

为简洁起见,我没有显示 mock-server-2、3 等的代码。但它仅在引用端口变量 ${MOCK_SERVER_HOST_PORT_1}、${MOCK_SERVER_HOST_PORT_2} 等时有所不同

.env 文件是

MOCK_SERVER_HOST_PORT_1=8003
MOCK_SERVER_HOST_PORT_2=8004

但是在 docker compose up 我得到以下错误

Error: Invalid value for '--port': '${port}' is not a valid integer.

这表示当容器不是 运行 时 ${port} 不会扩展。

想知道这里可能有什么问题吗?

所以问题在于 Entrypoint 的工作方式。

有两种模式exec和shell形式()

默认情况下它运行处于没​​有变量替换的执行模式

所以要替换变量需要 运行 shell 作为入口点而不是“你的”exe

这就是我所做的

ENTRYPOINT ["sh", "-c","uvicorn mock_sfapp.main:app --port ${SERVER_PORT}"]

该设置中的另一个问题是 ${port} 的替换,它是 dockerfile 中的 ARG 似乎不起作用, 需要设置一个 ENV 变量来解决这个问题。

像这样ENV SERVER_PORT=$port

选择一个端口号并将其硬编码在 Docker 文件中是最简单和绝对安全的。

# do not pass an ARG port
EXPOSE 8000  # optional but considered good practice
CMD ["uvicorn", "mock_s.main:app", "--port", "8000"]

在您的 Compose 设置中,第二个 ports: 数字必须是固定的容器端口 8000,但第一个主机端口可以是任何您想要的。

version: "3.8"
services:
  mock-server-1:
    build: .
    ports:
      - "${MOCK_SERVER_HOST_PORT_1}:8000" # 2nd number matches fixed number in image

如果你在容器之间连接,Compose 服务名可以用作主机名,你总是使用固定的端口;不考虑或不需要撰写 ports:。每个容器在内部都有自己的 IP 地址,如果您有多个服务恰好在同一端口上侦听,这不是问题。

version: '3.8'
services:
  mock-server-1:
    build: ./server1
    ports: ['8001:8000']  # listens on port 8000 internally
  mock-server-2:
    build: ./server2
    ports: ['8002:8000']  # also listens on port 8000 internally
    environment:
      - SERVER_1_URL=http://mock-server-1:8000

一般来说,您不应该将 Dockerfile ARG 用于您可能需要在部署时更改的任何内容,尤其是对于 Docker 可以重新映射的内容容器资源到别的东西。因此,您可能不应该将 ARG 用于端口(Compose ports: 可以重新映射它们)、用户 ID (user:) 或文件系统路径 (volumes:)。