Параметр env не применяется в контейнере

Я просто тестирую Docker, так что это может быть довольно простой вопрос, но я не могу понять, почему он не делает то, что я ожидаю.

Я создал довольно простой Dockerfile для тестирования, просто для создания простого образа, который устанавливает некоторые пакеты, клонирует репозиторий git и создает его требования:

FROM ubuntu:18.04

ENV PYTHONEXEC=python3 \
    PIPEXEC=pip \
    VIRTUALENVEXEC=virtualenv \
    GITREPO=https://github.com/test/test.git \
    REPODIR=test

RUN apt-get update && apt-get install -y git \
    python3 \
    python3-dev \
    python3-virtualenv \
    python-virtualenv \
    qt5-default \
    libcurl4-openssl-dev \
    libxml2 \
    libxml2-dev \
    libxslt1-dev \
    libssl-dev \
    virt-viewer

RUN mkdir -p /app

WORKDIR /app

RUN git clone $GITREPO $REPODIR \
    && $VIRTUALENVEXEC -p $PYTHONEXEC venv \
    && . venv/bin/activate \
    && cd $REPODIR \
    && $PIPEXEC install -r requirements.txt

CMD ["sleep", "1000000"]

Затем я создаю изображение с помощью:

docker build -t gitapp:latest .

Это работает до сих пор. Однако, если я укажу параметр -e в команде docker container run, похоже, он не заменит его в последней команде RUN.

Поэтому, если я запускаю docker container run -d -e "REPODIR=blah" gitapp, я ожидаю, что он будет клонирован в /app/blah, но он все еще клонирован в каталоге /app/test.

Когда я запускаю docker container exec -it -e "REPODIR=blah" <container-id> env, я получаю:

PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOSTNAME=2f6ba38341d6
TERM=xterm
REPODIR=blah
PYTHONEXEC=python3
PIPEXEC=pip
VIRTUALENVEXEC=virtualenv
GITREPO=https://github.com/test/test.git
HOME=/root

Таким образом, кажется, что переменная действительно передается в контейнер. Тогда почему он не передается последней команде RUN, чтобы она клонировала репо в нужном каталоге? Я пропустил что-то основное здесь?

Привет, я столкнулся с похожей проблемой, но это было с Kubernetes, но я думаю, что применима та же концепция, я использовал переменную ENV в своем коде, которая была установлена ​​как часть одного из контейнеров, однако, если бы я был изменяя переменную ENV снова, они не отражались в коде, но были видны как часть контейнера, так же, как вы видите его в docker exec, я думаю, вам нужно будет создать изображение с переменной ENV, которую вы хотите, чтобы они применяться

opensource-developer 15.07.2019 12:00

Когда вы создаете свой образ, выполняется шаг RUN, и когда вы запускаете свой контейнер с помощью docker run, команда RUN больше не выполняется повторно. Вот как работает докер, вы создаете образ, а затем запускаете контейнер с этим образом.

Michał Krzywański 15.07.2019 12:02

То есть вы имеете в виду, что это невозможно сделать во время выполнения? Образ должен быть построен с параметрами конечного времени принудительно? Если это так, я не вижу причины, по которой опция -e существует на docker container run...

nKn 15.07.2019 12:04

Параметр -e для docker container run необходим, когда вы хотите передать переменные среды в контейнер, который должен быть запущен. Например, у вас есть приложение с файлом свойств, и вы хотите переопределить эти свойства при запуске контейнера.

Michał Krzywański 15.07.2019 12:06

Ясно, тогда, возможно, создание ENTRYPOINT, которое выполняется при каждом запуске, могло бы решить проблему, перенос последней команды RUN в ENTRYPOINT

nKn 15.07.2019 12:08

Обычно при создании образа следует использовать команду RUN для установки необходимых зависимостей. Когда вы хотите изменить эти зависимости, вы обычно создаете новый образ с другими зависимостями и присваиваете ему другой тег. Итак, у вас установлено 2 образа с разными зависимостями. И вы можете запускать контейнеры на основе этих двух разных образов.

Michał Krzywański 15.07.2019 12:10

По нескольким причинам, вероятно, лучше git clone за пределами Dockerfile. Также обратите внимание на ARG для настройки времени сборки, которая может быть способом создания образа, включающего определенную версию пакета. (И настройте свой CMD для фактического запуска вашего приложения, и, вероятно, будет проще не использовать виртуальную среду.)

David Maze 15.07.2019 12:14
Развертывание модели машинного обучения с помощью Flask - Angular в Kubernetes
Развертывание модели машинного обучения с помощью Flask - Angular в Kubernetes
Kubernetes - это портативная, расширяемая платформа с открытым исходным кодом для управления контейнерными рабочими нагрузками и сервисами, которая...
Как создать PHP Image с нуля
Как создать PHP Image с нуля
Сегодня мы создадим PHP Image from Scratch для того, чтобы легко развернуть базовые PHP-приложения. Пожалуйста, имейте в виду, что это разработка для...
1
7
43
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Когда вы выполняете docker run, вы указываете контейнеру выполнить команду Dockerfile CMD или ENTRYPOINT. Команды Dockerfile, находящиеся выше точки входа, уже были выполнены во время сборки и не выполняются снова во время выполнения.

Именно по этой причине ваш репозиторий github клонируется в каталог, изначально определенный в Dockerfile, а не в тот, который передается при команде запуска с флагом -e.

Обходным путем может быть изменение точки входа вашего изображения. Вы можете передать эту часть

RUN git clone $GITREPO $REPODIR \
    && $VIRTUALENVEXEC -p $PYTHONEXEC venv \
    && . venv/bin/activate \
    && cd $REPODIR \
    && $PIPEXEC install -r requirements.txt

в файл сценария bash (назовем его my.script.sh), который будет выполняться как точка входа изображения. Скопируйте этот файл во время процесса сборки в нужное место, убедившись, что он имеет исполняемый флаг, и соответствующим образом отредактируйте точку входа Dockerfile:

CMD ["/path_to_script/myscript.sh" ]

Это, однако, имеет оговорку, что скрипт будет выполняться каждый раз при запуске контейнера в отличие от ваших текущих настроек, что может привести к задержке в зависимости от myscript.sh контента.

Другие вопросы по теме