Docker Housekeeping Teil 2 - Das RAM

  • Das werde ich wohl in mehreren Schritten schreiben.

    Zu beachten ist, dass meine NAS mit 32GB aufgerüstet ist. Will man das nachspielen, muss die Beispiele etwas anpassen.
    Sollte aber nicht so schwer sein. Die Liste wird später so angelegt: new_list = [True]*3*1024*1024*1024.
    Hat man nur 8GB, dann teilt man einfach durch 4: new_list = [True]*3*1024*1024*256.

    Docker bietet ja eine Möglichkeit Ressourcen zu limitieren. Das kann viel helfen, hat aber auch seine Fallstricke.
    Ich versuche das so aufzuschreiben, dass man es selber nachspielen kann.
    Was braucht man? Einen ssh Zugang auf die UGREEN und ein Python Image. Ich nutze: 3.12.9-alpine3.21

    Im ersten Schritt starte ich den Python Container:

    This image is exclusive to our members!
    Please log in or register for free to view graphics and attachments.

    Dann werfe ich einen Blick auf die Ressourcen meiner NAS:

    This image is exclusive to our members!
    Please log in or register for free to view graphics and attachments.

    Alles ist flauschig.

    Jetzt gehe ich per ssh auf meine NAS und benutze "docker exec" um in meinen Python Container zu kommen.

    Auf der NAS mal ein "docker ps":

    This image is exclusive to our members!
    Please log in or register for free to view graphics and attachments.

    Und nun geht es mit "docker exec -it python-1 sh" in den Container.
    Nach diesem Kommando sollte man ein "#" als prompt bekommen.
    Da rufe ich mal einen "free" auf um zu sehen was ich so habe.
    (Spoiler: free hilft im Container nur begrenzt, später mehr.)

    Danach rufe ich python auf.
    Innerhalb von python kann man dann eine Liste anlegen, die sich viel Speicher greift.

    Der Befehl dazu ist wie folgt:

    new_list = [True]*3*1024*1024*1024

    Und [True] belegt 8Byte im Speicher und ein bisschen Overhead

    Alles zusammen sieht dann so aus.

    This image is exclusive to our members!
    Please log in or register for free to view graphics and attachments.

    Jetzt ein Blick auf den Taskmanager.

    This image is exclusive to our members!
    Please log in or register for free to view graphics and attachments.

    Autsch. Ich hatte doch gerade noch fast 32GB.

    Was wird wohl passieren wenn ich noch mal eine kleinere Liste allokiere?

    Das wären 8GB: new_list_1 = [True]*1*1024*1024*1024

    This image is exclusive to our members!
    Please log in or register for free to view graphics and attachments.

    Dann ein Blick auf den Taskmanager der NAS.

    This image is exclusive to our members!
    Please log in or register for free to view graphics and attachments.

    Da stehen jetzt nur 30GB? Vorher waren es doch 25GB. Da fehlt ja was.
    Erwartet hätte ich 25GB + 8GB = 33GB. Und ich habe ja nur 30GB! Wo ist das hin?
    Einige werden schon befürchten was passiert ist. Das System hat angefangen zu swappen.
    Das ist nicht gut, weil ständig Teile des Rams auf die Festplatte ausgelagert werden.
    Das macht das System nicht wirklich schneller. Und geht auf (u.U.) auf die Lebenszeit der ssd.

    Hier zum Beweis noch ein free im Container

    This image is exclusive to our members!
    Please log in or register for free to view graphics and attachments.

    Hier kann man sehen was ein Container auf einem NAS anrichten kann.
    Und es eine gute Idee ist die Begrenzung der RAM-Nutzung für einen Container zu limitieren.

    Kann man sogar in der Docker APP von Ugreen tun.

    This image is exclusive to our members!
    Please log in or register for free to view graphics and attachments.

    Aber man muss die Kirche im Dorf lassen. Die meisten Container benehmen sich sehr anständig.
    Aber wer hat nicht schon was von den berühmten "memory leaks" gehört?
    Man sollte es einfach kennen.

    Im nächsten Teil zeige ich dann, warum das die Limitierung des Speichers zwar hilfreich ist, aber kein Allheilmittel.
    Es hilft nicht immer und man hat dann neue Probleme :). Die aber nicht so schlimm sind wie das Swappen.

    Edited 10 times, last by wasawasa (February 9, 2025 at 11:22 PM).

  • Vielen Dank für Deinen Beitrag. Sehr interessant!

    Ggf. Wäre das mal ein Ticket an UGREEN wert, um darauf hin zu weisen?

    VG Mike

  • Da kann UGREEN nicht viel machen.
    Das ist einfach eine Eigenschaft von Docker.
    Was man u.U. tun kann ist den Swap komplett aus dem System rauskonfigurieren.
    Bin aber nicht sicher, ob UGREEN das will. Das kann natürlich auch an anderer Stelle Konsequenzen haben.

    Aber bei allen meinen reinen Docker Hosts ist das erst was ich tue den Swap zu deaktivieren.

    Es gibt eine Möglichkeit das Swappverhalten bei Docker zu verbessern, aber es ist nicht wirklich weg.
    Wirklich helfen tut das nur auf Systemebene.

    Man kann das z.B. mit dem Kommando "sudo swapoff -a" erreichen. Aber nur bis zum nächsten reboot.

    Ich denke UGREEN hat sich beim Swap durchaus etwas gedacht. Sie haben den Wert gegenüber dem Default angepasst.
    In der Datei "/etc/sysctl.conf" findet sich ein Parameter "vm.swappiness", der per Default den Wert "60" hat.
    UGREEN hat ihn auf "10" angepasst. Das ist deutlich niedriger.
    Deaktiviert wäre das Swappen, wenn der Wert "0" drin steht.

    Also: Das Kommando "sudo swapoff -a" wirkt bis zum nächsten Reboot. Der Eintrag in die Konfig ist permanent.

    Edited 2 times, last by wasawasa (February 9, 2025 at 8:14 PM).

  • Einen Container etwas einhegen.
    Um zu verhindern, das ein wildgewordener Container den NAS an die Wand fährt, begrenzen ich jetzt einfach mal den RAM, den sich der Container nehmen darf. Was die verwendeten Parameter bewirken, kann man hier genauer nachlesen: https://docs.docker.com/engine/contain…ce_constraints/

    Ich verwende hier jetzt ein Compose Script, weil es immer aufwändiger wird, das am Beispiel von der UI zu erklären.

    Erst ein mal schaue ich was denn meine Container so zurückmelden. Dazu gibt es den Befehl "docker stats".

    This image is exclusive to our members!
    Please log in or register for free to view graphics and attachments.

    Man sieht, alle Container dürfen auf den gesamten Speicher zugreifen.
    Jetzt starte ich den Container über dieses Compose Script:

    Code
    version: '3'
    services:
        python:
            image: 'python:3.12.9-alpine3.21'
            container_name: python
            command: 'sleep infinity'
            network_mode: bridge
            mem_limit: 1g
            memswap_limit: 1g
            mem_swappiness: 0

    Um kein Swap zu haben müssen "mem_limit" und "memswap_limit" identische Größe haben.
    Warum kann ich nicht wirklich sagen. Ich nehme das mal so hin. Man hätte es besser machen können.

    Ein kleiner Exkurs: Ein Container muss immer was zu tun haben, sonst beendet er sich sofort wieder.
    Also gebe ich ihm das Shell Kommando "sleep infinity" mit. Damit hat er was zu tun, wenn er auch nur schläft.

    Ich starte den Container und schaue mir die "docker stats" an.
    Und da sieht es jetzt fein aus:

    This image is exclusive to our members!
    Please log in or register for free to view graphics and attachments.

    Als nächstes betrete ich den Container mit "docker ecec -it python sh".
    Und dann mache ich ein "free" in dem Container. Was sehe ich da:

    This image is exclusive to our members!
    Please log in or register for free to view graphics and attachments.

    Ich habe 28GB zur Verfügung?? So war das nicht geplant!
    Ok wenn ich die 28G zur Verfügung habe, dann allokiere ich einfach mal eine Menge Speicher.

    This image is exclusive to our members!
    Please log in or register for free to view graphics and attachments.

    Das ging jetzt mal daneben. Irgendetwas hat meinen Prozess gekillt!
    Das war der OOM-Killer. (OOM = Out-Of-Memmory).
    Mein Prozess (Python) wurde also vom OOM-Killer abgeräumt, was auch korrekt war.
    Ich habe die mit zugeteilte Grenze von einem GB überschritten.
    Und das, obwohl mir "free" gesagt hat ich hätte noch 28GB.

    Das liegt daran, dass die API, die "free" nutzt aus einer Zeit vor Docker kommt.
    Und um nicht mit der Kompatibilität zu brechen, bekommt man im Container keine angepassten Werte.
    Daraus folgt, dass Programme, die auf diese API bauen, im Container gegen den OOM-Killer laufen.
    Sie "merken" einfach nicht, dass jemand eine Restriktion gesetzt hat.
    Und es gibt noch verflucht viele Programme, die das tun.

    Aber man kann auch die Limits abfragen. Die werden über die "control groups" verwaltet.
    cgroups - Wikipedia
    Das ist kein triviales Thema und nur für ganz Neugierige.
    Wichtig zu wissen ist, dass z.B. Java das schon richtig macht.

    Dazwischen gibt es noch einige Konzepte, mit denen man da in den Griff bekommen kann.
    Einigen Programmen kann man einfach als Parameter eine Grenze mitgeben.
    Das muss man dann halt auch tun.

    Ist das jetzt schon zu abgehoben?
    Konnte man das verstehen?
    Ist es hilfreich?

Participate now!

Join our community with over 10,000 members!

Register yourself now for free to get full access to all content, graphics, downloads and other exclusive features!