Home > front end >  Dockerfile ARG to run python script
Dockerfile ARG to run python script

Time:09-30

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.

  • Related