Я просто тестирую 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, чтобы она клонировала репо в нужном каталоге? Я пропустил что-то основное здесь?
Когда вы создаете свой образ, выполняется шаг RUN, и когда вы запускаете свой контейнер с помощью docker run, команда RUN больше не выполняется повторно. Вот как работает докер, вы создаете образ, а затем запускаете контейнер с этим образом.
То есть вы имеете в виду, что это невозможно сделать во время выполнения? Образ должен быть построен с параметрами конечного времени принудительно? Если это так, я не вижу причины, по которой опция -e существует на docker container run...
Параметр -e для docker container run необходим, когда вы хотите передать переменные среды в контейнер, который должен быть запущен. Например, у вас есть приложение с файлом свойств, и вы хотите переопределить эти свойства при запуске контейнера.
Ясно, тогда, возможно, создание ENTRYPOINT, которое выполняется при каждом запуске, могло бы решить проблему, перенос последней команды RUN в ENTRYPOINT
Обычно при создании образа следует использовать команду RUN для установки необходимых зависимостей. Когда вы хотите изменить эти зависимости, вы обычно создаете новый образ с другими зависимостями и присваиваете ему другой тег. Итак, у вас установлено 2 образа с разными зависимостями. И вы можете запускать контейнеры на основе этих двух разных образов.
По нескольким причинам, вероятно, лучше git clone за пределами Dockerfile. Также обратите внимание на ARG для настройки времени сборки, которая может быть способом создания образа, включающего определенную версию пакета. (И настройте свой CMD для фактического запуска вашего приложения, и, вероятно, будет проще не использовать виртуальную среду.)


Когда вы выполняете 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 контента.
Привет, я столкнулся с похожей проблемой, но это было с Kubernetes, но я думаю, что применима та же концепция, я использовал переменную ENV в своем коде, которая была установлена как часть одного из контейнеров, однако, если бы я был изменяя переменную ENV снова, они не отражались в коде, но были видны как часть контейнера, так же, как вы видите его в
docker exec, я думаю, вам нужно будет создать изображение с переменной ENV, которую вы хотите, чтобы они применяться