{"id":7859,"date":"2021-11-09T16:54:16","date_gmt":"2021-11-09T14:54:16","guid":{"rendered":"https:\/\/u-labs.de\/portal\/?p=7859"},"modified":"2023-07-31T19:03:25","modified_gmt":"2023-07-31T17:03:25","slug":"einfuehrung-das-ist-docker-compose-und-so-installierst-du-es-auf-dem-raspberry-pi","status":"publish","type":"post","link":"https:\/\/u-labs.de\/portal\/einfuehrung-das-ist-docker-compose-und-so-installierst-du-es-auf-dem-raspberry-pi\/","title":{"rendered":"Einf\u00fchrung: Das ist Docker-Compose und so installierst du es auf dem Raspberry Pi!"},"content":{"rendered":"<p>Wer sich mit Docker besch\u00e4ftigt, wird recht schnell auf Docker-Compose sto\u00dfen. Doch was ist Docker-Compose? Worin unterscheidet es sich zu Docker? Brauche ich das, oder reicht mir das &#8222;normale&#8220; Docker? Dieser Beitrag soll alle diese Fragen beantworten und dir helfen, einen einfachen Webserver mithilfe von Docker-Compose zum laufen zu bringen.<\/p>\n<h2 class=\"wp-block-heading\">Welche Probleme entstehen mit <em>plain Docker<\/em>?<\/h2>\n<p><a href=\"https:\/\/u-labs.de\/portal\/raspberry-pi-einstieg-in-docker-container-fuer-anfaenger-theorie-praxis\/\" title=\"Raspberry Pi: Einstieg in Docker-Container f\u00fcr Anf\u00e4nger (Theorie + Praxis)\">In unserem ersten Einstiegs-Teil f\u00fcr Docker auf dem Raspberry Pi haben wir uns die generelle Funktionsweise angeschaut und dies auch in der Praxis mit einem Webserver demonstriert<\/a>. F\u00fcr einen einzelnen Container ist das ausreichend. Doch im Alltag reicht das schnell nicht mehr aus: Nahezu jede Webanwendung ben\u00f6tigt eine Datenbank. Teils kommen noch weitere Komponenten dazu, etwa Cronjobs. Als Folge daraus hat man f\u00fcr eine einzelne Anwendung oft mindestens zwei Container. <\/p>\n<p>Und wir m\u00fcssen uns zunehmend um mehrere Dinge k\u00fcmmern: Eine Datenbank muss beispielsweise im gleichen Netzwerk wie der Anwendungsserver liegen. Es muss also ein Netzwerk erstellt und beiden Containern zugewiesen werden. Ebenfalls allt\u00e4glich sind Volumes. Selbst f\u00fcr das simple Beispiel des Webservers aus dem vorherigen Teil haben wir eines gebraucht. Das alles l\u00e4sst sich mit Docker-Befehlen l\u00f6sen: <strong>docker network create, docker volume create<\/strong> und so weiter. Aus Erfahrung m\u00f6chte ich euch aber davon abraten: Ihr versinkt schnell in einer Vielzahl immer l\u00e4nger werdender Docker-Befehle, die oft nicht sauber dokumentiert sind und sp\u00e4ter aber wieder gebraucht werden.<\/p>\n<h2 class=\"wp-block-heading\">Wie l\u00f6st Docker-Compose diese Probleme?<\/h2>\n<p>Docker-Compose f\u00fchrt die gleichnamige Yaml-Datei ein: YAML ist ein Format, um Daten in Form von Schl\u00fcssel-Wert Paaren darzustellen. In der <strong>docker-compose.yml<\/strong> legen wir unsere Container mit s\u00e4mtlichen Eigenschaften fest: Vom Image \u00fcber Volumes bis hin zu Ressourcenbegrenzungen und Netzwerken. Mithilfe von Docker-Compose gen\u00fcgen wenige einfache Befehle, um die darin definierten Container verwalten zu k\u00f6nnen. <\/p>\n<p>Das hat mehrere Vorteile, die wohl Wichtigsten:<\/p>\n<ul class=\"wp-block-list\">\n<li>Alle Eigenschaften sind in einer Datei festgelegt, die wir z.B. mit Git in eine Versionsverwaltung ablegen k\u00f6nnen<\/li>\n<li>Es gibt nur noch wenige, kurze Befehle und dadurch eine bessere \u00dcbersicht, da gerade bei komplexeren Containern <strong>docker run<\/strong> Befehle ziemlich lang und damit un\u00fcbersichtlich werden k\u00f6nnen<\/li>\n<li>Alle darin definierten Container lassen sich gleichzeitig starten\/stoppen<\/li>\n<li>In einer Docker-Compose Datei k\u00f6nnen mehrere Container definiert und miteinander verkn\u00fcpft werden<\/li>\n<li>Abh\u00e4ngigkeiten werden festgelegt und eingehalten, z.B. zuerst die Datenbank starten, danach die Anwendung<\/li>\n<li>Volumes und Netzwerke lassen sich einfacher verwalten und automatisch erstellen<\/li>\n<li>Compose erkennt \u00c4nderungen<\/li>\n<\/ul>\n<h2 class=\"wp-block-heading\">Installation: Wie kann ich Docker-Compose auf dem Pi nutzen?<\/h2>\n<p><strong>Nachtrag vom 31.07.2023<\/strong>: Mittlerweile installiert <a href=\"https:\/\/u-labs.de\/portal\/docker-auf-dem-raspberry-pi-installieren-erste-container-starten-einfach-erklaert\/\" data-type=\"URL\" data-id=\"https:\/\/u-labs.de\/portal\/docker-auf-dem-raspberry-pi-installieren-erste-container-starten-einfach-erklaert\/\">das offizielle Skript von Docker (wie dies genutzt wird, habe ich in diesem Beitrag gezeigt)<\/a> automatisch die Compose-Erweiterung. Folgt ihr den Anweisungen aus diesem Beitrag, liefert <em>docker compose version<\/em> daher die Version zur\u00fcck und belegt damit die Funktion der Erweiterung. Dies solltet ihr zuerst pr\u00fcfen und die im Folgenden beschriebenen Schritte nur ausf\u00fchren, wenn ihr dabei keine Version erhaltet (= Plugin ist noch nicht installiert)!<\/p>\n<p>Intern baut Docker-Compose auf Docker auf &#8211; es ist keine eigene Container-Runtime wie Docker! Vereinfacht gesagt f\u00fchrt Docker-Compose im Hintergrund die Docker-Befehle aus und vereinfacht damit f\u00fcr uns. Als Voraussetzung m\u00fcsst ihr daher zun\u00e4chst Docker installiert haben, <a title=\"Raspberry Pi: Einstieg in Docker-Container f\u00fcr Anf\u00e4nger (Theorie + Praxis)\" href=\"https:\/\/u-labs.de\/portal\/raspberry-pi-einstieg-in-docker-container-fuer-anfaenger-theorie-praxis\/\">wie im Einstiegs-Beitrag erkl\u00e4rt<\/a>. Anschlie\u00dfend l\u00e4sst sich Docker-Compose zus\u00e4tzlich installieren. Auf der <a href=\"https:\/\/github.com\/docker\/compose\/releases\" target=\"_blank\" rel=\"nofollow\">Releases-Seite des Projektes<\/a> sucht man sich die aktuellste stabile Version f\u00fcr armv7 heraus. Zum Zeitpunkt des Erstellens dieses Artikels war dies die Version 2.3.4. Man kann sie mit wget direkt auf den Pi herunterladen. Anschlie\u00dfend machen wir die Bin\u00e4rdatei ausf\u00fchrbar und verschieben sie in das von Linux daf\u00fcr vorgesehen Verzeichnis, sodass Compose von \u00fcberall aus genutzt werden kann:<\/p>\n<div class=\"wp-block-syntaxhighlighter-code \">\n<pre class=\"brush: bash; title: ; notranslate\" title=\"\">\nwget wget https:\/\/github.com\/docker\/compose\/releases\/download\/v2.3.4\/docker-compose-linux-aarch64\nchmod +x chmod +x docker-compose-linux-aarch64\n\nmkdir -p ~\/.docker\/cli-plugins\nmv docker-compose-linux-aarch64 ~\/.docker\/cli-plugins\/docker-compose\n<\/pre>\n<\/div>\n<p>Damit sind wir auch schon fertig und sollten den Befehl<em> docker compose<\/em> fortan nutzen k\u00f6nnen:<\/p>\n<div class=\"wp-block-syntaxhighlighter-code \">\n<pre class=\"brush: bash; title: ; notranslate\" title=\"\">\n$ docker compose --version\nDocker Compose version v2.3.4\n<\/pre>\n<\/div>\n<p>Wie bei allen h\u00e4ndisch installierten Programmen sollte man hier immer mal wieder schauen, ob Aktualisierungen zur Verf\u00fcgung stehen und diese einspielen.<\/p>\n<p><strong>Erg\u00e4nzung vom 26.03.2022<\/strong>: Die Installation wurde mit der empfohlenen Vorgehensweise f\u00fcr die neue Version 2 aktualisiert. Statt die ausf\u00fchrbare Datei in das Bin-Verzeichnis zu kopieren, erfolgt die Installation als Docker Plugin. <a href=\"https:\/\/u-labs.de\/portal\/docker-compose-v1-vs-v2-welche-version-sollte-ich-benutzen-worin-liegen-die-unterschiede\/\" title=\"Docker Compose v1 vs. v2: Welche Version sollte ich benutzen? Worin liegen die Unterschiede?\">Weitere Informationen \u00fcber die Neuerungen in Version 2 findet ihr in diesem Beitrag<\/a>. In V2 wird Compose mit Minus aufgerufen.<\/p>\n<h2 class=\"wp-block-heading\">So startest du deinen ersten Container mit Docker-Compose<\/h2>\n<p>Als einfaches Beispiel wollen wir einen Nginx Webserver starten, wie <a href=\"https:\/\/u-labs.de\/portal\/raspberry-pi-einstieg-in-docker-container-fuer-anfaenger-theorie-praxis\/\" title=\"Raspberry Pi: Einstieg in Docker-Container f\u00fcr Anf\u00e4nger (Theorie + Praxis)\">im Beitrag zum Einstieg in Docker mit plain Docker bereits gezeigt<\/a>. Auch wenn ihr mit Compose arbeiten m\u00f6chtet kann ich euch diesen Beitrag empfehlen. Dort werden die Hintergr\u00fcnde detaillierter erkl\u00e4rt, beispielsweise zu den Images. F\u00fcr Compose legen wir eine Yaml-Datei namens <strong>docker-compose.yml<\/strong> an. Wahlweise statt der yml Endung auch yaml, das ist eine umstrittene Geschmackssache und spielt letztendlich keine Rolle. <\/p>\n<p>Zuerst geben wir die Version an. Das Compose-Format wurde mehrfach mit verschiedenen Versionen erweitert. Aktuell sind derzeit 2.4 und 3.8. Ich empfehle 2.4, da Version 3 nur im Cluster-Betrieb Vorteile bietet. Auf einer einzelnen Maschine bietet Version 2 dagegen sogar ein paar Vorteile.<\/p>\n<div class=\"wp-block-syntaxhighlighter-code \">\n<pre class=\"brush: yaml; title: ; notranslate\" title=\"\">\nversion: &quot;2.4&quot;\n<\/pre>\n<\/div>\n<p>Anschlie\u00dfend leiten wir eine Sektion <strong>services<\/strong> ein. Darin k\u00f6nnen beliebig viele Container definiert werden. Wichtig bei Yaml: Hierarchische Sektionen werden durch Einr\u00fccken gekennzeichnet. Tabs sind hier nicht zul\u00e4ssig, stattdessen Leerzeichen verwenden. Meist nutzt man zwei, es k\u00f6nnen aber auch mehr (z.B. 4) verwendet werden &#8211; allerdings konsistent.<\/p>\n<div class=\"wp-block-syntaxhighlighter-code \">\n<pre class=\"brush: yaml; title: ; notranslate\" title=\"\">\nversion: &quot;2.4&quot;\n\nservices:\n  webserver:\n    image: nginx:1.21\n    restart: always\n    ports:\n      - 80:80\n<\/pre>\n<\/div>\n<p>Hier haben wir einen Container namens <strong>webserver<\/strong> mit dem Image <strong>nginx<\/strong> und Tag 1.21. Durch <strong>restart: always<\/strong> wird der Container automatisch gestartet, wenn der Pi bootet. Schlussendlich folgt ein Portmapping von Port 80 des Hosts auf den gleichen Port des Containers &#8211; dies entspricht <strong>-p 80:80<\/strong> beim <strong>docker run<\/strong> Befehl.<\/p>\n<p>Zum Starten gen\u00fcgt es, <strong>docker-compose <\/strong>wie folgt im gleichen Verzeichnis wie die <strong>docker-compose.yml <\/strong>aufzurufen:<\/p>\n<div class=\"wp-block-syntaxhighlighter-code \">\n<pre class=\"brush: yaml; title: ; notranslate\" title=\"\">\ndocker compose up\n<\/pre>\n<\/div>\n<p>Wie beim <strong>docker run<\/strong> Befehl wird zun\u00e4chst das Image aus dem Internet geladen und anschlie\u00dfend der Container gestartet. Der Webserver ist anschlie\u00dfend \u00fcber den Hostname oder die IP-Adresse des Pi im Browser erreichbar:<\/p>\n<figure class=\"wp-block-image size-full\"><a href=\"https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2021\/11\/grafik.png\"><img loading=\"lazy\" decoding=\"async\" width=\"616\" height=\"354\" src=\"https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2021\/11\/grafik.png\" alt=\"\" class=\"wp-image-7875\" srcset=\"https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2021\/11\/grafik.png 616w, https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2021\/11\/grafik-300x172.png 300w, https:\/\/u-labs.de\/portal\/wp-content\/uploads\/2021\/11\/grafik-70x40.png 70w\" sizes=\"auto, (max-width: 616px) 100vw, 616px\" \/><\/a><\/figure>\n<p>Allerdings haben wir hier nun das gleiche Problem wie bei docker run: Der Container l\u00e4uft im Vordergrund und wird zusammen mit  der SSH-Sitzung oder Konsole beendet. Auch hier gibt es den detached Modus mit dem Schalter <strong>-d<\/strong>:<\/p>\n<div class=\"wp-block-syntaxhighlighter-code \">\n<pre class=\"brush: yaml; title: ; notranslate\" title=\"\">\ndocker compose up -d\n<\/pre>\n<\/div>\n<p>Dadurch l\u00e4uft der Container im Hintergrund. Logs lassen sich geb\u00fcndelt von allen Containern wie folgt einsehen:<\/p>\n<div class=\"wp-block-syntaxhighlighter-code \">\n<pre class=\"brush: yaml; title: ; notranslate\" title=\"\">\ndocker compose logs -f\n<\/pre>\n<\/div>\n<p>Oder alternativ \u00fcber <strong>docker logs<\/strong> mit Angabe des Containers. Welche Container Compose gestartet hat, sieht man mit dem Befehl <strong>ps<\/strong>:<\/p>\n<div class=\"wp-block-syntaxhighlighter-code \">\n<pre class=\"brush: yaml; title: ; notranslate\" title=\"\">\n$ docker compose ps\nNAME                        COMMAND                  SERVICE             STATUS              PORTS\ncompose-nginx-webserver-1   &quot;\/docker-entrypoint.\u2026&quot;   webserver           running             0.0.0.0:80-&gt;80\/tcp, :::80-&gt;80\/tcp\n\n<\/pre>\n<\/div>\n<p>Der generierte Name ist eine Kombination aus dem aktuellen Ordner und dem Dienstname. Stoppen kann man s\u00e4mtliche Container \u00fcber den Befehl <strong>down<\/strong>:<\/p>\n<div class=\"wp-block-syntaxhighlighter-code \">\n<pre class=\"brush: yaml; title: ; notranslate\" title=\"\">\ndocker compose down\n<\/pre>\n<\/div>\n<h2 class=\"wp-block-heading\">Eigene HTML-Seiten mit Volume ausliefern<\/h2>\n<p>Um eigene HTML-Seiten ausliefern zu k\u00f6nnen, erstellen wir einen www Ordner mit einer Indexseite:<\/p>\n<div class=\"wp-block-syntaxhighlighter-code \">\n<pre class=\"brush: yaml; title: ; notranslate\" title=\"\">\nmkdir www\necho &#039;&lt;h1&gt;Testseite Docker-Compose&lt;\/h1&gt;&#039; &gt; \/home\/pi\/www\/index.html\n<\/pre>\n<\/div>\n<p>und erweitern das Compose-File, sodass dieser lokale Ordner im Html-Wurzelverzeichnis des Webservers ausgeliefert wird:<\/p>\n<div class=\"wp-block-syntaxhighlighter-code \">\n<pre class=\"brush: yaml; title: ; notranslate\" title=\"\">\nversion: &quot;2.4&quot;\n\nservices:\n  webserver:\n    image: nginx:1.21\n    restart: always\n    ports:\n      - 80:80\n    volumes:\n      - .\/www:\/usr\/share\/nginx\/html\n<\/pre>\n<\/div>\n<p>Anschlie\u00dfend mit docker compose up den Container neu erzeugen und <\/p>\n<h2 class=\"wp-block-heading\">Weiteren Ausbau<\/h2>\n<p>In diesem einfachen Einstiegsbeispiel haben wir nur einen einzigen Container. Sein volles Potenzial sch\u00f6pft Docker-Compose aus, wenn mehrere Container f\u00fcr eine Anwendung n\u00f6tig sind. H\u00e4ufig sind dies etwa Datenbanken. Wie dies funktioniert und wie man Container in Abh\u00e4ngigkeit zueinander setzen kann, schauen wir uns im n\u00e4chsten Teil an. Er wird dann an dieser Stelle verlinkt.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Wer sich mit Docker besch\u00e4ftigt, wird recht schnell auf Docker-Compose sto\u00dfen. Doch was ist Docker-Compose? Worin unterscheidet es sich zu Docker? Brauche ich das, oder reicht mir das &#8222;normale&#8220; Docker? Dieser Beitrag soll alle diese Fragen beantworten und dir helfen, einen einfachen Webserver mithilfe von Docker-Compose zum laufen zu bringen. Welche Probleme entstehen mit plain &#8230;<\/p>\n","protected":false},"author":5,"featured_media":7885,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[671],"tags":[912,288,497,771],"class_list":["post-7859","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-raspberry-pi","tag-container","tag-debian","tag-docker","tag-docker-compose"],"_links":{"self":[{"href":"https:\/\/u-labs.de\/portal\/wp-json\/wp\/v2\/posts\/7859","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=7859"}],"version-history":[{"count":15,"href":"https:\/\/u-labs.de\/portal\/wp-json\/wp\/v2\/posts\/7859\/revisions"}],"predecessor-version":[{"id":10798,"href":"https:\/\/u-labs.de\/portal\/wp-json\/wp\/v2\/posts\/7859\/revisions\/10798"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/u-labs.de\/portal\/wp-json\/wp\/v2\/media\/7885"}],"wp:attachment":[{"href":"https:\/\/u-labs.de\/portal\/wp-json\/wp\/v2\/media?parent=7859"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/u-labs.de\/portal\/wp-json\/wp\/v2\/categories?post=7859"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/u-labs.de\/portal\/wp-json\/wp\/v2\/tags?post=7859"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}