## Введение
В современном мире контейнеризации и виртуализации эффективное управление ресурсами системы становится критически важным. В Linux для этого существует механизм под названием **cgroups** (control groups) — подсистема ядра, которая позволяет группировать процессы и управлять ресурсами, выделяемыми этим группам. Docker активно использует cgroups для ограничения и контроля ресурсов контейнеров.
Подробнее о Docker и управлении ресурсами можно прочитать в заметке [[Resource management in Docker]].
---
## Что такое cgroups?
**cgroups** — это механизм ядра Linux, который позволяет: ^WBQpB4KR
- Группировать процессы в иерархические группы.
- Ограничивать и контролировать использование ресурсов (CPU, память, диск, сеть и др.) для каждой группы.
- Отслеживать статистику использования ресурсов.
- Приоритизировать доступ к ресурсам.
Это особенно полезно для контейнеров, где нужно гарантировать, что один контейнер не "захватит" все ресурсы хоста, нарушая работу других.
---
## Основные подсистемы cgroups
Каждая подсистема (subsystem) отвечает за управление определённым типом ресурсов:
| Подсистема | Управляемый ресурс |
|------------|-----------------------------|
| cpu | CPU shares, квоты |
| cpuset | Привязка процессов к ядрам |
| memory | Ограничение памяти и swap |
| blkio | Ограничение скорости диска |
| devices | Контроль доступа к устройствам|
| net_cls | Классификация сетевого трафика|
Подробнее о подсистемах и их настройках можно узнать в [[Resource management in Docker]].
---
## Как работают cgroups в системе с systemd
На современных системах с systemd каждый процесс помещается в дерево cgroups. Можно увидеть структуру cgroups и процессы в них с помощью команды:
```bash
systemd-cgls
```
Пример вывода:
```
├─1 /usr/lib/systemd/systemd --switched-root --system --deserialize 22
├─system.slice
│ ├─docker-4be96b853089bc6044b29cb873cac460b429cfcbdd0e877c0868eb2a901dbf80.scope
│ │ ├─12345 /usr/bin/mycontainerprocess
```
Здесь видно, что процессы Docker-контейнера находятся в отдельном cgroup.
---
## Примеры управления ресурсами с помощью cgroups
### 1. Ограничение CPU с помощью Docker
Docker использует cgroups для управления CPU через параметр `--cpu-shares` (относительный вес) и `--cpuset-cpus` (привязка к ядрам).
Пример запуска контейнера с ограничением CPU:
```bash
# Запуск контейнера с 512 CPU shares (по умолчанию 1024)
docker run -it --rm -c 512 stress --cpu 4
# Привязка контейнера к первому и второму ядрам
docker run -it --rm --cpuset-cpus="0,1" stress --cpu 2
```
Подробнее о CPU ограничениях в [[Resource management in Docker]].
### 2. Ограничение памяти
По умолчанию контейнер может использовать всю память хоста. Чтобы ограничить память, используйте параметр `-m`:
```bash
docker run -it --rm -m 128m stress --vm 1 --vm-bytes 128M --vm-hang 0
```
Этот контейнер не сможет использовать больше 128 МБ памяти.
### 3. Ограничение скорости записи на диск
Docker не предоставляет прямых опций для ограничения скорости диска, но cgroups и systemd позволяют это сделать через свойства `BlockIO*`.
Пример ограничения скорости записи:
```bash
# Найдите устройство, на котором смонтирована файловая система контейнера
docker exec <container_id> mount | head -1
# Ограничьте скорость записи до 10MB/s для контейнера
sudo systemctl set-property --runtime docker-<container_id>.scope "BlockIOWriteBandwidth=/dev/mapper/your-device 10M"
```
Подробнее о блокировке дисковых ресурсов — в [[Resource management in Docker]].
---
## Работа с cgroups напрямую через файловую систему
Информация и настройки cgroups доступны в виртуальной файловой системе `/sys/fs/cgroup/`.
Пример просмотра CPU shares для контейнера:
```bash
cat /sys/fs/cgroup/cpu/system.slice/docker-<container_id>.scope/cpu.shares
```
Изменение CPU shares (например, на 512):
```bash
echo 512 | sudo tee /sys/fs/cgroup/cpu/system.slice/docker-<container_id>.scope/cpu.shares
```
---
## Использование systemd для управления cgroups
Поскольку systemd управляет cgroups, можно использовать `systemctl` для изменения свойств в реальном времени:
```bash
sudo systemctl set-property docker-<container_id>.scope CPUShares=512
```
Добавьте `--runtime` для временного изменения (до перезагрузки):
```bash
sudo systemctl set-property --runtime docker-<container_id>.scope CPUShares=512
```
---
## Мониторинг использования ресурсов cgroups
Для быстрого просмотра использования ресурсов cgroups можно использовать:
```bash
systemd-cgtop
```
Вывод покажет, сколько CPU, памяти и ввода/вывода используют группы процессов.
---
## Важные моменты
- CPU shares — это относительный вес, а не жёсткое ограничение по частоте.
- Ограничения памяти включают swap, который по умолчанию равен размеру памяти.
- Ограничение дискового пространства (квоты) для контейнеров пока не реализовано в Docker.
- Инструменты вроде `top` внутри контейнера не показывают ограничения cgroups, так как они не cgroups-aware.
---
## Где находятся файлы cgroups для Docker
Файлы cgroups расположены в виртуальной файловой системе, обычно по пути:
```
/sys/fs/cgroup/
```
Внутри этой директории есть поддиректории для каждой подсистемы (cpu, memory, blkio и др.) и дальше — для каждой группы процессов (scope), например:
```
/sys/fs/cgroup/cpu/system.slice/docker-<container_id>.scope/
/sys/fs/cgroup/memory/system.slice/docker-<container_id>.scope/
/sys/fs/cgroup/blkio/system.slice/docker-<container_id>.scope/
```
В этих директориях находятся файлы, управляющие ресурсами и показывающие статистику:
- `tasks` — список PID процессов в группе
- `cgroup.procs` — тоже список PID процессов
- `cpu.shares` — вес CPU для группы
- `memory.limit_in_bytes` — лимит памяти
- `memory.usage_in_bytes` — текущее использование памяти
- `blkio.throttle.write_bps_device` — ограничение скорости записи на диск
- и другие файлы для мониторинга и управления
---
## Типовые скрипты для мониторинга cgroups Docker
### 1. Просмотр процессов в cgroup контейнера
```bash
CONTAINER_ID=<container_id>
cat /sys/fs/cgroup/cpu/system.slice/docker-$CONTAINER_ID.scope/tasks
```
Выведет список PID процессов, запущенных в контейнере.
---
### 2. Мониторинг использования CPU и памяти контейнером
```bash
CONTAINER_ID=<container_id>
echo "CPU shares:"
cat /sys/fs/cgroup/cpu/system.slice/docker-$CONTAINER_ID.scope/cpu.shares
echo "Memory limit (bytes):"
cat /sys/fs/cgroup/memory/system.slice/docker-$CONTAINER_ID.scope/memory.limit_in_bytes
echo "Memory usage (bytes):"
cat /sys/fs/cgroup/memory/system.slice/docker-$CONTAINER_ID.scope/memory.usage_in_bytes
```
---
### 3. Скрипт для вывода текущего использования ресурсов всех контейнеров
```bash
#!/bin/bash
for scope in /sys/fs/cgroup/cpu/system.slice/docker-*.scope; do
CONTAINER=$(basename $scope | sed 's/docker-//;s/.scope//')
CPU_SHARES=$(cat $scope/cpu.shares)
MEM_USAGE=$(cat /sys/fs/cgroup/memory/system.slice/docker-$CONTAINER.scope/memory.usage_in_bytes)
MEM_LIMIT=$(cat /sys/fs/cgroup/memory/system.slice/docker-$CONTAINER.scope/memory.limit_in_bytes)
echo "Container: $CONTAINER"
echo " CPU shares: $CPU_SHARES"
echo " Memory usage: $MEM_USAGE bytes"
echo " Memory limit: $MEM_LIMIT bytes"
echo
done
```
---
### 4. Ограничение CPU и памяти для запущенного контейнера через systemd
```bash
CONTAINER_ID=<container_id>
# Ограничить CPU shares до 512
sudo systemctl set-property docker-$CONTAINER_ID.scope CPUShares=512
# Ограничить память до 256MB
sudo systemctl set-property docker-$CONTAINER_ID.scope MemoryLimit=256M
```
---
## Как устроена система cgroups
- **Иерархия cgroups:** cgroups организованы в виде дерева. Каждый процесс принадлежит к одной или нескольким cgroups (по разным подсистемам).
- **Подсистемы (controllers):** Каждая подсистема отвечает за управление определённым ресурсом (CPU, память, диск и т.д.).
- **Файловая система cgroups:** Через виртуальную файловую систему `/sys/fs/cgroup/` можно читать и изменять параметры cgroups.
- **Интеграция с systemd:** systemd создаёт и управляет cgroups для сервисов и контейнеров, что упрощает управление ресурсами.
---
Если хотите, могу помочь с конкретными примерами или настройками под ваши задачи!
---
Так документ станет удобнее для навигации и изучения связанных тем.
---