在Docker容器中将参数传递给Python argparse

58

我正准备尝试使用docker容器,我的python脚本调用了一些API并解析一个文件。脚本需要传递API服务器的URL、API密钥和要解析的文件路径参数,我使用argparse在脚本中处理这些参数。

我该如何将这些参数传递到Docker中?我不想将任何内容硬编码到Dockerfile中,因为我希望将此脚本交给需要定期运行并根据结果采取行动的工程师。谢谢您的帮助。我一直在搜索,但似乎建议是将这些东西硬编码到Dockerfile中-我希望用户能够在运行时输入这些参数。或者我已经找到答案,只是没有理解......

如果我的术语不正确,请谅解-这是我第一次尝试使用Docker。

4个回答

76

您如何操作取决于您使用docker的方式。如果您想在已经运行的容器中运行脚本,则可以使用exec:

docker exec <yourContainerName> python <yourScript> <args>

或者,如果你有一个Docker镜像,其中你的脚本是ENTRYPOINT,则传递给docker run命令的任何参数都将添加到entrypoint。

因此,如果您的Docker文件看起来像这样:

FROM yourbase
....
ENTRYPOINT <yourScript>

然后您可以通过运行容器本身来运行脚本:

docker run --rm <yourImageName> <args>
根据您下面的评论,看起来您想要这个选项。您应该更改您的Dockerfile以指定。
ENTRYPOINT ["python","./script.py"]

(使用CMD的替代方法)然后您可以通过以下方式运行:

docker run --rm <yourImageName>  -a API_KEY - f FILENAME -o ORG_ID

1
所以我的Python脚本是容器的原因。我在Dockerfile中只有:"CMD ["python","./script.py"]",但我想传递"-a API_KEY -f FILENAME -o ORG_ID"。 - Bring Coffee Bring Beer
6
需要提醒的是,在传递参数到Python时,您需要使用执行形式的 ENTRYPOINT ["python","./script.py"],而不是 shell 形式的 ENTRYPOINT python ./script.py。请注意不要改变原文意思,同时尽量使翻译更加通俗易懂。 - naeschdy
@naeschdy 是的,那正是困扰我的问题。你是正确的。 - jasper
我真的很喜欢EntryPoint,你可以构建它,就像在本地使用程序一样,只需在CLI中添加“docker run <imageName>”而不是“python <app_name>.py”。 - pelos

37

那么假设您的命令如下

python app.py "URL" "APIKEY" "filepath"
所以您需要按照以下方式放置Dockerfile
FROM python:3.6
WORKDIR /app
COPY app.py .
ENTRYPOINT ["python", "app.py"]

然后运行Docker容器的人将按照以下方式执行:

docker run -v /home/tarun/project/filetoparse.yaml:/config.yaml <yourimagename> "URL" "APIKEY" /config.yaml

如果你想要更多的灵活性,甚至可以使用环境变量。

docker run -v /home/tarun/project/filetoparse.yaml:/config.yaml -e APIKEY="XYZ" <dockerimage> "URL" /config.yaml

然后在你的脚本中,你可以使用 os.environ['APIKEY'] 来读取它。


我收到一个错误信息,说是未识别的参数。这是因为Docker版本的差异吗? - Memphis Meng

22

这个答案有点晚了,但是对于未来的读者,我想把它更多地关注于问题本身,即关于argparse的问题。基本思想就像@Chris指出的那样。实现解决方案的一种方法是在docker run命令中将参数传递给image。然后这些参数将被传递到您的ENTRYPOINT,从而传递到Python脚本。

文件通常看起来像这样...

file.py

import argparse
parser = argparse.ArgumentParser(description='Process some integers.')
parser.add_argument('pos', type=str, help='Example Positional Argument') # will be accesible under args.POS
parser.add_argument('--opt', type=str , help='Example Optional Argument') # will be accesible with args.OPT

args = parser.parse_args()

# do something with pos and OPT

没有Docker,您需要将此文件(假设它在pwd中)作为python file.py --opt opt_val pos_val运行。

Dockerfile

FROM python:<your_tag>
COPY ./file.py ./ # Assuming your Dockerfile and file.py are in the same directory

# some custom build steps

ENTRYPOINT ["python","./file.py"]

Docker构建和运行命令

使用以下命令进行构建:docker build --tag example:0.0.1 <dir>

下面展示多行运行命令(为了更好的可读性),

Docker运行

docker run --rm \
   --name example.container \
   example:0.0.1 \
   --opt=opt_val \
   POS=pos_value

Docker运行(PowerShell)

docker run --rm `
   --name example.container `
   example:0.0.1 `
   --opt=opt_val `
   POS=pos_value

以下是需要记住的一些要点:

  • Argparse支持添加位置参数和可选参数,并应相应地传递给docker run命令中的image
  • 上述解决方案可行,但不太灵活。最好使用环境变量,并在脚本内部使用os.environ()进行访问。
  • 使用此解决方案时,您不需要在Dockerfile中“硬编码”任何内容。

16
在 Dockerfile 中,我使用 CMD 命令,用法如下:CMD
FROM python:3
COPY ./app /app
WORKDIR /app
RUN pip install --upgrade pip
RUN pip install --no-cache-dir -r req.pip
CMD ["python","start.py","(api-url) ","(api-key)","(file-path)"]

注意: 对于每个参数,在其之间用逗号分隔。

如果您正在使用标志,则需要对其进行拆分。

CMD ["python","start.py","-u","(api-url) ","-k","(api-key)","-f","(file-path)"]

我认为这个问题是在寻找一种灵活的解决方案,以便在运行docker时可以灵活地传递参数,而不是在Dockerfile中硬编码它们。 - Memphis Meng

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接