{"id":16048,"date":"2025-12-19T15:48:57","date_gmt":"2025-12-19T14:48:57","guid":{"rendered":"https:\/\/u-labs.de\/portal\/?p=16048"},"modified":"2025-12-19T15:48:58","modified_gmt":"2025-12-19T14:48:58","slug":"docker-logs-begrenzen","status":"publish","type":"post","link":"https:\/\/u-labs.de\/portal\/docker-logs-begrenzen\/","title":{"rendered":"Ausufernde Docker-Logs: So verstehst &amp; begrenzt du sie"},"content":{"rendered":"<p>Docker speichert die Ausgabe (stdout\/stderr) der Container dauerhaft. Standardm\u00e4\u00dfig gibt es kein Rotieren, wie man es auf klassischen Servern mit Logrotate kennt. Erzeugt eine Anwendung hohe Mengen an Ausgaben, kann dies Gigabytes an Logdateien auf dem Dateisystem erzeugen. Es ist daher wichtig zu verstehen, wie Docker mit Protokollen umgeht. Und vor allem, diese in der Gr\u00f6\u00dfe zu beschr\u00e4nken. Daf\u00fcr sind keine externen Werkzeuge notwendig. Mit ein wenig Konfiguration begrenzt Docker automatisch die Gr\u00f6\u00dfe der Protokolle auf ein von dir festgelegtes Ma\u00df.<\/p>\n<h2 class=\"wp-block-heading\">So funktionieren Logs in Docker<\/h2>\n<p>Klassische Dateien (unter GNU\/Linux normal in <code class=\"\" data-line=\"\">\/var\/log<\/code> abgelegt) kommen \u00fcblicherweise nicht zum Einsatz. Diese w\u00e4ren unter Docker sowieso nur bis zum n\u00e4chsten Neustart des Containers verf\u00fcgbar. Ausgenommen sind Logs in Volumes, welche persistentes Speichern erm\u00f6glichen. Eben so wird vom Einsatz des Systemd-Journal abgesehen, welches vor allem bei Systemd-Units (Diensten) genutzt wird. <\/p>\n<p>Es ist bei Docker-Containern stattdessen \u00fcblich, s\u00e4mtliche Ausgaben auf die Standardausgabe zu schreiben. Dies ist nicht vergleichbar mit dem manuellen Starten eines Prozesses im Vordergrund! Der Docker Daemon l\u00e4uft als Systemd-Dienst und k\u00fcmmert sich im Hintergrund u.a. um das Schreiben dieser Logs ins Dateisystem. Daf\u00fcr legt er im <em>Docker Lib<\/em> Verzeichnis eine Ordnerstruktur an, in die er Protokolle ins JSON-Format schreibt.<\/p>\n<p>Das bietet mehrere Vorteile: Wir k\u00f6nnen die Protokolle mit Docker-Befehlen wie <code class=\"\" data-line=\"\">docker logs<\/code> oder <code class=\"\" data-line=\"\">docker compose logs<\/code> bequem einsehen. Insbesondere mit Compose sieht man dadurch nicht nur die Logs eines Containers, sondern s\u00e4mtlicher (z.B. Datenbank). Au\u00dferdem k\u00f6nnen sie zentral weitergeleitet werden, etwa an Elasticsearch. So hat man diese geb\u00fcndelt mit anderen Protokollen, dazu filter- und durchsuchbar.<\/p>\n<h2 class=\"wp-block-heading\">Praktischer Einblick in Docker Logs<\/h2>\n<p>Mit <code class=\"\" data-line=\"\">docker inspect<\/code> lassen sich viele tiefgehende Dinge erkunden, die Docker im Hintergrund f\u00fcr uns erledigt. Wer dies auf einem Container aufruft, wird schnell hunderte Zeilen an Ausgabe enthalten: Netzwerkeinstellungen, Volumes, Limits usw. Mit einem Go-Template<sup data-fn=\"056516e8-d153-408a-8218-0a5463104b26\" class=\"fn\"><a href=\"#056516e8-d153-408a-8218-0a5463104b26\" id=\"056516e8-d153-408a-8218-0a5463104b26-link\">1<\/a><\/sup> kann der Pfad ermittelt werden:<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-bash\" data-line=\"\">$ docker inspect --format=&#039;{{.LogPath}}&#039; portal_nginx\n\/var\/lib\/docker\/containers\/f4883a451474c34445abb74028235c80811c0f6c2ca01e9fb8c83ea992ed99aa\/f4883a451474c34445abb74028235c80811c0f6c2ca01e9fb8c83ea992ed99aa-json.log<\/code><\/pre>\n<p><em>f4883a451474c34445abb74028235c80811c0f6c2ca01e9fb8c83ea992ed99aa<\/em> ist hierbei die einzigartige ID, welche Docker jedem Container zuweist. Da sie im Ordner &amp; Dateiname steht, werden die Pfade sperrig lang. Wer mit tail in die Datei schaut, sieht jeweils den originalen Logeintrag zusammen mit Zeitstempel &amp; dem Ausgabestream (stdout\/stderr) als Meta-Info:<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-json\" data-line=\"\">{&quot;log&quot;:&quot;- - 1.2.3.4 - - [19\/Dec\/2025:15:06:56 +0100] \\&quot;POST \/portal\/wp-admin\/admin-ajax.php HTTP\/1.1\\&quot; 200 109 \\&quot;https:\/\/u-labs.de\/portal\/wp-admin\/post.php?post=16048\\u0026action=edit\\&quot; \\&quot;Mozilla\/5.0 (X11; Linux x86_64; rv:145.0) Gecko\/20100101 Firefox\/145.0\\&quot;\\n&quot;,&quot;stream&quot;:&quot;stdout&quot;,&quot;time&quot;:&quot;2025-12-19T14:06:56.05847318Z&quot;}<\/code><\/pre>\n<p>Abgesehen vom JSON-Format mit den Metadaten verh\u00e4lt sich diese Datei wie jede andere Datei: Sobald eine Ausgabe im Container erfolgt, schreibt der Docker-Daemon sie in diese Datei. Man k\u00f6nnte ihr auch mit <code class=\"\" data-line=\"\">tail -f<\/code> folgen. Wobei ich die Werkzeuge von Docker bevorzugen w\u00fcrde, sie sind komfortabler. Mit Werkzeugen wie <code class=\"\" data-line=\"\">ls<\/code> kann die Gr\u00f6\u00dfe im Dateisystem gepr\u00fcft werden. Da der Docker-Damon als root l\u00e4uft, sind daf\u00fcr entsprechende rechte n\u00f6tig.<\/p>\n<h2 class=\"wp-block-heading\">Das Problem: Es gibt kein Limit<\/h2>\n<p>Naturgem\u00e4\u00df werden Protokolle mit der Zeit immer gr\u00f6\u00dfer. Zur Grundausstattung jedes Servers geh\u00f6rt daher ein Mechanismus, der sie nach einer bestimmten Zeitspanne archiviert und irgendwann l\u00f6scht. Schlie\u00dflich braucht in aller Regel niemand mehr die Webserver-Logs von vor 3 Jahren. Handelt es sich um einen \u00f6ffentlich erreichbaren Dienst, kann das sogar kritisch werden: Gem\u00e4\u00df dem Grundsatz der Datensparsamkeit m\u00fcssen zumindest personenbezogene Daten nach (notwendigem) Gebrauch gel\u00f6scht werden.<\/p>\n<p>Auf klassischen GNU\/Linux-Systemen kommt daf\u00fcr Logrotate zum Einsatz. Meist komprimiert man die Dateien damit nach einigen Tagen, weil sie so deutlich weniger Speicherplatz belegen. Wochen oder Monate sp\u00e4ter k\u00f6nnen sie gel\u00f6scht werden. Fehlt ein solcher Mechanismus, werden die Dateien immer gr\u00f6\u00dfer. Je nach Datenmenge &amp; Aktivit\u00e4t k\u00f6nnen auch Textdateien auf mehrere GB wachsen. Insbesondere Webserver. Selbst wenn die Webseite nicht all zu stark besucht ist, gibt es immer mehr Bots im WWW. Insbesondere durch den <em>KI<\/em> Hype hat das stark zugenommen. Im U-Labs Portal w\u00e4chst das Zugriffsprotokoll von Nginx trotz regelm\u00e4\u00dfiger Leerung schnell auf \u00fcber 2GB an:<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-bash\" data-line=\"\">$ sudo ls -lh $(docker inspect --format=&#039;{{.LogPath}}&#039; portal_nginx)\n-rw-r----- 1 root root 2.2G Dez 19 15:22 \/var\/lib\/docker\/containers\/f4883a451474c34445abb74028235c80811c0f6c2ca01e9fb8c83ea992ed99aa\/f4883a451474c34445abb74028235c80811c0f6c2ca01e9fb8c83ea992ed99aa-json.log<\/code><\/pre>\n<p>Systemweit kannst du dir mit folgendem Einzeiler eine \u00dcbersicht \u00fcber s\u00e4mtliche derzeit vorhandenen Logdateien mit ihrer Gr\u00f6\u00dfe verschaffen:<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-bash\" data-line=\"\">$ sudo ls -lh $(docker inspect --format=&#039;{{.LogPath}}&#039; $(docker ps --format=&#039;{{.Names}}&#039;))\n-rw-r----- 1 root root  18M Dez 19 14:44 \/var\/lib\/docker\/containers\/01e91183a5e1762adade346dd8017ac3e8679a94c55313a44d0368fda67d5526\/01e91183a5e1762adade346dd8017ac3e8679a94c55313a44d0368fda67d5526-json.log\n-rw-r----- 1 root root  24K Dez 16 01:18 \/var\/lib\/docker\/containers\/063c2f8bb0218cbe3ea00da826b7209413c8a7a78d0eaffccd53ea378dbae7f4\/063c2f8bb0218cbe3ea00da826b7209413c8a7a78d0eaffccd53ea378dbae7f4-json.log\n-rw-r----- 1 root root 1.5M Dez 19 02:32 \/var\/lib\/docker\/containers\/100da33621b9125322d2362f21edb6f9d06291e4e27732306df0536b3e277794\/100da33621b9125322d2362f21edb6f9d06291e4e27732306df0536b3e277794-json.log\n-rw-r----- 1 root root  75M Dez 19 15:28 \/var\/lib\/docker\/containers\/1828edd3e9e1af73750f3382f942a505210711eb68a3dc2ad965511fd251782b\/1828edd3e9e1af73750f3382f942a505210711eb68a3dc2ad965511fd251782b-json.log\n[...]<\/code><\/pre>\n<p>Insbesondere, wenn du hier bereits gro\u00dfe Dateien siehst, besteht Handlungsbedarf. Auch wenn nicht w\u00fcrde ich es jedoch nicht darauf ankommen lassen: Logdateien k\u00f6nnen das Dateisystem mit der Zeit beachtlich f\u00fcllen! Jeden Tag ein paar MB summieren sich mit der Zeit. Au\u00dferdem kann ein derzeit langsames Wachstum durch z.B. (vergessene) Debug-Logs oder exzessive Fehlermeldungen in Zukunft noch steigen. Docker legt seine Dateien standardm\u00e4\u00dfig in vielen Distributionen nach <code class=\"\" data-line=\"\">\/var\/lib\/docker<\/code> ab. F\u00fcr gew\u00f6hnlich ist das keine eigene Partition, sondern liegt im Wurzel-Dateisystem. Das m\u00f6chte man nicht unbedingt voll laufen lassen. Daher: Besser vorzeitig darum k\u00fcmmern.<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-bash\" data-line=\"\">$ docker info | grep &quot;Docker Root&quot;\n Docker Root Dir: \/var\/lib\/docker<\/code><\/pre>\n<h2 class=\"wp-block-heading\">So begrenzt du Dockers Protokolle systemweit<\/h2>\n<p>Unter Docker greift Logrotate nicht ohne weiteres. Doch die Container Laufzeitumgebung besitzt bereits zwei eingebaute Wege, um Logdateien ein Limit zu verpassen. Methode 1 ist global, d.H. sie gilt standardm\u00e4\u00dfig f\u00fcr alle Container. Ich bevorzuge sie und setze damit eine sinnvolle Standard-Begrenzung. So muss dies nicht explizit f\u00fcr jeden einzelnen Container angegeben werden, obwohl dies bei vielen \u00e4hnlich ist.<\/p>\n<p>Das globale Limit wird in der Konfigurationsdatei des Docker Daemons unter <code class=\"\" data-line=\"\">\/etc\/docker\/daemon.json<\/code> festgelegt. Sollte sie nicht existieren, die Datei mit Root-Rechten anlegen:<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-json\" data-line=\"\">{\n  &quot;log-opts&quot;: {\n    &quot;max-size&quot;: &quot;100m&quot;,\n    &quot;max-file&quot;: &quot;3&quot;\n  }\n}<\/code><\/pre>\n<p>Im Kern bietet Docker \u00e4hnliche Funktionalit\u00e4t wie Logrotate: Die erste Anweisung setzt ein Limit pro Logdatei, in diesem Beispiel 100MB. \u00dcber die zweite wird begrenzt, wie viele Logdateien es geben darf (hier 3). Docker w\u00fcrde also die erste Datei f\u00fcllen, bis sie 100MB erreicht hat. Dann eine zweite &amp; dritte, ebenfalls bis jeweils 100MB. Nachdem die dritte Datei das 100MB Limit erreicht hat, l\u00f6scht es die \u00e4lteste der Dateien. Komprimieren wird von Docker nicht unterst\u00fctzt. Wer das m\u00f6chte, kann zus\u00e4tzlich Logrotate verwenden.<\/p>\n<p>Durch die Client-Server Struktur von Docker werden die \u00c4nderungen erst nach dem Neustart des Daemons wirksam. Zu beachten: Dies stoppt s\u00e4mtliche laufende Container &amp; startet sie ebenfalls neu!<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-bash\" data-line=\"\">sudo systemctl restart docker<\/code><\/pre>\n<h2 class=\"wp-block-heading\">Limits pro Container<\/h2>\n<p>Es kann sinnvoll sein, diese globalen Grenzwerte f\u00fcr einzelne Container h\u00f6her oder niedriger zu setzen. Ein Beispiel: Du betreibst Webserver mit hoher Last. Hier sollen die Limits h\u00f6her sein, um mehr als nur die letzten Stunden nachvollziehen zu k\u00f6nnen. Bei anderen Anwendungen, die weniger Ausgaben erzeugen, ist das nicht n\u00f6tig. In solchen F\u00e4llen nutzt du das Attribut <code class=\"\" data-line=\"\">logging<\/code> in der <code class=\"\" data-line=\"\">docker-compose.yml<\/code>, um Abweichungen von den systemweiten Begrenzungen anzugeben:<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-yaml\" data-line=\"\">services:\n  nginx:\n    image: nginx:1.27-alpine\n    restart: always\n    # ...\n    logging:\n      driver: &quot;json-file&quot;\n      options:\n        max-file: &quot;3&quot;\n        max-size: &quot;10m&quot;<\/code><\/pre>\n<p>Den Daemon neu zu starten, ist hierbei nicht n\u00f6tig. Es gen\u00fcgt, die Container mit Docker-Compose neu zu starten, damit die \u00c4nderungen wirksam werden:<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-bash\" data-line=\"\">docker compose up -d<\/code><\/pre>\n<h2 class=\"wp-block-heading\">Quellen<\/h2>\n<ol class=\"wp-block-footnotes\">\n<li id=\"056516e8-d153-408a-8218-0a5463104b26\"><a href=\"https:\/\/docs.docker.com\/engine\/cli\/formatting\/\" target=\"_blank\" rel=\"nofollow\">https:\/\/docs.docker.com\/engine\/cli\/formatting\/<\/a> <a href=\"#056516e8-d153-408a-8218-0a5463104b26-link\" aria-label=\"Zur Fu\u00dfnotenreferenz 1 navigieren\">\u21a9\ufe0e<\/a><\/li>\n<\/ol>\n","protected":false},"excerpt":{"rendered":"<p>Docker speichert die Ausgabe (stdout\/stderr) der Container dauerhaft. Standardm\u00e4\u00dfig gibt es kein Rotieren, wie man es auf klassischen Servern mit Logrotate kennt. Erzeugt eine Anwendung hohe Mengen an Ausgaben, kann dies Gigabytes an Logdateien auf dem Dateisystem erzeugen. Es ist daher wichtig zu verstehen, wie Docker mit Protokollen umgeht. Und vor allem, diese in der &#8230;<\/p>\n","protected":false},"author":5,"featured_media":16058,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":"[{\"content\":\"<a href=\\\"https:\/\/docs.docker.com\/engine\/cli\/formatting\/\\\">https:\/\/docs.docker.com\/engine\/cli\/formatting\/<\/a>\",\"id\":\"056516e8-d153-408a-8218-0a5463104b26\"}]"},"categories":[883],"tags":[],"class_list":["post-16048","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-docker-containertechnologie"],"_links":{"self":[{"href":"https:\/\/u-labs.de\/portal\/wp-json\/wp\/v2\/posts\/16048","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/u-labs.de\/portal\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/u-labs.de\/portal\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/u-labs.de\/portal\/wp-json\/wp\/v2\/users\/5"}],"replies":[{"embeddable":true,"href":"https:\/\/u-labs.de\/portal\/wp-json\/wp\/v2\/comments?post=16048"}],"version-history":[{"count":8,"href":"https:\/\/u-labs.de\/portal\/wp-json\/wp\/v2\/posts\/16048\/revisions"}],"predecessor-version":[{"id":16056,"href":"https:\/\/u-labs.de\/portal\/wp-json\/wp\/v2\/posts\/16048\/revisions\/16056"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/u-labs.de\/portal\/wp-json\/wp\/v2\/media\/16058"}],"wp:attachment":[{"href":"https:\/\/u-labs.de\/portal\/wp-json\/wp\/v2\/media?parent=16048"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/u-labs.de\/portal\/wp-json\/wp\/v2\/categories?post=16048"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/u-labs.de\/portal\/wp-json\/wp\/v2\/tags?post=16048"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}