### A note on resource reporting tools The tools you are used to using to report usage like `top`, `/proc/meminfo` and so on **are not cgroups aware**. This means that they’ll report the information about the host even if we run them inside of a container. I found a [nice blog post](http://fabiokung.com/2014/03/13/memory-inside-linux-containers/) from Fabio Kung on this topic. Give it a read. So, what can we do? If you want to quickly find which container (or any systemd service, really) uses the most resources on the host I recommend the `systemd-cgtop` command: systemd-cgtop [OPTIONS...] [CGROUP] Show top control groups by their resource usage. `-h --help Show this help` `--version Show package version` `-p --order=path Order by path` `-t --order=tasks Order by number of tasks/processes` `-c --order=cpu Order by CPU load (default)` `-m --order=memory Order by memory load` `-i --order=io Order by IO load` `-r --raw Provide raw (not human-readable) numbers` `--cpu=percentage Show CPU usage as percentage (default)` `--cpu=time Show CPU usage as time` `-P Count userspace processes instead of tasks (excl. kernel)` `-k Count all processes instead of tasks (incl. kernel)` `--recursive=BOOL Sum up process count recursively` `-d --delay=DELAY Delay between updates` `-n --iterations=N Run for N iterations before exiting` `-1 Shortcut for --iterations=1` `-b --batch Run in batch mode, accepting no input` `--depth=DEPTH Maximum traversal depth (default: 3)` `-M --machine= Show container` ![[Pasted image 20251111194234.png]] Отличный вопрос 👇 `systemd-cgtop` — это **утилита мониторинга**, которая показывает **использование ресурсов (CPU, память, I/O, задачи)** в реальном времени по _control groups (cgroups)_, то есть по **юнитам systemd, контейнерам, сервисам и процессам**. --- ## 🧩 Что такое `systemd-cgtop` - Это аналог `top`, но не для отдельных процессов, а для **групп процессов**, которыми управляет **systemd**. - Каждая строка в выводе — это **cgroup**: например, контейнер Docker, сервис systemd, юнит `.scope`, пользовательская сессия и т.д. --- ## 📊 Пример вывода ```bash $ systemd-cgtop Path Tasks %CPU Memory Input/s Output/s / 327 5.0 1.2G /user.slice 89 2.0 500M /system.slice 220 3.0 700M /docker-45ea2142f956c5127ef4f87e8d7bf78db830abb355d1d220644bf40efd95fdf6.scope 6 15.0 250M ``` ### Поля: | Поле | Значение | | --------------------- | ------------------------------------------------------------------------ | | **Path** | Имя _cgroup_, обычно совпадает с сервисом, контейнером или пользователем | | **Tasks** | Количество процессов (или потоков) в группе | | **%CPU** | Доля CPU, потребляемая всеми процессами этой группы | | **Memory** | Используемая память | | **Input/s, Output/s** | Скорость чтения/записи данных (в байтах/с) | --- ## ⚙️ Примеры использования ### 🔹 Обычный просмотр: ```bash systemd-cgtop ``` ### 🔹 Обновление каждые 2 секунды: ```bash systemd-cgtop --delay=2s ``` ### 🔹 Показать только активные группы: ```bash systemd-cgtop --hide-unmoved ``` ### 🔹 Показать больше процессов (не только 10 по умолчанию): ```bash systemd-cgtop -n 0 ``` --- ## 🐳 В контексте Docker Когда ты видишь такие строки: ``` docker-45ea2142f956c5127ef4f87e8d7bf78db830abb355d1d220644bf40efd95fdf6.scope ``` — это конкретный **контейнер Docker**, который systemd отслеживает как отдельную _scope-группу_. В `systemd-cgtop` ты можешь увидеть: - сколько CPU он потребляет, - сколько оперативки занимает, - сколько процессов в контейнере, - и его I/O-активность. --- ## 💡 Применение в DevOps `systemd-cgtop` полезен для: - наблюдения за нагрузкой контейнеров и сервисов; - отладки runaway-процессов; - проверки ограничений ресурсов (`CPUQuota`, `MemoryMax`); - диагностики проблем в Docker, Podman, LXC, systemd-nspawn и т.д. --- Хочешь, я покажу, как с помощью `systemd-cgtop` можно _в реальном времени отследить_, какой контейнер потребляет больше всего CPU и памяти, с автоматическим логированием в файл? Отлично. Ниже — готовые варианты, как **в реальном времени** смотреть, какой контейнер жрёт больше CPU/памяти, и **логировать это в файл**. --- # Вариант A — быстрый просмотр Top-N контейнеров (без логов) **CPU (топ-5):** ```bash watch -n 1 'systemd-cgtop -b -n1 | { read h; read h2; printf "%s\n%s\n" "$h" "$h2"; grep docker- | sort -k3,3 -hr | head -5; }' ``` **Память (топ-5):** ```bash watch -n 1 'systemd-cgtop -b -n1 | { read h; read h2; printf "%s\n%s\n" "$h" "$h2"; grep docker- | awk "NR>0{print}" | sort -k4,4 -hr | head -5; }' ``` > Пояснение: `systemd-cgtop -b -n1` — один «снимок» в batch-режиме, `grep docker-` — только контейнеры (`*.scope`), `sort -h` — «человеческая» сортировка по столбцу `%CPU` (3-й) или `Memory` (4-й). --- # Вариант B — простой **логер** в CSV (каждую секунду) Создаст файл `cgtop-docker.csv` с колонками: `timestamp,path,tasks,cpu_percent,memory` ```bash #!/usr/bin/env bash set -euo pipefail LOG="cgtop-docker.csv" INTERVAL="1s" # Заголовок (если файла нет) [ -f "$LOG" ] || echo "timestamp,path,tasks,cpu_percent,memory" > "$LOG" while :; do TS="$(date -Is)" # Один срез cgtop systemd-cgtop --batch --iterations=1 --delay="$INTERVAL" \ | awk -v ts="$TS" ' NR<=2 { next } # пропускаем 2 строки заголовка $1 ~ /^docker-.*\.scope$/ { # только docker *.scope # Ожидаемый формат столбцов: # Path Tasks %CPU Memory Input/s Output/s path=$1; tasks=$2; cpu=$3; mem=$4; gsub(/%/,"",cpu); # убираем символ % print ts "," path "," tasks "," cpu "," mem }' >> "$LOG" done ``` Запуск: ```bash chmod +x ./cgtop-logger.sh sudo ./cgtop-logger.sh ``` Остановить: `Ctrl+C`. Посмотреть «топ по CPU» за последние 200 строк: ```bash tail -n 200 cgtop-docker.csv | sort -t, -k4,4nr | head ``` --- # Вариант C — логер + сводка «кто лидер сейчас» Этот скрипт на каждом шаге печатает две строки-сводки: **TOPCPU** и **TOPMEM**. ```bash #!/usr/bin/env bash set -euo pipefail LOG_RAW="cgtop-docker.csv" LOG_SUMMARY="cgtop-summary.log" INTERVAL="1s" [ -f "$LOG_RAW" ] || echo "timestamp,path,tasks,cpu_percent,memory" > "$LOG_RAW" while :; do TS="$(date -Is)" systemd-cgtop --batch --iterations=1 --delay="$INTERVAL" \ | awk -v ts="$TS" -v raw="$LOG_RAW" -v sum="$LOG_SUMMARY" ' BEGIN { maxcpu = -1; maxcpupath = ""; maxmem = -1; maxmempath = ""; } NR<=2 { next } $1 ~ /^docker-.*\.scope$/ { path=$1; tasks=$2; cpu=$3; mem=$4; # лог сырого CSV cpu_pct=cpu; gsub(/%/,"",cpu_pct); print ts "," path "," tasks "," cpu_pct "," mem >> raw; # CPU лидер cpu_num=cpu_pct+0; if (cpu_num > maxcpu) { maxcpu=cpu_num; maxcpupath=path } # нормализуем память в MiB mem_s=mem; unit_tol=tolower(mem_s); gsub(/[^0-9.]/,"",mem_s); mem_val=mem_s+0; if (unit_tol ~ /g/) mem_mib=mem_val*1024; else if (unit_tol ~ /m/) mem_mib=mem_val; else if (unit_tol ~ /k/) mem_mib=mem_val/1024; else mem_mib=mem_val; # fallback if (mem_mib > maxmem) { maxmem=mem_mib; maxmempath=path } } END { if (maxcpupath != "") printf("%s TOPCPU %s %.2f%%\n", ts, maxcpupath, maxcpu) >> sum; if (maxmempath != "") printf("%s TOPMEM %s %.2f MiB\n", ts, maxmempath, maxmem) >> sum; }' done ``` Просмотр сводки: ```bash tail -f cgtop-summary.log ``` --- # Вариант D — как сервис systemd (фон, автозапуск) `/etc/systemd/system/cgtop-logger.service` ```ini [Unit] Description=Log Docker cgroups via systemd-cgtop After=network.target docker.service [Service] Type=simple ExecStart=/usr/local/bin/cgtop-logger.sh Restart=always RestartSec=2s Nice=10 IOSchedulingClass=best-effort IOSchedulingPriority=7 [Install] WantedBy=multi-user.target ``` Положите скрипт в `/usr/local/bin/cgtop-logger.sh`, сделайте исполняемым. Далее: ```bash sudo systemctl daemon-reload sudo systemctl enable --now cgtop-logger.service sudo journalctl -u cgtop-logger.service -f ``` (Опционально — сделать `*.timer`, если нужен периодический запуск.) --- ## Полезные замечания - Колонки `systemd-cgtop` могут слегка отличаться между версиями systemd (но порядок `Path Tasks %CPU Memory ...` стабилен). - Если у вас **cgroup v2**, вывод всё равно совместим, скрипты выше работают. - Если контейнеры управляются не Docker, а Podman/k8s-cri, меняется только префикс (`libpod-...scope`, `kubepods-...`), достаточно заменить `grep docker-` на соответствующий паттерн (или убрать фильтр вообще). Если хочешь — подгоню скрипт именно под твой вывод (cgroup v1/v2, суффиксы памяти, нужные интервалы) и добавлю выгрузку в Prometheus-совместимый формат.