🐳 Как и зачем запускать Docker внутри Docker

Мануал

Запуск Docker внутри Docker позволяет создавать образы и запускать контейнеры в уже контейнеризированной среде.

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

Доступ к Docker изнутри контейнера Docker чаще всего желателен в контексте систем CI и CD.

Обычно агенты, запускающие ваш пайплайн, размещаются внутри контейнера Docker.

Вы можете использовать стратегию Docker-in-Docker, если один из этапов вашего пайплайна будет создавать образ или взаимодействовать с контейнерами.

Образ Docker-in-Docker

Docker предоставляется в виде самодостаточного образа через тег docker:dind на Docker Hub.

Запустив этот образ, вы получите функционирующую установку демона Docker внутри вашего нового контейнера.

Он будет работать независимо от демона вашего хоста, который запускает контейнер dind, поэтому docker ps внутри контейнера даст результаты, отличные от docker ps на вашем хосте.

docker run -d --privileged --name docker \
    -e DOCKER_TLS_CERTDIR=/certs \
    -v docker-certs-ca:/certs/ca \
    -v docker-certs-client:/certs/client \
    docker:dind

Использование Docker-in-Docker таким образом связано с одним большим предостережением: необходимо использовать привилегированный режим.

Это ограничение действует, даже если вы используете контейнеры без рутов.

Привилегированный режим активируется флагом –privileged в команде, показанной выше.

Использование привилегированного режима дает контейнеру полный доступ к вашей хост-системе.

Это необходимо в сценарии Docker-in-Docker, чтобы ваш внутренний Docker мог создавать новые контейнеры.

Однако в некоторых средах это может быть неприемлемым риском для безопасности.

Существуют и другие проблемы с dind.

В некоторых системах могут возникать конфликты с модулями безопасности Linux Security Modules (LSM), такими как AppArmor и SELinux.

Это происходит, когда внутренний Docker применяет политики LSM, которые внешний демон не может предугадать.

Еще одна проблема связана с файловыми системами контейнеров.

Внешний демон будет работать поверх обычной файловой системы вашего хоста, например ext4.

Однако все его контейнеры, включая внутренний демон Docker, будут располагаться на файловой системе с копированием при записи (CoW).

Это может привести к несовместимости, если внутренний демон настроен на использование драйвера хранения, который не может быть использован поверх существующей файловой системы CoW.

Вместо этого монтируйте сокет Docker на хосте

Проблемы, связанные с dind, лучше всего решать, избегая его использования вообще.

Во многих сценариях вы можете добиться желаемого эффекта, монтируя Docker-сокет хоста в обычный docker-контейнер:

docker run -d --name docker
    -v /var/run/docker.sock:/var/run/docker.sock \
    docker:latest

Docker CLI внутри образа docker взаимодействует с сокетом демона Docker, который он находит по адресу /var/run/docker.sock.

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

Это означает, что контейнеры, созданные внутренним Docker, будут находиться на вашей хост-системе вместе с самим контейнером Docker.

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

Запуск docker ps даст одинаковые результаты, независимо от того, выполняется ли он на хосте или внутри вашего контейнера.

Эта техника митигирует проблемы реализации dind.

Она также устраняет необходимость использования привилегированного режима, хотя монтирование сокета Docker само по себе является потенциальной проблемой безопасности.

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

Когда использовать каждый подход

Docker-in-Docker через dind исторически широко используется в средах CI.

Это означает, что “внутренние” контейнеры имеют уровень изоляции от хоста.

Один контейнер CI runner поддерживает все контейнеры пайплайна без загрязнения Docker-демона хоста.

Хотя это часто работает, это чревато побочными эффектами и не является целью использования dind.

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

По словам Жерома Петаццони, создателя реализации dind, предпочтительным решением должно быть использование подхода на основе сокетов.

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

Если для вашего случая использования вам абсолютно необходим dind, есть более безопасный способ его развертывания.

Современный проект Sysbox – это специализированная контейнерная среда выполнения, которая может встраивать другие среды выполнения без использования привилегированного режима.

Контейнеры Sysbox становятся VM-подобными, поэтому они могут поддерживать программное обеспечение, которое обычно запускается “на пустом месте” на физической или виртуальной машине.

Включает Docker и Kubernetes без какой-либо специальной конфигурации.

Заключение

Запуск Docker внутри Docker – относительно распространенное требование.

Скорее всего, вы столкнетесь с ней при настройке CI-серверов, которым необходимо поддерживать сборку образов контейнеров из созданных пользователем конвейеров.

Использование docker:dind дает вам независимого демона Docker, работающего внутри собственного контейнера.

Он эффективно создает дочерние контейнеры, которые не видны непосредственно с хоста.

Хотя кажется, что dind обеспечивает сильную изоляцию, на самом деле он таит в себе множество проблем, связанных с крайними случаями и безопасностью.

Это связано с взаимодействием Docker с операционной системой.

Монтирование сокета Docker вашего хоста в контейнер, включающий бинарный файл docker, является более простой и предсказуемой альтернативой.

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

При использовании подхода на основе сокета никаких дополнительных настроек не требуется.

 

Добавить комментарий