Что происходит за кулисами, когда переменные env `-e` передаются в контейнер докеров?

В качестве эксперимента я устанавливаю переменные среды в своем контейнере Docker двумя способами: используя параметр -e и используя файл environment, смонтированный в /etc/environment внутри контейнера. В файле есть одна строка:

FROM_ENV_FILE=true

Моя команда docker run:

docker run -de FROM_CMD_LINE=true -v $(pwd)/environment:/etc/environment ubuntu:14.04 sleep infinity

Когда я запускаю docker exec b20543b507e3 cat /etc/environment, я вижу, что этот файл смонтирован правильно и содержит мое значение, однако я вижу только установленное FROM_CMD_LINE при запуске printenv, поэтому кажется, что мой файл /etc/environment игнорируется.

Мой вопрос заключается не только в том, почему /etc/environment не работает в моем образе докера ubuntu:14.04?. Я ищу ответ, который объясняет, что Docker делает для настройки среды процесса, чтобы сделать доступными пользовательские переменные среды, переданные через -e, для всех запущенных процессов в контейнере, поэтому я надеюсь понять, почему /etc/environment игнорируется в контейнер.

Соответствующие сведения о времени выполнения, с которыми я работаю, вставлены ниже.

docker version

Client:
 Version:      18.03.1-ce
 API version:  1.37
 Go version:   go1.9.5
 Git commit:   9ee9f40
 Built:        Thu Apr 26 07:13:02 2018
 OS/Arch:      darwin/amd64
 Experimental: false
 Orchestrator: swarm

Server:
 Engine:
  Version:      18.03.1-ce
  API version:  1.37 (minimum version 1.12)
  Go version:   go1.9.5
  Git commit:   9ee9f40
  Built:        Thu Apr 26 07:22:38 2018
  OS/Arch:      linux/amd64
  Experimental: true

Глядя на примечания к выпуску для 18.03.1-ce :

Containerd: обновление до версии 1.0.3 moby/moby#36749

Сейчас я копаюсь в исходном коде containerd, но я надеялся, что кто-то, уже знакомый со средой выполнения контейнера, сможет мне помочь.


person erstaples    schedule 09.07.2018    source источник


Ответы (1)


Когда какой-либо процесс запускается в Linux (используя системные вызовы fork/execve), его окружение явно указывается путем передачи массива переменных в метод execve. Когда Docker запускает контейнер (то есть порождает корневой процесс контейнера), он агрегирует все переменные, переданные с использованием аргумента -e, и добавляет их в список переменных среды, которые должны быть установлены для основного процесса контейнера.

Однако Docker ничего не знает о /etc/environment, который принадлежит контейнеру и является внутренним для его файловой системы, независимо от того, смонтирован он извне или нет. Этот файл принадлежит системе Linux PAM (которая отвечает за аутентификацию) и используется, когда кто-то входит в систему, чтобы установить общие переменные среды для сеанса аутентификации. Вы можете проверить это, запустив su внутри вашего контейнера:

$ docker run -v $PWD/environment:/etc/environment -it ubuntu:14.04 bash
root@4902dd72b49b:/# env | grep ENV
root@4902dd72b49b:/# su -
root@4902dd72b49b:/# env | grep ENV
FROM_ENV_FILE=true

При запуске su запускается сеанс аутентификации, поэтому используется файл /etc/environment.

Таким образом, вы не должны пытаться использовать этот файл для установки переменных для основного процесса контейнера. Этот файл имеет другое назначение и Docker об этом не знает.

person Danila Kiver    schedule 09.07.2018
comment
Спасибо за объяснение! Я думаю, что понимаю, просто потерпите меня для быстрого продолжения, чтобы я полностью понял: в основном процесс Docker — в хост-ОС — порождает основной процесс контейнера, устанавливая переменные среды, переданные из -e, но поскольку он находится вне контейнера, он ничего не знает о содержимом /etc/environment (или любых файлах настроек среды из файловой системы контейнера, если уж на то пошло), и поэтому все, что находится внутри файловой системы контейнера, неприменимо к среде основного процесса контейнера. Это правильно? - person erstaples; 09.07.2018
comment
Да, ты прав. Обратите внимание, что, формально говоря, Docker может проверять файловую систему контейнера, но /etc/environment — это просто файл конфигурации конкретной библиотеки (libpam), поэтому для Docker это просто текстовый файл без какого-либо особого смысла. - person Danila Kiver; 09.07.2018
comment
Я получаю это сейчас. Спасибо, что нашли время, чтобы объяснить это. - person erstaples; 09.07.2018