Skip to content

NGRsoftlab/Astra-docker-image

Repository files navigation

NGRSOFTLAB logo

Docker in Docker

Dive efficiency Made with love Powered by Docker NGR Team

DinD image

Ascii svg art by aasvg.

Description

Docker in Docker - это реализация DinD на базе Astra Linux

Присоединяйтесь к нашим социальным сетям:

NGR Social Telegram       NGR Social Media

Contents

OS Docker Status
Astra 1.8 Docker 25.0 ✅ Fully supported
Таблица 1. Поддерживаемые ОС-ы.

 

Docker - это проект с открытым исходным кодом, который автоматизирует развертывание приложений внутри программных контейнеров, предоставляя дополнительный уровень абстракции и автоматизации виртуализации на уровне операционной системы в Linux, Mac OS и Windows. Образ построен на основе отечественной ОС Astra Linux. Проект реализован на основе официального репозитория Docker

Прежде чем запускать Docker-in-Docker, обязательно прочтите публикацию в блоге Жерома Петаццони на эту тему⁠, где он описывает некоторые плюсы и минусы такого подхода(а также некоторые неприятные подводные камни, с которыми Вы можете столкнуться). Если Вы по-прежнему убеждены, что Вам нужен Docker-in-Docker, а не просто доступ к серверу Docker, на котором размещен контейнер, то читайте дальше

  • docker:<version>-<os_version> - базовый образ. Он предназначен для использования как одноразового контейнера, а также как основа для создания других образов
  • docker:<version>-rootless-<os_version> - образ лишенный запуска из под высоко привилегированного пользователя. Как и в случае с обычным dind образом, --privileged для правильной работы Docker-in-Docker требуется(тут и тут), что является проблемой безопасности, требующей соответствующего решения

Для начала работы необходимо установить pre-commit и хуки

$ pip install pre-commit
$ pre-commit --version

pre-commit 4.2.0

$ pre-commit install

pre-commit installed at .git/hooks/pre-commit
pre-commit installed at .git/hooks/commit-msg
pre-commit installed at .git/hooks/pre-push

Warning

Чтобы проверить свои изменения, воспользуйтесь командой pre-commit run --all-files. Чтобы проверить конкретную задачу, воспользуетесь командой pre-commit run <target> --all-files. Если Вы понимаете что творите и хотите пропустить проверку pre-commit-ом воспользуйтесь --no-verify, пример git commit -m "Добавил изменения и не хочу проверки" --no-verify

Собрать образ Astra Linux based:

  • Docker cli

    ## Export Docker CLI version
    export ASTRA_VERSION='1.8.2-slim'
    export DCLI_VERSION="25.0-astra${ASTRA_VERSION}"
    
    ## DCLI image: 715MB
    docker build \
        --progress=plain \
        --no-cache \
        -t docker:"${DCLI_VERSION}" \
        .
  • DinD

    ## Export DinD version
    export ASTRA_VERSION='1.8.2-slim'
    export DIND_VERSION="25.0-dind-astra${ASTRA_VERSION}"
    
    ## DinD image: 727MB
    docker build \
        --progress=plain \
        --no-cache \
        -f Dockerfile.dind \
        -t docker:"${DIND_VERSION}" \
        .
  • DinD rootless

    ## Export DinD rootless version
    export ASTRA_VERSION='1.8.2-slim'
    export DIND_ROOTLESS_VERSION="25.0-dind-rootless-astra${ASTRA_VERSION}"
    
    ## DinD rootless image: 753MB
    docker build \
        --progress=plain \
        --no-cache \
        -f Dockerfile.dind.rootless \
        -t docker:"${DIND_ROOTLESS_VERSION}" \
        .
Имя Значение по умолчанию Тип Описание
image_name astra string Имя образа.
image_registry '' string Адрес до реестра образа1.
image_version 1.8.2-slim string Версия образа.
dind_additional_tools 'curl sshpass jq xmlstarlet yq' string Список дополнительных пакетов, которые будут установлены вместе с основными.
Таблица 2. Переопределяемые аргументы для сборки образа.

 

Порядок сборки образов:

Dockerfile => Dockerfile.dind => Dockerfile.dind.rootless

export ASTRA_VERSION='1.8.2-slim'
export DIND_VERSION="25.0-dind-astra${ASTRA_VERSION}"

docker run --privileged --name some-docker -d \
  --network some-network --network-alias docker \
  -e DOCKER_TLS_CERTDIR=/certs \
  docker:"${DIND_VERSION}"

Note

--privileged требуется для правильной работы Docker-in-Docker, но его следует использовать с осторожностью, поскольку он обеспечивает полный доступ к среде хоста, как описано в соответствующем разделе документации Docker

Базовый пример использования:

$ export ASTRA_VERSION='1.8.2-slim'
$ export DIND_ROOTLESS_VERSION="25.0-dind-rootless-astra${ASTRA_VERSION}"

## None TLS variant
$ docker run -d --name some-docker --privileged docker:"${DIND_ROOTLESS_VERSION}"

## With TLS variant
$ docker run -d --name some-docker --privileged -e DOCKER_TLS_CERTDIR=/home/rootless/certs docker:"${DIND_ROOTLESS_VERSION}"

## To verify the daemon has finished generating TLS certificates and is listening successfully
$ docker logs --tail=3 some-docker

time="xxx" level=info msg="Daemon has completed initialization"
time="xxx" level=info msg="API listen on /run/user/1000/docker.sock"
time="xxx" level=info msg="API listen on [::]:2376"

## Using "docker-entrypoint.sh" which auto-sets "DOCKER_HOST" appropriately
$ docker exec -it some-docker docker-entrypoint.sh sh

/ $ docker info --format '{{ json .SecurityOptions }}'
["name=seccomp,profile=builtin","name=rootless","name=cgroupns"]

Чтобы запустить с другим UID/GID, отличным от того, который зашит в образ, измените разрешения /etc/passwd, /etc/group, и файловой системы(особенно для rootless домашнего каталога пользователя). Например:

FROM docker:"${DIND_VERSION}"

USER root

RUN set -eux; \
    sed -i -e 's/^rootless:x:1000:1000:/rootless:x:1234:5678:/' /etc/passwd; \
    sed -i -e 's/^rootless:x:1000:/rootless:x:5678:/' /etc/group; \
    chown -R rootless ~rootless

USER rootless

dind вариант этого образа будет автоматически генерировать сертификаты TLS в каталоге, указанном в DOCKER_TLS_CERTDIR переменной. Если этот параметр включен, демон Docker будет запущен с помощью --host=tcp://0.0.0.0:2376 --tlsverify ...(а если отключен, демон Docker будет запущен с помощью --host=tcp://0.0.0.0:2375)

Внутри каталога, указанного в DOCKER_TLS_CERTDIR, скрипты точки входа будут создавать/использовать три каталога:

  • ca: файлы центра сертификации(cert.pem, key.pem)
  • server: dockerd файлы сертификатов демона(cert.pem, ca.pem, key.pem)
  • client: docker файлы сертификатов клиента(cert.pem, ca.pem, key.pem; подходит для DOCKER_CERT_PATH)

Warning

Чтобы использовать эту функцию из 'клиентского' контейнера, необходимо, чтобы client подкаталог каталога ${DOCKER_TLS_CERTDIR} был общим

Чтобы отключить это поведение, переопределите команду контейнера или точку входа для dockerd(... docker:"${DIND_VERSION}" dockerd ... или ... --entrypoint dockerd docker:"${DIND_VERSION}" ...)

export ASTRA_VERSION='1.8.2-slim'
export DIND_VERSION="25.0-dind-astra${ASTRA_VERSION}"

docker run --privileged --name some-docker -d \
  --network some-network --network-alias docker \
  -e DOCKER_TLS_CERTDIR=/certs \
  -v some-docker-certs-ca:/certs/ca \
  -v some-docker-certs-client:/certs/client \
  docker:"${DIND_VERSION}" --storage-driver overlay2

Вдохновляясь официальной конфигурацией systemd ⁠docker.service, Вы можете рассмотреть различные значения для следующих параметров конфигурации среды выполнения, особенно для производственных экземпляров Docker:

export ASTRA_VERSION='1.8.2-slim'
export DIND_VERSION="25.0-dind-astra${ASTRA_VERSION}"

docker run --privileged --name some-docker -d \
  ... \
  --ulimit nofile=-1 \
  --ulimit nproc=-1 \
  --ulimit core=-1 \
  --pids-limit -1 \
  --oom-score-adj -500 \
  docker:"${DIND_VERSION}"
export ASTRA_VERSION='1.8.2-slim'
export DIND_VERSION="25.0-dind-astra${ASTRA_VERSION}"

docker run --rm --privileged --name some-docker \
  --cap-add=NET_ADMIN --cap-add=SYS_MODULE \
  -e DOCKER_TLS_CERTDIR=/cert \
  docker:"${DIND_VERSION}"

Warning

Некоторые из них не будут поддерживаться в зависимости от настроек на хосте dockerd, например --ulimit nofile=-1, выдавая ошибки, которые выглядят как error setting rlimit type 7: operation not permitted, а некоторые могут наследовать разумные значения от экземпляра хоста dockerd или могут не применяться для Вашего использования Docker-in-Docker(например установить --oom-score-adj значение, которое выше, чем dockerd на хосте, чтобы Ваш экземпляр Docker-in-Docker был завершен до завершения экземпляра хоста Docker)

Имя Значение по умолчанию Тип Описание
DEBUG '' string Включает режим отладки для скрипта. Чтобы включить необходимо передать при запуске: -e DEBUG=true.
DOCKER_TLS_CERTDIR '' string При наличии значения происходит генерация TLS сертификатов. Чтобы включить необходимо передать при запуске, например: -e DOCKER_TLS_CERTDIR=/cert.
DOCKER_HOST '' string Переопределяемое значение хостового сокета. По умолчанию пытается сам определить данное значение.
DOCKERD_ROOTLESS_ROOTLESSKIT_FLAGS '' string Дополнительные параметры запуска для rootlesskit.
DOCKERD_ROOTLESS_ROOTLESSKIT_NET slirp4netns string Дополнительные параметры запуска для сети(net) rootlesskit. По умолчанию используется пакет slirp4netns.
DOCKERD_ROOTLESS_ROOTLESSKIT_MTU 65520 integer Дополнительные параметры запуска для сети(mtu) rootlesskit. По умолчанию используется оптимальное значение для пакета slirp4netns - 65520.
Таблица 3. Переопределяемые переменные среды.

 

Существует несколько способов хранения данных, используемых приложениями, работающими в контейнерах Docker:

  1. Позвольте Docker управлять хранением данных, записывая их на диск в хост-системе, используя собственное внутреннее управление томами⁠. Это значение по умолчанию, оно простое и довольно прозрачное. Недостатком является то, что файлы может быть трудно найти для инструментов и приложений, которые работают непосредственно в хост-системе, т.е. вне контейнеров
  2. Создайте каталог данных на хост-системе(вне контейнера) и смонтируйте его в каталог, видимый изнутри контейнера. Это помещает файлы в известное место на хост-системе и упрощает доступ инструментов и приложений на хост-системе к файлам. Недостатком является то, что пользователю необходимо убедиться, что каталог существует, и что, например, разрешения каталога и другие механизмы безопасности на хост-системе настроены правильно

Базовые настройки для последнего варианта выше:

  1. Создайте каталог данных на подходящем томе вашей хост-системы, например /my/own/var-lib-docker.

  2. Запустите docker контейнер следующим образом:

    docker run --privileged --name some-docker -v /my/own/var-lib-docker:/var/lib/docker -d docker:"${DIND_VERSION}"

Часть -v /my/own/var-lib-docker:/var/lib/docker команды монтирует /my/own/var-lib-docker каталог из базовой хост-системы как /var/lib/docker внутри контейнера, куда Docker по умолчанию будет записывать свои файлы

  1. Создать сеть

    $ docker network create some-network
    24b348027117af59f92b0a07d1bf8d6085f8e4ead043085b86f5497cd303b454
  2. Создать тома для сертификатов

    $ docker volume create some-docker-certs-ca
    some-docker-certs-ca
    
    $ docker volume create some-docker-certs-client
    some-docker-certs-client
  3. Создать контейнер с dind образом

    $ export ASTRA_VERSION='1.8.2-slim'
    $ export DIND_VERSION="25.0-dind-astra${ASTRA_VERSION}"
    
    $ docker run --privileged --name some-docker -d \
      --network some-network --network-alias docker \
      -e DOCKER_TLS_CERTDIR=/certs \
      -v some-docker-certs-ca:/certs/ca \
      -v some-docker-certs-client:/certs/client \
      docker:"${DIND_VERSION}"
    
    some-docker
  4. Проверяем лог работы

    $ docker logs some-docker
    
    ...
    time="2025-06-05T13:30:22.274575341Z" level=info msg="Loading containers: done."
    time="2025-06-05T13:30:22.290273807Z" level=warning msg="WARNING: bridge-nf-call-iptables is disabled"
    time="2025-06-05T13:30:22.290340928Z" level=warning msg="WARNING: bridge-nf-call-ip6tables is disabled"
    time="2025-06-05T13:30:22.290380248Z" level=info msg="Docker daemon" commit=37ca0c1e containerd-snapshotter=false storage-driver=overlay2 version=25.0.5.astra2
    time="2025-06-05T13:30:22.290756206Z" level=info msg="Daemon has completed initialization"
    time="2025-06-05T13:30:22.341445194Z" level=info msg="API listen on /var/run/docker.sock"
    time="2025-06-05T13:30:22.341462295Z" level=info msg="API listen on [::]:2376"
  5. Подключаемся к контейнеру через клиента

    $ export ASTRA_VERSION='1.8.2-slim'
    $ export DCLI_VERSION="25.0-astra${ASTRA_VERSION}"
    
    $ docker run --rm --network some-network \
      -e DOCKER_TLS_CERTDIR=/certs \
      -v some-docker-certs-client:/certs/client:ro \
      docker:"${DCLI_VERSION}" version
    
    Client:
      Version:           25.0.5.astra2
      API version:       1.44
      Go version:        go1.20.14
      Git commit:
      Built:             Fri Feb 21 12:55:57 2025
      OS/Arch:           linux/amd64
      Context:           default
    
    
    Server:
      Engine:
        Version:          25.0.5.astra2
        API version:      1.44 (minimum version 1.24)
        Go version:       go1.20.14
        Git commit:       37ca0c1e
        Built:            Fri Feb 21 12:55:57 2025
        OS/Arch:          linux/amd64
        Experimental:     false
      containerd:
        Version:          1.7.13~astra1
        GitCommit:        .m
      runc:
        Version:          1.1.12~astra1
        GitCommit:
      docker-init:
        Version:          0.19.0
        GitCommit:
  6. Подключаемся внутрь второго контейнера с клиентом, чтобы проверить соответствие с прошлым выводимым, на предмет исключения искажения данных

    $ export ASTRA_VERSION='1.8.2-slim'
    $ export DCLI_VERSION="25.0-astra${ASTRA_VERSION}"
    
    $ docker run -it --rm --network some-network \
      -e DOCKER_TLS_CERTDIR=/certs \
      -v some-docker-certs-client:/certs/client:ro \
      docker:"${DCLI_VERSION}" bash
    
    $ docker version
    
    Client:
      Version:           25.0.5.astra2
      API version:       1.44
      Go version:        go1.20.14
      Git commit:
      Built:             Fri Feb 21 12:55:57 2025
      OS/Arch:           linux/amd64
      Context:           default
    
    Server:
      Engine:
        Version:          25.0.5.astra2
        API version:      1.44 (minimum version 1.24)
        Go version:       go1.20.14
        Git commit:       37ca0c1e
        Built:            Fri Feb 21 12:55:57 2025
        OS/Arch:          linux/amd64
        Experimental:     false
      containerd:
        Version:          1.7.13~astra1
        GitCommit:        .m
      runc:
        Version:          1.1.12~astra1
        GitCommit:
      docker-init:
        Version:          0.19.0
        GitCommit:
    
    $ docker info
    
    Client:
      Version:    25.0.5.astra2
      Context:    default
      Debug Mode: false
      Plugins:
        buildx: Docker Buildx (Docker Inc.)
          Version:  0.12.1~astra1
          Path:     /usr/local/lib/docker/cli-plugins/docker-buildx
        compose: Docker Compose (Docker Inc.)
          Version:  2.20.2.astra2
          Path:     /usr/local/lib/docker/cli-plugins/docker-compose
    
    Server:
      Containers: 0
        Running: 0
        Paused: 0
        Stopped: 0
      Images: 0
      Server Version: 25.0.5.astra2
      Storage Driver: overlay2
        Backing Filesystem: extfs
        Supports d_type: true
        Using metacopy: false
        Native Overlay Diff: true
        userxattr: false
      Logging Driver: json-file
      Cgroup Driver: cgroupfs
      Cgroup Version: 2
      Plugins:
        Volume: local
        Network: bridge host ipvlan macvlan null overlay
        Log: awslogs fluentd gcplogs gelf journald json-file local splunk syslog
      Swarm: inactive
      Runtimes: io.containerd.runc.v2 runc
      Default Runtime: runc
      Init Binary: docker-init
      containerd version: .m
      runc version:
      init version:
      Security Options:
        seccomp
        Profile: builtin
        cgroupns
      Kernel Version: 6.8.0-60-generic
      Operating System: Astra Linux
      OSType: linux
      Architecture: x86_64
      CPUs: 16
      Total Memory: 62.22GiB
      Name: 24b348027117
      ID: 880fc4a0-be34-4a52-9074-93ed43d64828
      Docker Root Dir: /var/lib/docker
      Debug Mode: false
      Experimental: false
      Insecure Registries:
        127.0.0.0/8
      Live Restore Enabled: false
    
    ## Взаимодействуем с докером по концепции `dind` запустим контейнер внутри контейнера из дочернего клиента, например bash
    $ docker run -it --rm bash
    
    Unable to find image 'bash:latest' locally
    latest: Pulling from library/bash
    fe07684b16b8: Pull complete
    af91e2532c28: Pull complete
    70f5897ce880: Pull complete
    Digest: sha256:01a15c6f48f6a3c08431cd77e11567823530b18159889dca3b7309b707beef91
    Status: Downloaded newer image for bash:latest
    
    bash-5.3# ls
    bin    dev    etc    home   lib    media  mnt    opt    proc   root   run    sbin   srv    sys    tmp    usr    var
  7. Запустим на прямую клиента, но в качестве аргументов передадим запуск образа

    $ export ASTRA_VERSION='1.8.2-slim'
    $ export DCLI_VERSION="25.0-astra${ASTRA_VERSION}"
    
    $ docker run -it --rm --network some-network \
      -e DOCKER_TLS_CERTDIR=/certs \
      -v some-docker-certs-client:/certs/client:ro \
      docker:"${DCLI_VERSION}" run -it --rm bash
    
    bash-5.3# ls
    bin    dev    etc    home   lib    media  mnt    opt    proc   root   run    sbin   srv    sys    tmp    usr    var
  8. Очистить рабочую область

    $ docker rm -f some-docker
    $ docker network rm some-network
    $ docker volume rm some-docker-certs-ca
    $ docker volume rm some-docker-certs-client
    
    ...remove actions...

При настройке CI/CD Вы указываете образ, который используется для создания контейнера, в котором выполняются Ваши задания. Чтобы указать этот образ, используйте ключевое слово image

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

Пример использования service в GitLab CI/CD

  stage: db-operation
  image: docker:cli
  rules:
    - if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
      changes:
        - '**/*.sql'
      when: on_success
    - when: manual
  variables:
    POSTGRES_USER: postgres
    POSTGRES_PASSWORD: ""
    POSTGRES_HOST_AUTH_METHOD: trust
    POSTGRES_CREATE_DATABASE: test-database
    DOCKER_HOST: tcp://docker:2375
    DOCKER_TLS_CERTDIR: ""
  services:
    - name: postgres:latest
      alias: postgres
      command: [
        "postgres",
        "-c", "log_destination=jsonlog",
        "-c", "logging_collector=on",
        "-c", "log_connections=on",
        "-c", "log_directory=log",
        "-c", "log_filename=postgresql"
      ]
    - name: docker:dind
      alias: docker
  script:
    - createdb -h postgres -U postgres -w test-database -E UTF8
  • При ошибке, которая продемонстрирована ниже, необходимо на хостовой системе включить модуль ядра br_netfilter: sudo modprobe br_netfilter; lsmod | grep br_netfilter
time="2025-06-09T10:35:17.735993522Z level=warning msg="Running modprobe bridge br_netfilter failed with message: modprobe: WARNING: Module bridge not found in directory /lib/modules/6.8.0-60-generic\nmodprobe: WARNING: Module br_netfilter not found in directory /lib/modules/6.8.0-60-generic\n, error: exit status 1"

time="2025-06-09T10:35:17.968855735Z" level=warning msg="WARNING: Running in rootless-mode without cgroups. Systemd is required to enable cgroups in rootless-mode."
time="2025-06-09T10:35:17.968872656Z" level=warning msg="WARNING: bridge-nf-call-iptables is disabled"
time="2025-06-09T10:35:17.968885820Z" level=warning msg="WARNING: bridge-nf-call-ip6tables is disabled"

Лого для проекта создано при помощи aasvg проекта. Вы можете создать такое же и/или модифицировать имеющееся. Для этого воспользуйтесь сайтом или установите figlet. Если Вы используете способ с установкой figlet, то вдобавок необходимо сказать необходимый шрифт, например я использую Doom. Далее, необходимо воспользоваться aasvg и конвертировать ascii арт в svg. Обратите внимание - по умолчанию будет svg в красном цвете, чтобы изменить цвет, необходимо изменить его определение тут

$ curl 'http://www.figlet.org/fonts/doom.flf' -o /usr/share/figlet/doom.flf
$ curl 'http://www.figlet.org/fonts/larry3d.flf' -o /usr/share/figlet/larry3d.flf
$ figlet -f doom 'Docker in Docker'

______           _             _      ______           _
|  _  \         | |           (_)     |  _  \         | |
| | | |___   ___| | _____ _ __ _ _ __ | | | |___   ___| | _____ _ __
| | | / _ \ / __| |/ / _ | '__| | '_ \| | | / _ \ / __| |/ / _ | '__|
| |/ | (_) | (__|   |  __| |  | | | | | |/ | (_) | (__|   |  __| |
|___/ \___/ \___|_|\_\___|_|  |_|_| |_|___/ \___/ \___|_|\_\___|_|

$ aasvg --source --embed < docs/ascii.txt > docs/images/logo.svg
Docker mascot
Docker mascot.

Footnotes

  1. 🛠️ Например можно использовать свой приватный реестр образов: --build-arg image_registry=my-container-registry:1111/

Contributors