Передача аргументов командной строки в сцепленный python ENTRYPOINT в Dockerfile - PullRequest
0 голосов
/ 13 октября 2018

У меня есть Dockerfile на основе FROM continuumio/miniconda3 с ENTRYPOINT, который объединяет команды source activate <env> && python my_script.py, например:

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

Я пытаюсь передать аргументы командной строки в my_script, используя docker runследующим образом:

docker run -it my_image "foo" "bar"

Но они не передаются в сценарий.Есть идеи, как мне это сделать?Обратите внимание, что если я изменю точку входа на ENTRYPOINT [ "/bin/bash", "-c", "source activate env && python my_script.py foo bar" ], это работает!Но это не то, что я хочу: входные данные foo и bar могут различаться для разных экземпляров контейнера.

Я также попытался поместить команды активации исходного кода env и python в отдельный скрипт оболочки, а затем попытался:

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

(где сценарий оболочки вызывает source activate env and python my_script.py $1 $2 в последовательности)

Но это говорит мне, что /opt/conda/envs/env не является средой conda!

Есть идеи?

Ответы [ 2 ]

0 голосов
/ 13 октября 2018

Чистый ответ: Контейнеры 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 script, он может генерировать сценарии оболочки , которые будут запускать какой-то конкретный модуль 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 '...' в сценарий оболочки.(Вы намекаете на это в своем вопросе.) Пока скрипт является исполняемым и содержит соответствующую строку #!/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"]
0 голосов
/ 13 октября 2018

Мне потребовалось некоторое время, чтобы выяснить, что не так.

Прежде всего, вы были правы, предполагая, что что-либо после docker run <image> будет добавлено к команде ENTRYPOINT.

Однако проблема на самом деле связана с /bin/bash -c.Предполагается, что команда, которую мы хотим запустить, находится в форме строки сразу после опции.Однако это означает, что параметры / аргументы также должны быть в строке.

Так, например, /bin/bash -c ls -l не будет ls в режиме списка.

Но /bin/bash -c "ls -l" будет.

Но так как ваш аргумент будет добавлен в конце команды, он не пройдёт.Итак, для этого попробуйте сделать это, /bin/bash -c 'ls $0' -l.см. этот ответ для более подробной информации.

Итак, чтобы передать аргумент, я сделал эти файлы.(просто чтобы убедиться, что я был прав)

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

...