Eine Erkenntnis aus der Untersuchung der Stabilitätsprobleme war, dass Docker-Container beliebig viel Arbeitsspeicher beanspruchen und (vermutlich auf Grund der hohen Berechtigung mit der Docker läuft) damit das System in den Abgrund reißen können. Normalerweise kenne ich es so, dass zu speicherhungrige Programme vom System getötet werden, bevor sie die Stabilität gefährden.
Docker bietet die Möglichkeit, für jeden Container individuelle Ressourcen-Limits festzulegen. Dies
kann die Rechenzeit betreffen, aber eben auch den Arbeitsspeicher. Dazu wird in der
docker-compose.yaml
ein Abschnitt deploy
eingefügt
(siehe auch hier). Ein Beispiel:
services: app: image: ... ports: ... volumes: ... deploy: resources: limits: memory: 256M
Hier wird für den Container mit Namen app
ein Limit von 256 MB Arbeitsspeicher festgelegt.
Mehr sieht dieser Container nicht, d.h. auch die Menge an Arbeitsspeicher, der für Buffers und Caches
der Prozesse innerhalb dieses Containers aufgewendet wird, ist dadurch nach oben hin begrenzt.
Ich hätte nun den verfügbaren Arbeitsspeicher von ca. 950 MB einfach durch die Anzahl der Dienste teilen und jedem seinen Anteil zukommen lassen können. Dies hätte aber den Nachteil, dass jedes gesparte Megabyte "verloren" wäre, weil die anderen Dienste es nicht nutzen könnten. Stattdessen habe ich die einzelnen Dienste genau beobachtet und mir plausible Limits überlegt, die einerseits dem Bedarf der Dienste gerecht werden, andererseits aber ein Davonlaufen verhindern. Mein Gedanke: wenn ich z.B. insgesamt 1200 MB "austeile", aber kein Dienst mehr als 400 MB für sich selbst beanspruchen kann, ist das System vor einem einzelnen Amokläufer sicher und könnte zwei gleichzeitig durchgehende Container evtl. auch noch überleben.
In der Praxis hat sich gezeigt, dass ein Container, der viel Arbeitsspeicher zur Verfügung hat, auch viel beansprucht. Insbesondere filebrowser scheint nahezu beliebig viel Speicher zu konsumieren, allerdings eher im Sinne von Caching; ich konnte in der Bedienbarkeit keinen nennenswerten Unterschied feststellen zwischen einem Limit von 250 MB und einem Limit von 400 MB.
Die festgelegten Grenzen sieht man auch in der Anzeige von docker stats
:
CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS 69aeba43d2cc linkding-app-1 0.02% 57.33MiB / 256MiB 22.40% 84.3kB / 1.34kB 4.81MB / 4.1kB 7 29201395c135 mosquitto-app-1 0.13% 1.438MiB / 8MiB 17.97% 42.4MB / 29.2MB 897kB / 0B 1
Die kleinste Menge, die als Limit angegeben werden kann, beträgt übrigens 6 MB und wäre für
mosquitto
wahrscheinlich immer noch genug.
Hinweis: damit das hier beschriebene Docker-Feature funktioniert muss eine Funktion des
Linux-Kernels aktiviert werden, die beim Raspberry Pi OS per Default nicht aktiv ist. Dazu editiert man die
Datei /boot/cmdline.txt
und fügt die Anweisung cgroup_enable=memory
hinzu.