简体   繁体   中英

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

I would like to build one image and run multiple containers against same image with containers running on different ports

I have following docker file

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"]

and docker compose file

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"

For brevity, I am not showing code for mock-server-2, 3 and so on. but it only differs by reference to port variable ${MOCK_SERVER_HOST_PORT_1}, ${MOCK_SERVER_HOST_PORT_2} and so on

.env file is

MOCK_SERVER_HOST_PORT_1=8003
MOCK_SERVER_HOST_PORT_2=8004

but on docker compose up I get following error

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

This indicates ${port} is not expanded when container is not run.

Any thoughts what might be wrong here?

So problem is in how Entrypoint works.

There are two modes exec and shell form ( How do I use Docker environment variable in ENTRYPOINT array? )

By default it runs in exec mode where there is no variable substitution

So to substitute variable one needs to run shell as Entrypoint and not "your" exe

So this is what I did

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

Another problem in that setup is the substitution of ${port} which is a ARG in dockerfile does not seem to work, One needs to set an ENV variable to fix this.

Something like this ENV SERVER_PORT=$port

It's easiest and perfectly safe to pick a single port number and hard-code it in the Dockerfile.

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

In your Compose setup the second ports: number must be the fixed container port 8000 but the first host port can be anything you'd like.

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

If you're connecting between containers, the Compose service name can be used as a host name, and you always use the fixed port; Compose ports: aren't considered or required. Each container internally has its own IP address and it's not a problem if you have multiple services that happen to listen on the same port.

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

In general you shouldn't use Dockerfile ARG for anything that you might need to change at deployment time, and especially for things where Docker has a way to remap the container resource to something else. So you probably shouldn't use ARG for ports (Compose ports: can remap them), user IDs ( user: ), or filesystem paths ( volumes: ).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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