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?
2
Answers
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.
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.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.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 useARG
for ports (Composeports:
can remap them), user IDs (user:
), or filesystem paths (volumes:
).