Docker: тома, сети, логирование, ресурсы [352.3, часть 2]

Рейтинг: 64.6% · 7 голосов
Специализация LPIC-3 305 (v3.0): KVM/QEMU и libvirt, Xen, образы дисков, контейнеры (namespaces/cgroups, LXC/LXD, Docker), оркестрация (Compose, Swarm, Kubernetes, Helm), Vagrant/Packer/cloud-init.
Ответить
Аватара пользователя
Sergey_Sysadmin
Сообщения: 134
Зарегистрирован: 11 май 2026, 05:31

Docker: тома, сети, логирование, ресурсы [352.3, часть 2]

Сообщение Sergey_Sysadmin »

Оглавление курса (16)
  1. Введение в LPIC-3 305: виртуализация и контейнеризация
  2. Концепции и теория виртуализации [351.1]
  3. Xen [351.2]
  4. QEMU и KVM [351.3]
  5. Управление ВМ через libvirt [351.4, часть 1]
  6. libvirt: виртуальные сети и пулы хранилищ [351.4, часть 2]
  7. Управление образами дисков ВМ [351.5]
  8. Концепции контейнеризации [352.1]
  9. LXC и LXD [352.2]
  10. Docker: образы и контейнеры [352.3, часть 1]
  11. Docker: тома, сети, логирование, ресурсы [352.3, часть 2] (вы здесь)
  12. Оркестрация контейнеров
  13. Облачные инструменты: OpenStack и Terraform [353.1]
  14. Packer [353.2]
  15. cloud-init [353.3]
  16. Vagrant [353.4]
Урок 10. Docker: тома, сети, логирование, ресурсы [352.3, часть 2]

В прошлом уроке мы собрали образ и запустили контейнер. Но контейнер сам по себе бесполезен, пока ему некуда складывать данные, не с кем общаться по сети, пока его логи неуправляемы, а аппетит к памяти и CPU ничем не ограничен. Этот урок про то, как Docker подключает хранилище, строит сети, собирает логи и режет ресурсы через cgroups v2. Это ровно та часть, где админ перестаёт играть и начинает эксплуатировать.

Изображение

Как это работает

Слой записи контейнера эфемерный: удалили контейнер - потеряли всё, что он туда нагенерил. Чтобы данные пережили перезапуск, их выносят наружу. Есть два механизма. Том (volume) - это каталог, которым управляет сам Docker внутри /var/lib/docker/volumes, с собственным жизненным циклом. Bind mount - это когда вы напрямую подсовываете контейнеру конкретный путь хоста. Том переносимый и не зависит от структуры хоста, поэтому для данных приложений рекомендуют именно его. Bind mount удобен, когда нужно дать контейнеру реальный файл хоста (конфиг, сокет, исходники при разработке), но он жёстко привязан к ФС хоста и легко ломает изоляцию.

Сеть в Docker построена на драйверах. По умолчанию контейнеры попадают в bridge - программный коммутатор docker0, за которым стоит NAT через nftables (в современных ядрах iptables-команды Docker транслируются в nft, legacy-таблицы это наследие). Драйвер host убирает сетевую изоляцию вообще: контейнер делит сетевой стек с хостом, публикация портов не нужна и не работает. Драйвер none даёт только loopback - полная изоляция. Overlay соединяет контейнеры на разных хостах в один L2-сегмент поверх VXLAN, это основа Swarm. Пользовательский bridge отличается от дефолтного тем, что в нём работает встроенный DNS по именам контейнеров - это важно, дефолтный bridge резолвинг по имени не даёт.

Публикация порта (-p 8080:80) ставит правило DNAT: трафик на порт 8080 хоста перенаправляется на порт 80 внутри контейнера. Без публикации порт виден только внутри сети Docker, наружу хоста его нет.

Логи контейнера - это то, что процесс пишет в stdout и stderr. Перехватывает их драйвер логирования. По умолчанию это json-file: построчный JSON в /var/lib/docker/containers. Беда дефолта в том, что без настройки ротации он растёт безгранично и однажды забивает диск. На 2026 год для одиночных хостов рекомендуют драйвер local - бинарный сжатый формат с включённой по умолчанию ротацией. json-file оставлен дефолтом ради совместимости и потому, что его парсят сборщики логов Kubernetes. Драйверы вроде journald, syslog, fluentd отдают логи во внешние системы. Важно: docker logs работает только с json-file, local и journald.

Ограничение ресурсов опирается на cgroups v2 - единую иерархию ядра, которой через драйвер systemd управляет Docker. На Debian 13, Ubuntu 24.04, RHEL 10 и Fedora 41+ v2 включена из коробки, а драйвер cgroup по умолчанию systemd. Флаг --memory ставит жёсткий потолок памяти (cgroup memory.max): превысил - процесс убивает OOM-killer ядра. Флаг --cpus задаёт долю процессорного времени (через cpu.max, он же CPUQuota у systemd): --cpus=1.5 это полтора ядра. Это не привязка к конкретным ядрам, а квота времени на период.

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

Тома и bind mount. Современный синтаксис --mount явный и предпочтительнее старого -v:

Код: Выделить всё

docker volume create appdata
docker run -d --name db \
  --mount type=volume,src=appdata,dst=/var/lib/postgresql/data \
  postgres:17

# bind mount каталога хоста, только чтение
docker run --rm \
  --mount type=bind,src=/etc/myapp,dst=/etc/myapp,ro \
  alpine cat /etc/myapp/config.yml

docker volume ls
docker volume inspect appdata
docker volume rm appdata
Сети. Пользовательский bridge с DNS по именам:

Код: Выделить всё

docker network create --driver bridge backend
docker run -d --name redis --network backend redis:7
docker run --rm --network backend alpine ping -c1 redis   # резолвится по имени

docker network ls
docker network inspect backend
docker run -d --network host nginx        # стек хоста, -p игнорируется
docker run --rm --network none alpine ip a # только lo
Логирование. Установка драйвера local с ротацией для одного контейнера и глобально:

Код: Выделить всё

docker run -d --name app \
  --log-driver local \
  --log-opt max-size=10m --log-opt max-file=3 \
  myapp:latest
Глобальный дефолт в /etc/docker/daemon.json (путь одинаков в Debian/Ubuntu и RHEL/Fedora):

Код: Выделить всё

{
  "log-driver": "local",
  "log-opts": { "max-size": "10m", "max-file": "5" }
}
После правки перезапускаем демон. Debian/Ubuntu и RHEL/Fedora тут не различаются, всё через systemd:

Код: Выделить всё

sudo systemctl restart docker
docker info --format '{{.LoggingDriver}}'
Ресурсы. Лимиты памяти и CPU, проверка через cgroup:

Код: Выделить всё

docker run -d --name limited \
  --memory 512m --memory-swap 512m \
  --cpus 1.5 \
  nginx

docker stats limited --no-stream
docker info | grep -i cgroup          # Cgroup Version: 2, Driver: systemd
cat /sys/fs/cgroup/system.slice/docker-*.scope/memory.max
Проверить версию и драйвер cgroup на хосте можно и так:

Код: Выделить всё

stat -fc %T /sys/fs/cgroup/       # cgroup2fs = v2
Очистка и обслуживание. Здесь легко отстрелить нужное, поэтому осторожно:

Код: Выделить всё

docker system df                  # сколько занято образами, томами, кэшем
docker container prune            # удалить остановленные контейнеры
docker image prune -a             # все образы без контейнеров
docker volume prune               # ОСТОРОЖНО: висячие тома, это данные
docker builder prune              # кэш сборки
docker system prune -a --volumes  # снести всё лишнее разом
Частые грабли
  • json-file без max-size забивает диск под ноль, и узнаёшь об этом, когда демон уже не стартует. Ставьте ротацию глобально в daemon.json, по контейнеру задним числом не применится.
  • docker volume prune и тем более system prune --volumes сносят данные без подтверждения по имени. Один лишний ключ - и базы нет.
  • Дефолтный bridge не резолвит контейнеры по имени. Завязались на --link (он deprecated) - переходите на пользовательскую сеть.
  • --memory-swap по умолчанию равен удвоенному --memory, то есть своп всё равно доступен. Чтобы реально запретить своп, явно ставьте --memory-swap равным --memory.
  • Лимиты применились, а контейнер их не видит изнутри (free, nproc показывают хост). Это нормально: cgroup ограничивает, но не подменяет /proc. JVM и Node до сих пор иногда читают хостовую память - проверяйте флаги рантайма.
  • На старом ядре с cgroup v1 часть лимитов v2 (например memory.max swap) ведёт себя иначе. Сверяйтесь с docker info, не полагайтесь на привычки.
  • host-сеть несовместима с -p и убивает изоляцию портов: контейнер занимает порты хоста напрямую, конфликты гарантированы.
Мини-лаба
  • Создайте том appdata и пользовательскую сеть backend.
  • Запустите postgres:17 с томом на /var/lib/postgresql/data, в сети backend, с лимитами --memory 512m --cpus 1.0 и драйвером логов local.
  • Подключите второй контейнер (alpine) в backend и пингуйте postgres по имени - убедитесь, что DNS работает.
  • Нагрузите контейнер и посмотрите docker stats: упирается ли он в заданный потолок CPU.
  • Проверьте memory.max контейнера в /sys/fs/cgroup и сравните с заданным лимитом.
  • Удалите контейнер postgres, создайте заново на тот же том - данные должны быть на месте.
  • Прогоните docker system df, затем docker container prune и docker image prune. Том appdata не трогайте.
Контрольные вопросы
  • Чем volume отличается от bind mount по жизненному циклу и переносимости, и какой когда выбирать?
  • Почему контейнеры в пользовательском bridge видят друг друга по имени, а в дефолтном bridge - нет?
  • Что делает -p 8080:80 на уровне ядра и почему этот ключ бессмысленен при --network host?
  • Почему драйвер local в 2026 предпочтительнее json-file и в чём подвох дефолта?
  • Как --cpus=1.5 и --memory=512m отображаются на cgroup v2, и что произойдёт при превышении памяти?
  • Чем опасен docker system prune --volumes и как чистить безопасно?
👍3 ❤️2 🔥1 😄 🤔3
Аватара пользователя
nadjib
Сообщения: 1
Зарегистрирован: 02 июн 2026, 03:39

Re: Docker: тома, сети, логирование, ресурсы [352.3, часть 2]

Сообщение nadjib »

А если на bridge-сети контейнер резолвит соседа по имени, а в дефолтной нет - это значит --link реально можно выкидывать совсем? у меня пол-компоуза на нём держится
👍2 ❤️1 🔥 😄 🤔1
Аватара пользователя
Playa5k
Сообщения: 1
Зарегистрирован: 31 май 2026, 11:10

Re: Docker: тома, сети, логирование, ресурсы [352.3, часть 2]

Сообщение Playa5k »

поймал ровно граблю с json-file: за выходные nginx налогировал 40 гигов и docker не стартанул. поставил local + max-size 10m в daemon.json, перезапустил демон, полёт нормальный
👍2 ❤️ 🔥1 😄 🤔
Ответить
← Предыдущая глава
Docker: образы и контейнеры [352.3, часть 1]
Следующая глава →
Оркестрация контейнеров

Все главы курса «LPIC-3 305: виртуализация и контейнеризация»

Поделиться темой: ✈ Telegram VK

Вернуться в «LPIC-3 305: виртуализация и контейнеры»

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и 0 гостей