将命令行参数传递给Dockerfile中的串联python ENTRYPOINT

时间:2018-10-13 02:41:17

标签: python docker dockerfile conda

我有一个基于FROM continuumio/miniconda3的Dockerfile,其中有一个ENTRYPOINT连接了source activate <env> && python my_script.py命令,如下所示:

ENTRYPOINT [ "/bin/bash", "-c", "source activate env && python my_script.py" ]

我正尝试使用docker run将命令行参数传递给my_script,如下所示:

docker run -it my_image "foo" "bar"

但是这些没有传递给脚本。有什么想法我可以做到这一点吗?请注意,如果我将入口点更改为ENTRYPOINT [ "/bin/bash", "-c", "source activate env && python my_script.py foo bar" ],则可以使用!但这不是我想要的:对于不同的容器实例,输入foo和bar可以不同。

我还尝试将源代码激活env和python命令放在单独的shell脚本中,然后尝试:

ENTRYPOINT [ "/bin/bash", "-c", "my_shell_script.sh" ]

(shell脚本按顺序调用source activate env and python my_script.py $1 $2

但这告诉我/opt/conda/envs/env不是conda环境!

有什么想法吗?

2 个答案:

答案 0 :(得分:0)

我花了一些时间才找出问题所在。

首先,您正确地假设docker run <image>之后的任何内容都将附加到ENTRYPOINT命令。

但是,问题实际上出在/bin/bash -c上。假定我们希望运行的命令在选项后紧跟着是字符串形式。但是,这意味着选项/参数也必须在字符串中。

例如 /bin/bash -c ls -l不会处于列表模式。

但是/bin/bash -c "ls -l"

但是由于您的参数将附加在命令的最后,因此不会通过。因此,为此尝试 /bin/bash -c 'ls $0' -l。有关更多详细信息,请参见此answer

因此,基本上来说,我传递了一个文件。 (只是为了确保我是对的)

script

#!/bin/bash

echo $VARIABLE $1

env

#!/bin/bash

export VARIABLE="Hello"

dockerfile

FROM ubuntu:16.04

COPY script .
COPY env .
ENTRYPOINT ["/bin/bash","-c","source ./env && ./script $0"]

在使用docker build test .命令后,我运行了docker run test world 我得到了Hello world

答案 1 :(得分:0)

一个纯粹的答案: Docker容器已经提供了一个单独的隔离文件系统空间,该空间具有自己的空间来安装Python库,与系统Python和其他容器分开;您无需在Docker映像内安装虚拟环境。如果您只是跳过与虚拟环境有关的所有内容并确保您的脚本是可执行的,则可以直接以ENTRYPOINT身份运行该脚本,并且它将看到“命令”为sys.argv

FROM python:3
WORKDIR /app
COPY requirements.txt ./
RUN pip install -r requirements.txt # as "system" packages
COPY . ./
RUN chmod +x my_script.py
ENTRYPOINT ["/app/my_script.py"]

您需要确保Python脚本的第一行包含“ shebang”行,以便系统知道它是Python:

#!/usr/bin/env python3
import ...
def main(): ...
if __name__ == '__main__':
    main()

全Python答案:如果您编写了setup.py脚本,它可以generate wrapper scripts来启动某些特定的Python模块。即使将其安装在虚拟环境中,也可以在不激活虚拟环境的情况下直接运行脚本,它将起作用。

所以您的setup.py可能会说:

from setuptools import setup
setup(
    ...
    entry_points={
        'console_scripts': [
            'my_script = my_module.my_script:main'
        ]
    }
)

然后您的Dockerfile可以说

FROM python:3
WORKDIR /app
COPY . ./
RUN python -m venv env
RUN ./env/bin/pip install .
ENTRYPOINT ["/app/env/bin/my_script"]

一个最小的答案:您可以将sh -c '...'调用中的扩展设置移入Shell脚本。 (您会在问题中暗示这一点。)只要脚本是可执行的,并且一开始就包含适当的#!/path/to/interpreter行,您就可以直接运行它,并且它将适当地理解命令行参数。这样该脚本可以少到

#!/bin/sh

# activate the virtual environment
# "." is POSIX standard and equivalent to bash-specific "source"
. env/bin/activate

# run the actual script, passing our command-line arguments on to it
exec python my_script.py "$@"

然后您的Dockerfile看起来像

...
COPY entrypoint.sh ./
RUN chmod +x entrypoint.sh
ENTRYPOINT ["/app/entrypoint.sh"]