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)

Mit cgget (cgroup-tools)

# 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.