Что на самом деле происходит при выполнении команды 'Docker Run'
Перечисленные далее шаги на самом деле являются упрощённым объяснением того, как запускается и работает контейнер Docker. Давайте разберёмся в этом:
- Монтирование каталога: В Docker это означает настройку файловой системы для контейнера. Смонтированный каталог является корневой файловой системой контейнера, который обычно представляет собой образ Docker, указанный в команде
docker run
. - Разделение пространства имён: Пространства имён — это функция ядра Linux, которую Docker использует для обеспечения изоляции между контейнерами. Когда Docker "отделяет" пространство имён, он создаёт новое пространство имён, изолированное от других пространств имён, обеспечивая тем самым частное рабочее пространство для процессов в контейнере.
- Создание chroot, указывающего на смонтированный каталог: chroot — это системный вызов Unix, изменяющий корневой каталог для текущего запущенного процесса и его дочерних процессов. Создавая chroot с указанием на смонтированный каталог, Docker ограничивает часть файловой системы, к которой может получить доступ контейнер, только смонтированным каталогом (т.е. файловой системой контейнера).
- Создание групп управления и привязка к PID в пространстве имён: Группы управления (cgroups) — это ещё одна функция ядра Linux, которую Docker использует для ограничения и изоляции использования ресурсов (CPU, памяти, дискового ввода/вывода и т.д.) контейнеров. Docker создаёт cgroup для контейнера и привязывает её к PID (идентификатору процесса) в пространстве имён, тем самым обеспечивая применение ограничений на ресурсы к процессам контейнера.
- Установка возможностей Linux в chroot: Возможности Linux — это разделение привилегий, традиционно ассоциируемых с суперпользователем, на более широкий набор отдельных привилегий. В целях повышения безопасности Docker устанавливает определённые возможности для среды chroot, ограничивая возможности процессов в контейнере.
- Запуск приложения в пространстве имён: Наконец, 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
на хост-машине, и наоборот.
Это удобная функция, когда требуется, чтобы данные сохранялись даже после остановки или удаления контейнера, поскольку они находятся на хост-машине, а не внутри контейнера.