I've made the following Dockerfile
:
FROM python:3.7
WORKDIR /app
# Install python dependencies
ADD requirements.txt /app/
RUN pip3 install --upgrade pip
RUN pip3 install -r requirements.txt
# Copy sources
ADD . /app
# Read arguments
ARG top_k=5
ARG threshold=0.5
ARG broker=broker.mqttdashboard.com
ARG port=8000
ARG topic=topic/truc
# Run detection
CMD python3 detect.py --top_k ${top_k} --threshold ${threshold} --broker ${broker} --port ${port} --topic ${topic}
The building works great but when I try to run the container, I got an error saying the arguments are missing:
usage: detect.py [-h] [--top_k TOP_K] [--threshold THRESHOLD]
[--broker BROKER] [--port PORT] [--topic TOPIC]
detect.py: error: argument --top_k: expected one argument
The python code is very basic:
parser = argparse.ArgumentParser()
parser.add_argument('--top_k', type=int, default=3, help='Number of categories with highest score to display')
args = parser.parse_args()
Is there something I don't understand with Docker ARG
?
My plan is to edit these arguments in the kubernetes
yaml file.
CodePudding user response:
ARG
doesn't make sense here. It's a way to pass in options when you build the image, but to change those options you'd need to rebuild it. In this case you're just trying to provide the options when you run the script.
One approach is to just pass these options as command-line options. Have a default CMD
that runs the script, but override that when you run the container.
# In the Dockerfile, no ARGs, and a default
CMD ./detect.py
docker run --rm ... my/image \
./detect.py --top_k 5
A variant here is to provide the command as ENTRYPOINT
and the options as CMD
.
ENTRYPOINT ["./detect.py"] # must be JSON-array form
# CMD ["--help"] # must be JSON-array form
docker run --rm ... my/image \
--top_k 5
In both cases, Kubernetes args:
specifies the "command" part after the image name in the docker run
command.
image: my/image
args:
- --top_k
- 5
It might be more manageable to update your application code to accept these options directly as environment variables
parser.add_argument('--top_k', type=int,
default=int(os.environ.get('TOP_K', '3')), # <-----
help='Number of categories with highest score to display')
Then in the Dockerfile you can specify these defaults as ENV
variables if you need to change them in a Docker context
ENV TOP_K=5
CMD ["./detect.py"] # with no additional arguments
But then it's straightforward to supply individual environment-value settings when you run the container.
docker run --rm ... \
-e TOP_K=20 \
my/image
image: my/image
env:
- name: TOP_K
value: '20' # must be a YAML string
The mechanical problem you're running into is that ARG
values are only inserted into the environment for RUN
commands and not the ENTRYPOINT
or CMD
. The syntax you show would likely work if you used ENV
instead of ARG
, or used both to make the option configurable at build time but then saved in the image as an environment variable, but it's going to be trickier to set up and maintain.
CodePudding user response:
Use ENV
instead of ARG
ARG
- uses in buildstep, ENV
- in runtime
CodePudding user response:
You can create the one shell script
#!/bin/sh
# --> I need $DATA to be set
if [ -z "$DATA" ]; then
echo "Please set a DATA environment variable" >&2
exit 1
fi
echo "You are running $DATA version of your app"
exec "$@"
run docker : docker run --rm -e DATA=some_data docker_image_name /bin/true
You can specify the default data in Dockerfile
FROM centos:7.4.1708
COPY ./run.sh /usr/local/bin
RUN chmod a x /usr/local/bin/run.sh
ENV DATA=default_data"
ENTRYPOINT ["run.sh"]
Kubernetes config
image: image/docker
env:
- name: DATA
value: '20'
Option : 2 : Command line argument
Shell script: run.sh
#!/bin/sh
# --> pass a data, thn command, as parameters
DATA="$1"
if [ -z "$DATA" ]; then
echo "Please pass DATA as a command-line" >&2
exit 1
fi
echo "Details of data $DATA"
shift
export DATA #This will set argument as environment
exec "$@"
run docker
docker run --rm docker_image_name **some_data** /bin/true
In option 2, you are setting argument as the environment var.
Use environment variable instead of argument if possible.