Что на самом деле происходит при выполнении команды 'Docker Run'

Источник: «What Really Happens When You Command ‘Docker Run’»
Docker — это инструмент, облегчающий создание, развёртывание и запуск приложений с помощью контейнеров. Контейнеры позволяют инженеру упаковать приложение со всеми необходимыми компонентами, например библиотеками и другими зависимостями, и отправить его в виде единого пакета. Это означает, что приложение будет работать на любой другой машине, независимо от настроек, которые могут отличаться от настроек машины, использовавшейся для написания и тестирования кода.

Перечисленные далее шаги на самом деле являются упрощённым объяснением того, как запускается и работает контейнер Docker. Давайте разберёмся в этом:

  1. Монтирование каталога: В Docker это означает настройку файловой системы для контейнера. Смонтированный каталог является корневой файловой системой контейнера, который обычно представляет собой образ Docker, указанный в команде docker run.
  2. Разделение пространства имён: Пространства имён — это функция ядра Linux, которую Docker использует для обеспечения изоляции между контейнерами. Когда Docker "отделяет" пространство имён, он создаёт новое пространство имён, изолированное от других пространств имён, обеспечивая тем самым частное рабочее пространство для процессов в контейнере.
  3. Создание chroot, указывающего на смонтированный каталог: chroot — это системный вызов Unix, изменяющий корневой каталог для текущего запущенного процесса и его дочерних процессов. Создавая chroot с указанием на смонтированный каталог, Docker ограничивает часть файловой системы, к которой может получить доступ контейнер, только смонтированным каталогом (т.е. файловой системой контейнера).
  4. Создание групп управления и привязка к PID в пространстве имён: Группы управления (cgroups) — это ещё одна функция ядра Linux, которую Docker использует для ограничения и изоляции использования ресурсов (CPU, памяти, дискового ввода/вывода и т.д.) контейнеров. Docker создаёт cgroup для контейнера и привязывает её к PID (идентификатору процесса) в пространстве имён, тем самым обеспечивая применение ограничений на ресурсы к процессам контейнера.
  5. Установка возможностей Linux в chroot: Возможности Linux — это разделение привилегий, традиционно ассоциируемых с суперпользователем, на более широкий набор отдельных привилегий. В целях повышения безопасности Docker устанавливает определённые возможности для среды chroot, ограничивая возможности процессов в контейнере.
  6. Запуск приложения в пространстве имён: Наконец, Docker запускает указанное вами приложение в созданной им изолированной и ограниченной по ресурсам среде (т.е. контейнере). Приложение думает, что оно работает на своей машине, но на самом деле оно работает внутри контейнера Docker на хост-машине.

Как Docker, выполняя операцию chroot к смонтированному каталогу, ограничивает доступ контейнера только к этой конкретной части файловой системы (т.е. к файловой системе контейнера)

chroot — это команда в UNIX и UNIX-подобных операционных системах, которая изменяет корневой каталог. Она эффективно изолирует текущий процесс и его дочерние процессы от остальной части системы.

Рассмотрим следующий сценарий: На хост-машине имеется следующая структура каталогов:

/
├── home
│ ├── user
│ │ ├── dir1
│ │ └── dir2
├── var
│ ├── log
│ └── lib
└── tmp

Теперь запускаем контейнер Docker и монтируем каталог home/user с хост-машины в контейнер Docker. В контейнере Docker структура каталогов будет выглядеть следующим образом:

/
├── dir1
└── dir2

Здесь Docker выполнил операцию chroot в каталог home/user. Это означает, что корень (/) внутри контейнера Docker соответствует home/user на хост-машине. Процесс внутри контейнера Docker воспринимает его как всю свою файловую систему. Он не знает и не имеет доступа к каталогам и файлам за пределами каталога home/user на хост-машине (например, /var, /tmp и т.д.).

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

Приведём ещё один пример для понимания того же самого.

docker run -p 8080:8080 -p 50000:50000 -v /your/home:/var/jenkins_home -d jenkins/jenkins

Давайте разберём команду:

docker run: Это команда для создания и запуска нового контейнера Docker.

-p 8080:8080 -p 50000:50000: Эти опции указывают Docker на сопоставление портов 8080 и 50000 вашей хост-машины с портами 8080 и 50000 внутри контейнера Docker соответственно. Это позволит вам получить доступ к серверу Jenkins через эти порты на вашей хост-машине.

-v /your/home:/var/jenkins_home: Это монтирование тома. Он указывает Docker на сопоставление каталога /your/home на хост-машине с каталогом /var/jenkins_home внутри контейнера Docker.

-d: Эта опция запускает контейнер в отделённом режиме, то есть он работает в фоновом режиме и не занимает вашу командную строку.

jenkins/jenkins: Это образ Docker, на котором основан контейнер.

Теперь обсудим файловую структуру:

На хост-машине имеется каталог /your/home, который может содержать любое количество файлов и каталогов. Например:

/your/home
├── file1
├── file2
└── dir1

При выполнении команды docker run с опцией -v /your/home:/var/jenkins_home Docker монтирует каталог /your/home с вашего хоста в каталог /var/jenkins_home внутри контейнера Docker.

Таким образом, внутри контейнера Docker структура файлов будет выглядеть следующим образом:

Это означает, что Jenkins, запущенный внутри контейнера Docker, будет считывать и записывать данные в каталог /var/jenkins_home, который соответствует /your/home на хост-машине. Любые изменения, внесённые Jenkins в /var/jenkins_home, будут отражены в /your/home на хост-машине, и наоборот.

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

Дополнительные материалы

Предыдущая Статья

PHP 8.3 что нового. Изменения и новый функционал.

Следующая Статья

Создание Laravel пакета в локальной среде