Как стать автором
Обновить
58.74
Cloud4Y
#1 Корпоративный облачный провайдер

Использование Docker in Docker в GitLab

Время на прочтение8 мин
Количество просмотров36K

Привет!

Давайте рассмотрим способы запуска Docker в Docker-контейнере (вложенное использование Docker). Такой подход не является повседневным использованием, но иногда помогает решить задачи:

  • При построении пайплайна CI/CD в GitLab или Jenkins для создания образов Docker и их публикации в реджестри (реестре образов)

  • При использовании Jenkins Dynamic Agents (динамических Docker-контейнеров) 

  • При необходимости построения изолированной среды от хоста, где будет выполнятся стендовая работа, а после проведения можно будет легко удалить её.   

Существует три способа запуска docker в docker:
  1. Запуск docker путём монтирования docker.sock (метод DooD)

  2. Использовать дочерний контейнер внутри контейнера  (метод dind)

  3. Использование среды выполнения Nestybox sysbox Docker

Для эксперимента создадим виртуальную машину в облаке Cloud4Y из готового шаблона ubuntu-server-2204 по мануалу. Далее установим docker (https://docs.docker.com/engine/install/ubuntu/). Я воспользуюсь скриптом:

#curl -sSL https://get.docker.com/ | sh

Проверим версию 

# docker –v
Docker version 20.10.22, build 3a2c30b

Метод 1: Docker в Docker с использованием [/var/run/docker.sock]

Что такое /var/run/docker.sock

/var/run/docker.sock является сокетом Unix по умолчанию (IPC-сокет). Сокеты предназначены для обмена данными между процессами на одном хосте. Демон Docker по умолчанию прослушивает docker.sock. Если вы находитесь на том же хосте, на котором запущен демон Docker, вы можете использовать /var/run/docker.sock для управления контейнерами.

Например, если мы запустим следующую команду: 

# curl --unix-socket /var/run/docker.sock http://localhost/version

она вернёт версию docker engine, такую же, как мы проверяли ранее:

{"Platform":{"Name":"Docker Engine -
Community"},"Components":[{"Name":"Engine","Version":"20.10.22","Details":{"ApiVersion":"1.41","A
rch":"amd64","BuildTime":"2022-12-
15T22:25:49.000000000+00:00","Experimental":"false","GitCommit":"42c8b31","GoVersion":"go1.18.9
","KernelVersion":"5.15.0-27-
generic","MinAPIVersion":"1.12","Os":"linux"}},{"Name":"containerd","Version":"1.6.13","Details":{"Git
Commit":"78f51771157abb6c9ed224c22013cdf09962315d"}},{"Name":"runc","Version":"1.1.4","Detail
s":{"GitCommit":"v1.1.4-0-g5fd4c4d"}},{"Name":"dockerinit","
Version":"0.19.0","Details":{"GitCommit":"de40ad0"}}],"Version":"20.10.22","ApiVersion":"1.41",
"MinAPIVersion":"1.12","GitCommit":"42c8b31","GoVersion":"go1.18.9","Os":"linux","Arch":"amd64","
KernelVersion":"5.15.0-27-generic","BuildTime":"2022-12-15T22:25:49.000000000+00:00"}

Теперь давайте запустим Docker in Docker с помощью /var/run/docker.sock. Для этого нам нужно запустить docker с сокетом Unix по умолчанию и передать docker.sock в качестве тома:

# docker run -v /var/run/docker.sock:/var/run/docker.sock -ti docker

Этот метод иногда называют DooD (Docker outside of Docker), потому что он использует Docker вне Docker.  Поскольку он монтирует только сокет хост-среды, используемый образ Docker не используется dind, и не требует привилегированный -privileged режим, как это описано далее в методе 2. 

Тут нужно понимать риски безопасности, что если ваш контейнер получает доступ к docker.sock, это означает, что у него будут повышенные привилегии по сравнению с docker. 

Теперь из контейнера мы имеем возможность выполнять команды docker для создания и отправки образов в реджестри. Фактически, в данном случае операции docker выполняются на хосте виртуальной машины, на которой запущен ваш базовый контейнер docker, а не внутри контейнера. То есть, если вы выполняете команды docker из контейнера, вы даёте указание docker подключиться к docker-engine хоста виртуальной машины через docker.sock. 

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

# docker run --name dood -v /var/run/docker.sock:/var/run/docker.sock -ti docker

Внутри запущенного контейнера скачаем образ docker —  alpine, командой # docker pull  alpine

И посмотрим доступные локальные образы в контейнере 

# docker images

REPOSITORY   TAG       IMAGE ID       CREATED       SIZE

docker       latest    81a4721a045e   8 days ago    152MB

alpine       latest    49176f190c7e   3 weeks ago   7.05MB

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

Метод 2: Docker в Docker с использованием dind

Этот метод фактически создаёт дочерний контейнер внутри контейнера. Используйте этот метод, только если вы действительно хотите, чтобы контейнеры и образы находились внутри контейнера.  Для этого нужно использовать официальный образы docker с тэгом dind. Образ dind загружается с необходимыми утилитами для запуска Docker внутри контейнера Docker и требуют для запуска привилегированный режим. Запустим контейнер:

# docker run --privileged -d --name dind docker:dind

И войдем интерактивно: 

# docker exec -it dind /bin/sh

повторим, что делали ранее, но скачаем теперь другой образа docker —  busybox

# docker pull busybox

И посмотрим доступные локальные образы  в контейнере 

# docker images

REPOSITORY   TAG       IMAGE ID       CREATED       SIZE

busybox      latest    334e4a014c81   7 days ago    4.86MB

Теперь выйдем из контейнера и посмотрим на хостовой машине

# docker images

REPOSITORY   TAG       IMAGE ID       CREATED       SIZE

docker       dind      d74418bd2227   8 days ago    322MB

docker       latest    81a4721a045e   8 days ago    152MB

alpine       latest    49176f190c7e   3 weeks ago   7.05MB

Поскольку Docker на хост-машине и Docker в контейнере docker: dind являются отдельными, образы в контейнере (busybox) не видны с хост-машины, и наоборот. 

 С этим методом связано много проблем:

  • Он плохо работает с модулями безопасности Linux (LSM)

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

  • С безопасностью — из-за необходимости использования привилегированного режима. 

  • Отсутствием поддержки docker-compose в установке по умолчанию и необходимости установки https://docs.docker.com/compose/install/ 

Метод 3: Docker в Docker с использованием среды выполнения Sysbox

Методы 1 и 2 имеют недостатки с точки зрения безопасности из-за запуска базовых контейнеров в привилегированном режиме. Nestybox пытается решить эту проблему, используя среду выполнения Sysbox Docker. Sysbox — это бесплатная среда выполнения контейнеров с открытым исходным кодом, которая расширяет возможности контейнеров двумя ключевыми способами:

  • Улучшает изоляцию контейнера:

    • Пространство имён пользователей Linux во всех контейнерах (т. е. пользователь root в контейнере не имеет привилегий на хосте).

    • Виртуализирует части procfs и sysfs внутри контейнера.

    • Скрывает информацию о хосте внутри контейнера и другие.

  • Позволяет контейнерам работать подобно виртуальным машинам:

    • С помощью Sysbox контейнеры могут запускать программное обеспечение системного уровня, такое как systemd, Docker, Kubernetes, K3s, buildx, устаревшие приложения и т. д. беспрепятственно и безопасно.

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

    • Никаких привилегированных контейнеров, специальных монтирований томов и т. д.

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

# wget https://downloads.nestybox.com/sysbox/releases/v0.5.0/sysbox-ce_0.5.0-0.linux_amd64.deb
# sha256sum sysbox-ce_0.5.0-0.linux_amd64.deb
(Должен быть eeacd9ae0e08ee5e5637e3b93e4f0cf78f20f9590ef2e7ab08347700682422f0  sysbox-ce_0.5.0-0.linux_amd64.deb)
# docker rm $(docker ps -a -q) -f
# sudo apt-get install -y jq
# sudo apt-get install -y ./sysbox-ce_0.5.0-0.linux_amd64.deb
# sudo systemctl status sysbox -n20
● sysbox.service - Sysbox container runtime
     Loaded: loaded (/lib/systemd/system/sysbox.service; enabled; vendor preset: enabled)
     Active: active (running) since Wed 2022-12-14 13:39:54 UTC; 14s ago
       Docs: https://github.com/nestybox/sysbox
   Main PID: 14708 (sh)
      Tasks: 2 (limit: 4579)
     Memory: 408.0K
        CPU: 61ms
     CGroup: /system.slice/sysbox.service
             ├─14708 /bin/sh -c "/usr/bin/sysbox-runc --version && /usr/bin/sysbox-mgr --version && /usr/bin/sysbox-fs --version && /bin/sleep infinity"
             └─14726 /bin/sleep infinity

Теперь мы можем запустить наш контейнер с использованием среда выполнения sysbox при помощи # docker run --runtime=sysbox-runc --name sysbox -d docker:dind

И войти интерактивно: 

# docker exec -it sysbox /bin/sh

Рекомендации по использованию

  • Используйте Docker в Docker только в том случае, если это действительно необходимо вам. Проводите достаточное тестирование, прежде чем переносить любые продуктовые решения на метод Docker-in-Docker.

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

  • Использовании Docker-in-Docker не влияет на производительность контейнера, но определяется производительностью хоста. 

Пример использования Docker-in-Docker для gitlab-runner 

В качестве примера рассмотрим работу gitlab-runner с использованием всех методов. Для этого на нашей виртуальной машине установим gitlab-runner с executor-м docker: 

# docker run -d --name gitlab-runner --restart always \
	-v /srv/gitlab-runner/config:/etc/gitlab-runner \
	-v /var/run/docker.sock:/var/run/docker.sock \
	gitlab/gitlab-runner:latest 

зарегистрируем три раннера с разными тэгами: dood-tag,  dind-tag, sysbox-tag для каждого метода и образом по умолчанию docker:stable. 

# docker run --rm -it -v /srv/gitlab-runner/config:/etc/gitlab-runner gitlab/gitlab-runner register

В конфигурацию соответствующего раннера в /srv/gitlab-runner/config/config.toml внесём правки:

  • В раннер dood-tag с методом 1, ставим настройки  

    • volumes = ["/cache", "/var/run/docker.sock:/var/run/docker.sock"] 

  • В раннер dind-tag с методом 2, ставим настройки  

    • privileged = true

  • В раннер sysbox-tag с методом 3, ставим настройки 

    • runtime = "sysbox-runc"

В итоге CI/CD Settings нашего проекта мы увидим 

Напишем конфигурацию для  GitLab .gitlab-ci.yml 

stages:
  - DooD
  - dind
  - Sysbox   

DooD_Job:
  stage: DooD

  script:
    - docker images

  tags:
    - dood-tag

dind_Job:
  stage: dind
 
  variables:
      DOCKER_TLS_CERTDIR: ""

  services:
    - docker:dind

  script:
    - docker images

  tags:
    - dind-tag


Sysbox_Job:
  stage: Sysbox

  variables:
    DOCKER_TLS_CERTDIR: ""

  services:
    - docker:dind
    
  script:
    - docker images

  tags:
    - sysbox-tag

с тремя стейджами и заданием для каждого метода, запускаемого на своем раннере, и посмотрим результат docker images

Результаты по каждому раннеру: 

  1. DooD_Runner

  1. Dind_runner

  1. Sysbox_runner

Мы видим сходство результата по второму и третьему методу, при этом мы не использовали привилегированный режим в третьем.  

Подробности по раннерам смотрите в документации GitLab: 

Написано на базе этой статьи. Спасибо за внимание!


Что ещё интересного есть в блоге Cloud4Y

→ Информационная безопасность и глупость: необычные примеры

→ NAS за шапку сухарей

→ Как распечатать цветной механический телевизор на 3D-принтере

→ Создание e-ink дисплея с прогнозом погоды

→ Аналоговый компьютер Telefunken RA 770

Подписывайтесь на наш Telegram-канал, чтобы не пропустить очередную статью. Пишем только по делу. А ещё напоминаем про второй сезон нашего сериала ITить-колотить. Его можно посмотреть на YouTube и ВКонтакте.

Теги:
Хабы:
Всего голосов 21: ↑20 и ↓1+19
Комментарии12

Публикации

Информация

Сайт
www.cloud4y.ru
Дата регистрации
Дата основания
2009
Численность
51–100 человек
Местоположение
Россия