GitLab CI не подключается к Docker daemon: DOCKER_HOST, TLS и executor

Job начинается с образа docker, команда docker --version работает, а docker build сообщает Cannot connect to the Docker daemon. Первая команда проверила только клиент. Сборка требует сервер Docker Engine, до которого клиент должен добраться по Unix socket или TCP. Наличие CLI в контейнере этот сервер не создаёт.

В GitLab встречаются разные модели. Shell executor может обращаться к daemon машины Runner. Docker executor иногда получает смонтированный socket хоста. В Docker-in-Docker отдельный service-контейнер запускает свой daemon. Адреса и права этих вариантов различаются; настройки из одного нельзя механически переносить в другой.

Сначала определим, куда идёт клиент

Посмотрите executor в начале журнала, затем значения DOCKER_HOST, DOCKER_TLS_VERIFY и DOCKER_CERT_PATH без вывода содержимого сертификатов. Если CLI пытается открыть /var/run/docker.sock, а ожидается DinD, TCP-адрес не задан или перекрыт. Если используется tcp://docker: 2376, нужен доступ к service с таким именем и подходящие TLS-файлы.

docker version
docker info
printf 'DOCKER_HOST=%s\n' "${DOCKER_HOST:-unset}"
printf 'DOCKER_CERT_PATH=%s\n' "${DOCKER_CERT_PATH:-unset}"

В docker version различайте Client и Server. Ответ Server доказывает соединение с daemon; успешный Client без Server объясняет исходную ошибку. Сообщение certificate signed by unknown authority указывает на TLS, а lookup docker — на имя или сеть service. Connection refused чаще означает, что адрес разрешился, но сервер ещё не слушает либо выбран неправильный порт.

Один согласованный вариант с TLS

Ниже пример для Docker executor и отдельного DinD service. Runner должен быть заранее настроен для разрешённого запуска такого service, включая privileged и общий каталог клиентских сертификатов /certs/client. В YAML job эти настройки Runner не возникают автоматически.

docker_probe:
  image: docker:27.5.1-cli
  services:
    - name: docker:27.5.1-dind
      alias: docker
  variables:
    DOCKER_HOST: tcp://docker:2376
    DOCKER_TLS_CERTDIR: /certs
    DOCKER_TLS_VERIFY: "1"
    DOCKER_CERT_PATH: /certs/client
  script:
    - docker version
    - docker info

Версии клиента и service зафиксированы одной парой для воспроизводимости примера. Для своего проекта выберите поддерживаемую пару по принятой политике обновлений. Общий volume должен дать клиенту сертификаты, которые создаёт DinD. Без него совпадение имён переменных не обеспечивает аутентификацию.

У Kubernetes executor сеть и подключение volumes устроены иначе, поэтому используйте отдельный вариант DinD для своего executor. Если в Runner разрешён только rootless service, обычный dind-образ может не соответствовать его ограничениям. Исправление выбирается вместе с администратором Runner по фактической конфигурации.

Почему смешение портов ломает соединение

В распространённой конфигурации DinD TLS использует 2376, а вариант без TLS — 2375. DOCKER_TLS_CERTDIR управляет созданием сертификатов service. DOCKER_TLS_VERIFY управляет поведением клиента. Если оставить включённый TLS у сервера и направить клиент на незашифрованный порт, они не договорятся.

Не начинайте диагностику с отключения TLS. Сначала проверьте наличие файлов cert.pem, key.pem и ca.pem в ожидаемом каталоге, настройки общего volume и журналы service. Если команда осознанно выбирает вариант без TLS в изолированном стенде, она должна согласованно изменить обе стороны, а не одно значение DOCKER_HOST.

Соединение появилось, что проверять дальше

Если service ещё запускается, используйте ограниченное ожидание готовности, сохраняя последний ответ docker info. Бесконечный retry скрывает постоянную ошибку адреса или TLS. Ошибка доступа к registry после успешного Server относится уже к следующему этапу: daemon доступен, но не может получить нужный образ или авторизоваться.

При socket binding клиент управляет daemon хоста, а при DinD — отдельным daemon service. Это меняет размещение образов, кэш и область полномочий job. Перед реальной сборкой запишите выбранную модель в конфигурации Runner и подтвердите, что diagnostic job видит именно ожидаемый сервер. Тогда исправление соединения не приведёт к незаметной смене среды сборки.

Ещё по теме

Продолжить изучение

Хотите собрать проверяемый путь от коммита до релиза? Jobs, runners, артефакты и деплой — темы программы «GitLab CI/CD: автоматизация сборки и деплоя».

Продолжить на практике

  • GitLab CI/CD: автоматизация сборки и деплоя ↗

    От первого .gitlab-ci.yml до pipeline, который тестирует код, собирает образ и выкладывает приложение. Runners, artifacts, cache, registry, окружения и безопасный откат — на одном практическом проекте.