Главная/Подготовка среды/Урок

1.3. Docker daemon

Цели

После этого материала вы сможете:

  • объяснить архитектуру daemon–client и то, почему CLI сам ничего не запускает;
  • управлять службой Docker через systemctl: статус, запуск, остановка, перезапуск, автозагрузка;
  • объяснить роль docker.socket и механизм socket activation;
  • читать логи daemon через journalctl и находить в них причину проблемы;
  • настраивать daemon через /etc/docker/daemon.json и проверять конфигурацию до перезапуска;
  • объяснить, что произойдёт с работающими containers при перезапуске daemon;
  • понимать назначение каталога /var/lib/docker и его структуру.

Предварительные знания

Ключевые термины

ТерминОбъяснение
daemonФоновый процесс, работающий без привязки к терминалу. В нашем случае — dockerd
systemdСистема инициализации и менеджер служб в большинстве современных дистрибутивов Linux
unitЕдиница управления в systemd: служба, сокет, таймер и другие. Описывается unit-файлом
socket activationМеханизм systemd, при котором сокет создаётся заранее, а служба запускается при первом обращении к нему
journalctlИнструмент чтения журнала systemd, куда пишут логи все службы
drop-inФайл переопределения настроек unit без изменения оригинального unit-файла
live restoreРежим, при котором containers продолжают работать во время перезапуска daemon

Теория

Архитектура daemon–client

Команда docker ничего не запускает сама. Она формирует HTTP-запрос и отправляет его daemon через Unix socket. Daemon выполняет работу и возвращает ответ.

text
   пользователь
        │  docker run nginx
        ▼
   ┌──────────────┐    HTTP over Unix socket     ┌──────────────┐
   │  docker CLI  │ ───────────────────────────► │   dockerd    │
   │              │ ◄─────────────────────────── │   (daemon)   │
   └──────────────┘      JSON-ответ              └──────┬───────┘
                                                        │ gRPC
                                                        ▼
                                                  ┌──────────────┐
                                                  │  containerd  │
                                                  └──────────────┘

Из этой схемы следуют три практических вывода.

Первый. CLI и daemon — разные программы, которые могут иметь разные версии. Именно поэтому docker version показывает два блока. Обычно версии совпадают, но CLI может подключаться и к удалённому daemon другой версии.

Второй. Всё, что делает Docker, выполняется от имени root (в обычном режиме). Пользователь, способный отправлять команды daemon, фактически имеет права root на машине. Этому посвящён урок 1.5.

Третий. Если daemon не работает, CLI бесполезен. Диагностика проблем начинается с проверки daemon.

Два unit-файла: service и socket

Установка создаёт два unit:

UnitНазначение
docker.serviceСам daemon dockerd
docker.socketUnix socket /var/run/docker.sock с socket activation

Socket activation означает: systemd создаёт и слушает socket сам, а docker.service запускается при первом обращении к нему. Это ускоряет загрузку системы — daemon не стартует, пока не понадобится.

Практическое следствие, которое сбивает с толку: команда

bash
sudo systemctl stop docker

останавливает docker.service, но docker.socket продолжает слушать. Первое же обращение через docker ps запустит daemon обратно. Чтобы остановить Docker по-настоящему, нужно остановить оба unit.

Что происходит с containers при перезапуске daemon

Ответ зависит от настройки live-restore.

По умолчанию (live-restore выключен): при остановке daemon все работающие containers останавливаются. При старте daemon containers с restart policy always или unless-stopped запускаются заново.

С live-restore: true: containers продолжают работать во время перезапуска daemon. Это возможно благодаря архитектуре с shim-процессами: каждый container имеет собственный containerd-shim, который является его родителем и не зависит от dockerd. Механизм подробно разбирается в разделе 17.

Ограничения live-restore: не работает при изменении части настроек daemon и несовместим со Swarm mode.

Конфигурация через daemon.json

Файл /etc/docker/daemon.json задаёт настройки daemon. По умолчанию его не существует — Docker работает с настройками по умолчанию.

Наиболее полезные параметры для курса:

ПараметрНазначение
log-driver, log-optsДрайвер логирования и ротация. Разбирается в разделе 13
data-rootКаталог данных вместо /var/lib/docker
default-address-poolsДиапазоны адресов для создаваемых сетей. Разбирается в разделе 08
live-restoreСохранение containers при перезапуске daemon
featuresВключение возможностей, например containerd-snapshotter
debugПодробное логирование

Важное правило: изменения применяются только после перезапуска или перечитывания конфигурации. Синтаксическая ошибка в JSON приводит к тому, что daemon не стартует. Поэтому файл нужно проверять до перезапуска.

Каталог данных

По умолчанию /var/lib/docker. Структура зависит от того, какое хранилище образов используется.

text
/var/lib/docker/
├── buildkit/            кэш сборки BuildKit
├── containers/          метаданные и логи containers
├── image/               метаданные образов (классическое хранилище)
├── network/             конфигурация сетей
├── overlay2/            слои образов и writable layers
├── plugins/             плагины
├── volumes/             данные named volumes
└── tmp/

При использовании containerd image store образы хранятся в /var/lib/containerd, а /var/lib/docker содержит остальное.

Не редактируйте содержимое этих каталогов вручную. Метаданные и файлы связаны между собой; ручное удаление приводит к несогласованному состоянию, которое чинится только полной переустановкой. Для очистки используйте команды Docker — см. раздел 13.


Внутренний механизм

Последовательность запуска

  1. systemd активирует docker.socket и создаёт /var/run/docker.sock с владельцем root, группой docker и правами 0660.
  2. При первом обращении к сокету systemd запускает docker.service.
  3. dockerd читает /etc/docker/daemon.json (если файл существует) и аргументы из unit-файла.
  4. Daemon проверяет доступность механизмов ядра, выбирает storage driver, инициализирует сеть.
  5. Daemon подключается к containerd (запускается как отдельная служба containerd.service).
  6. Daemon восстанавливает состояние containers из метаданных.
  7. Containers с подходящей restart policy запускаются.

Если любой шаг не удался, dockerd завершается с ошибкой, и systemd помечает unit как failed. Причина всегда есть в журнале.

Конфликт аргументов daemon.json и unit-файла

Частая ловушка. Unit-файл содержит строку запуска:

text
ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock

Если тот же параметр задать и в daemon.json (например, hosts), daemon откажется стартовать с ошибкой о конфликте. Правило: параметр задаётся либо в daemon.json, либо в аргументах — но не в обоих местах.

Для изменения аргументов запуска используется drop-in файл, а не редактирование /lib/systemd/system/docker.service (он перезапишется при обновлении пакета).


Команды и примеры

Статус службы

bash
systemctl status docker

Ожидаемый результат:

text
● docker.service - Docker Application Container Engine
     Loaded: loaded (/usr/lib/systemd/system/docker.service; enabled; preset: enabled)
     Active: active (running) since Wed 2026-07-29 10:12:44 MSK; 2h 5min ago
TriggeredBy: ● docker.socket
       Docs: https://docs.docker.com
   Main PID: 1842 (dockerd)
      Tasks: 21
     Memory: 118.4M
        CPU: 4.312s
     CGroup: /system.slice/docker.service
             └─1842 /usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock

Что читать в этом выводе:

ПолеЗначение
Loaded: ... enabledСлужба запускается автоматически при загрузке системы
Active: active (running)Служба работает
TriggeredBy: docker.socketАктивирована через socket activation
Main PIDPID процесса dockerd
CGroupСтрока запуска с фактическими аргументами

Команда не требует sudo для чтения статуса.

Управление службой

bash
sudo systemctl stop docker

Что делает: останавливает docker.service. Работающие containers будут остановлены (при выключенном live-restore).

Важно: docker.socket продолжает работать, и любая команда docker запустит daemon заново. Для полной остановки:

bash
sudo systemctl stop docker.socket docker.service
bash
sudo systemctl start docker

Запускает daemon.

bash
sudo systemctl restart docker

Перезапускает. Используется после изменения daemon.json.

bash
sudo systemctl reload docker

Перечитывает часть конфигурации без перезапуска daemon и без остановки containers. Работает не для всех параметров — например, изменение data-root требует полного перезапуска.

Автозагрузка:

bash
sudo systemctl disable docker.service docker.socket   # отключить
sudo systemctl enable docker.service docker.socket    # включить

Что изменяет: создаёт или удаляет символические ссылки в /etc/systemd/system/. Не влияет на текущее состояние службы.

Логи daemon

bash
sudo journalctl -u docker.service

Весь журнал службы с начала.

Практически полезные варианты:

bash
# последние 50 строк
sudo journalctl -u docker.service -n 50

# следить в реальном времени
sudo journalctl -u docker.service -f

# за последний час
sudo journalctl -u docker.service --since "1 hour ago"

# только ошибки
sudo journalctl -u docker.service -p err

# без сокращения длинных строк
sudo journalctl -u docker.service --no-pager -o cat

Разбор флагов:

ФлагЗначение
-uФильтр по unit
-n NПоследние N строк
-fСледовать за новыми записями (как tail -f)
--sinceНачиная с момента времени; принимает и абсолютные даты, и выражения вроде 10 min ago
-p errПриоритет не ниже err
-o catТолько текст сообщения, без метаданных

Не путайте journalctl -u docker.service (логи самого daemon) и docker logs <container> (логи приложения внутри container). Это разные источники. Логи приложения разбираются в разделе 13.

Настройка daemon.json

Создание файла:

bash
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json > /dev/null <<'EOF'
{
  "log-driver": "local",
  "log-opts": {
    "max-size": "10m",
    "max-file": "3"
  },
  "live-restore": true
}
EOF

Что делает эта конфигурация:

  • log-driver: local — использовать драйвер local вместо json-file. Он эффективнее по месту и по умолчанию выполняет ротацию;
  • max-size: 10m, max-file: 3 — не более трёх файлов по 10 MB на container, то есть максимум 30 MB логов;
  • live-restore: true — containers переживают перезапуск daemon.

Проверка синтаксиса до перезапуска. Если в файле ошибка, daemon не стартует, и вы останетесь без Docker. Проверьте JSON заранее:

bash
python3 -m json.tool /etc/docker/daemon.json

Команда выведет отформатированный JSON при корректном синтаксисе и сообщение об ошибке с номером строки при некорректном.

Дополнительная проверка средствами самого Docker — запуск daemon в режиме валидации:

bash
sudo dockerd --validate
text
configuration OK

Применение изменений:

bash
sudo systemctl restart docker
sudo docker info --format '{{.LoggingDriver}}'
text
local

Изменение аргументов запуска через drop-in

bash
sudo systemctl edit docker.service

Открывается редактор. Впишите:

ini
[Service]
ExecStart=
ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock --debug

Пустая строка ExecStart= обязательна: она сбрасывает значение из оригинального unit-файла. Без неё systemd попытается выполнить обе команды и откажет.

Применение:

bash
sudo systemctl daemon-reload
sudo systemctl restart docker

Просмотр итоговой конфигурации:

bash
systemctl cat docker.service

Отмена изменений:

bash
sudo systemctl revert docker.service
sudo systemctl daemon-reload
sudo systemctl restart docker

Просмотр каталога данных

bash
sudo docker info --format '{{.DockerRootDir}}'
text
/var/lib/docker

Объём:

bash
sudo du -sh /var/lib/docker

Структурированный отчёт средствами Docker:

bash
sudo docker system df
text
TYPE            TOTAL     ACTIVE    SIZE      RECLAIMABLE
Images          12        3         2.841GB   1.902GB (66%)
Containers      5         2         12.4MB    8.1MB (65%)
Local Volumes   4         2         318.2MB   102.4MB (32%)
Build Cache     47        0         1.204GB   1.204GB

Эта команда безопаснее du: она показывает, что именно занимает место и сколько можно освободить.


Практический пример

Задача: настроить ротацию логов, убедиться, что настройка применилась, и уметь откатить изменение.

text
daemon-config/
├── daemon.json
└── apply.sh

daemon.json

json
{
  "log-driver": "local",
  "log-opts": {
    "max-size": "10m",
    "max-file": "3"
  },
  "live-restore": true
}

apply.sh

bash
#!/usr/bin/env bash
# apply.sh — безопасное применение конфигурации Docker daemon.
set -euo pipefail

CONFIG_SRC="$(dirname "$0")/daemon.json"
CONFIG_DST="/etc/docker/daemon.json"
BACKUP="/etc/docker/daemon.json.bak"

echo "1. Проверка синтаксиса JSON..."
python3 -m json.tool "$CONFIG_SRC" > /dev/null
echo "   OK"

echo "2. Резервная копия текущей конфигурации..."
if [ -f "$CONFIG_DST" ]; then
    sudo cp "$CONFIG_DST" "$BACKUP"
    echo "   Сохранено в $BACKUP"
else
    echo "   Текущей конфигурации нет — создаётся впервые"
fi

echo "3. Установка новой конфигурации..."
sudo mkdir -p /etc/docker
sudo cp "$CONFIG_SRC" "$CONFIG_DST"

echo "4. Валидация средствами dockerd..."
sudo dockerd --validate

echo "5. Перезапуск daemon..."
sudo systemctl restart docker

echo "6. Проверка применённых настроек..."
driver="$(sudo docker info --format '{{.LoggingDriver}}')"
echo "   Logging driver: $driver"

if [ "$driver" = "local" ]; then
    echo
    echo "Готово."
else
    echo
    echo "Настройка не применилась. Проверьте: sudo journalctl -u docker.service -n 30"
    exit 1
fi

Запуск:

bash
chmod +x apply.sh
./apply.sh

Откат:

bash
sudo cp /etc/docker/daemon.json.bak /etc/docker/daemon.json
sudo systemctl restart docker

Проверка результата

bash
sudo docker info --format 'Driver: {{.LoggingDriver}}  LiveRestore: {{.LiveRestoreEnabled}}'
text
Driver: local  LiveRestore: true

Проверка, что daemon перезапустился без ошибок:

bash
systemctl is-active docker
text
active

Типичные ошибки

ОшибкаПричинаИсправление
После systemctl stop docker команда docker ps снова запускает daemonРаботает socket activation через docker.socketОстановить оба unit: sudo systemctl stop docker.socket docker.service
Daemon не стартует после правки daemon.jsonСинтаксическая ошибка JSON (лишняя запятая, кавычки)python3 -m json.tool /etc/docker/daemon.json, исправить, перезапустить
unable to configure the Docker daemon ... conflicting optionsОдин параметр задан и в daemon.json, и в ExecStartУбрать дублирование из одного из мест
Изменения в /lib/systemd/system/docker.service пропали после обновленияФайл принадлежит пакету и перезаписываетсяИспользовать systemctl edit docker.service
systemctl edit не сработалЗабыта пустая строка ExecStart= перед новойДобавить сброс значения
Ручное удаление файлов из /var/lib/dockerМетаданные рассогласовались с файлами на дискеНе делать этого; использовать docker system prune — см. раздел 13
Поиск логов приложения через journalctl -u dockerЭто логи daemon, а не containersИспользовать docker logs <container>

Контрольные вопросы

На понимание:

  1. Почему docker version показывает две версии?
  2. Что такое socket activation и как оно влияет на остановку Docker?
  3. Что произойдёт с работающими containers при systemctl restart docker с включённым и с выключенным live-restore?
  4. Почему нельзя редактировать /lib/systemd/system/docker.service напрямую?
  5. Почему ошибка в daemon.json приводит к полной неработоспособности Docker, а не игнорируется?

На применение:

  1. Как посмотреть только ошибки daemon за последние 30 минут?
  2. Как проверить корректность daemon.json до перезапуска службы?
  3. Как узнать фактическую строку запуска dockerd со всеми аргументами?

На диагностику:

  1. systemctl status docker показывает activating (auto-restart), и состояние повторяется. Какова последовательность действий?
  2. После добавления "hosts": ["unix:///var/run/docker.sock"] в daemon.json daemon перестал стартовать. В чём причина?

Краткое резюме

  1. CLI и daemon — разные программы; CLI только отправляет запросы через Unix socket.
  2. Установка создаёт два unit: docker.service и docker.socket.
  3. Socket activation запускает daemon при первом обращении, поэтому остановки только docker.service недостаточно.
  4. Логи daemon читаются через journalctl -u docker.service; логи приложений — через docker logs.
  5. Конфигурация daemon задаётся в /etc/docker/daemon.json; файл по умолчанию отсутствует.
  6. Синтаксическая ошибка в daemon.json не даёт daemon запуститься — проверяйте до перезапуска.
  7. Параметр задаётся либо в daemon.json, либо в аргументах ExecStart, но не в обоих местах.
  8. Аргументы запуска изменяются через systemctl edit, а не правкой unit-файла пакета.
  9. live-restore позволяет containers пережить перезапуск daemon.
  10. Содержимое /var/lib/docker не редактируется вручную; для анализа используйте docker system df.

Официальные источники

ИсточникСсылкаЧто подтверждает
Docker daemon configurationhttps://docs.docker.com/engine/daemon/Файл daemon.json, применение настроек, валидация
Configure the daemon with systemdhttps://docs.docker.com/engine/daemon/proxy/Использование drop-in файлов systemd
dockerd CLI referencehttps://docs.docker.com/reference/cli/dockerd/Все параметры daemon, флаг --validate, live-restore
Start containers automaticallyhttps://docs.docker.com/engine/containers/start-containers-automatically/Взаимодействие restart policies и перезапуска daemon
systemctl(1) man pagehttps://man7.org/linux/man-pages/man1/systemctl.1.htmlКоманды управления unit, edit, revert, cat
journalctl(1) man pagehttps://man7.org/linux/man-pages/man1/journalctl.1.htmlФлаги фильтрации журнала

Навигация

← Предыдущий материал
Вернуться к разделу
Следующий материал → Первый container
Главное оглавление

Markdown на GitHub ↗