cgroups (Control Groups) ermöglichen die Kontrolle von Ressourcen für Prozessgruppen unter Linux. Sie sind die Grundlage für Container-Technologien wie Docker.
Grundlagen
cgroups v1 vs v2
| Feature | v1 | v2 |
|---|
| Hierarchie | Mehrere | Eine einheitliche |
| Struktur | Pro Controller | Vereinheitlicht |
| Standard | Älter | Modern (ab Kernel 4.5) |
Version prüfen
# v2 wenn unified
mount | grep cgroup
# Oder
cat /proc/filesystems | grep cgroup
Verfügbare Controller
# cgroups v2
cat /sys/fs/cgroup/cgroup.controllers
# Ausgabe: cpu io memory pids
cgroups v2 - Systemd
Slice-Hierarchie
# Struktur anzeigen
systemd-cgls
# Ausgabe:
# ├─user.slice
# │ └─user-1000.slice
# │ └─session-1.scope
# ├─system.slice
# │ ├─nginx.service
# │ └─mysql.service
# └─init.scope
Service-Limits mit Systemd
# /etc/systemd/system/myapp.service.d/limits.conf
[Service]
# CPU: 50% eines Cores
CPUQuota=50%
# Memory: Max 1GB
MemoryMax=1G
MemoryHigh=800M
# I/O: Gewichtung
IOWeight=50
# Prozesse: Max 100
TasksMax=100
systemctl daemon-reload
systemctl restart myapp
Temporäre Limits
# CPU-Limit setzen
systemctl set-property myapp.service CPUQuota=25%
# Memory-Limit setzen
systemctl set-property myapp.service MemoryMax=512M
# Permanent (--runtime für temporär)
systemctl set-property --runtime myapp.service CPUQuota=25%
Limits anzeigen
# Service-Limits
systemctl show myapp.service | grep -E "(CPU|Memory|IO|Tasks)"
# cgroup-Pfad
systemctl show -p ControlGroup myapp.service
Manuelle cgroups v2
cgroup erstellen
# Verzeichnis erstellen
mkdir /sys/fs/cgroup/mygroup
# Controller aktivieren
echo "+cpu +memory +io +pids" > /sys/fs/cgroup/cgroup.subtree_control
CPU-Limits
# CPU-Bandwidth (Quota/Period)
# 50% CPU = 50000/100000
echo "50000 100000" > /sys/fs/cgroup/mygroup/cpu.max
# CPU-Gewichtung (1-10000, default 100)
echo 50 > /sys/fs/cgroup/mygroup/cpu.weight
Memory-Limits
# Max Memory (Hard Limit)
echo 1073741824 > /sys/fs/cgroup/mygroup/memory.max # 1GB
# High Memory (Soft Limit - Drosselung)
echo 805306368 > /sys/fs/cgroup/mygroup/memory.high # 768MB
# Swap-Limit
echo 0 > /sys/fs/cgroup/mygroup/memory.swap.max
# Aktuelle Nutzung
cat /sys/fs/cgroup/mygroup/memory.current
I/O-Limits
# Device-Nummern finden
lsblk -o NAME,MAJ:MIN
# Read-Limit (Bytes/s) - z.B. 8:0 für /dev/sda
echo "8:0 rbps=10485760" > /sys/fs/cgroup/mygroup/io.max # 10MB/s
# Write-Limit
echo "8:0 wbps=5242880" > /sys/fs/cgroup/mygroup/io.max # 5MB/s
# IOPS-Limit
echo "8:0 riops=1000 wiops=500" > /sys/fs/cgroup/mygroup/io.max
Prozess-Limits
# Max Prozesse/Threads
echo 50 > /sys/fs/cgroup/mygroup/pids.max
# Aktuelle Anzahl
cat /sys/fs/cgroup/mygroup/pids.current
Prozess zuweisen
# PID zuweisen
echo $PID > /sys/fs/cgroup/mygroup/cgroup.procs
# Prozess mit cgroup starten
cgexec -g cpu,memory:mygroup command
# Oder mit systemd-run
systemd-run --scope -p MemoryMax=500M command
Praktische Beispiele
Datenbank-Server begrenzen
# /etc/systemd/system/mysql.service.d/limits.conf
[Service]
# 4 CPU-Cores
CPUQuota=400%
# 8GB RAM
MemoryMax=8G
MemoryHigh=7G
# Keine Swap-Nutzung
MemorySwapMax=0
# I/O-Priorität
IOWeight=200
Web-Worker begrenzen
# /etc/systemd/system/php-fpm.service.d/limits.conf
[Service]
# 2 CPU-Cores
CPUQuota=200%
# 2GB RAM
MemoryMax=2G
# Max 100 Prozesse
TasksMax=100
Batch-Job limitieren
#!/bin/bash
# batch-job.sh
# Eigene cgroup erstellen
CGROUP="/sys/fs/cgroup/batch-$$"
mkdir -p $CGROUP
# Limits setzen
echo "25000 100000" > $CGROUP/cpu.max # 25% CPU
echo 536870912 > $CGROUP/memory.max # 512MB RAM
# Prozess zuweisen
echo $$ > $CGROUP/cgroup.procs
# Job ausführen
./heavy-task.sh
# Aufräumen
rmdir $CGROUP
Monitoring
cgroup-Statistiken
# CPU-Statistiken
cat /sys/fs/cgroup/mygroup/cpu.stat
# Memory-Statistiken
cat /sys/fs/cgroup/mygroup/memory.stat
# I/O-Statistiken
cat /sys/fs/cgroup/mygroup/io.stat
# Pressure (PSI)
cat /sys/fs/cgroup/mygroup/cpu.pressure
cat /sys/fs/cgroup/mygroup/memory.pressure
cat /sys/fs/cgroup/mygroup/io.pressure
systemd-cgtop
# Echtzeit-Monitoring
systemd-cgtop
# Sortierung ändern (während Lauf: c=CPU, m=Memory, i=I/O)
# Installation
apt install cgroup-tools
# Werte lesen
cgget -g cpu,memory /mygroup
Container-Nutzung
Docker-Limits
# CPU-Limit
docker run --cpus=2 --memory=1g myimage
# CPU-Shares (relative Gewichtung)
docker run --cpu-shares=512 myimage
# Memory mit Swap
docker run --memory=1g --memory-swap=2g myimage
LXC/LXD-Limits
# CPU
lxc config set container limits.cpu 2
# Memory
lxc config set container limits.memory 1GB
Zusammenfassung
| Controller | Datei | Beschreibung |
|---|
| cpu | cpu.max | CPU-Quota |
| cpu | cpu.weight | CPU-Gewichtung |
| memory | memory.max | Hartes Limit |
| memory | memory.high | Weiches Limit |
| io | io.max | I/O-Bandbreite |
| pids | pids.max | Prozess-Limit |
| Systemd-Option | Beschreibung |
|---|
| CPUQuota | CPU-Prozent |
| MemoryMax | RAM-Limit |
| MemoryHigh | RAM-Soft-Limit |
| IOWeight | I/O-Priorität |
| TasksMax | Prozess-Limit |
| Befehl | Funktion |
|---|
| systemd-cgls | Hierarchie anzeigen |
| systemd-cgtop | Echtzeit-Monitor |
| systemctl set-property | Limits setzen |
| cgexec | Prozess mit cgroup starten |
Fazit
cgroups sind fundamental für Ressourcen-Kontrolle unter Linux. Systemd vereinfacht die Nutzung erheblich. Container nutzen cgroups für Isolation. Für produktive Systeme sollten kritische Services Limits haben. Memory-Limits verhindern OOM-Probleme.