
Arbeiten mit Portainer Stacks (docker-compose)
So schön das grafische Arbeiten mit Portainer ist, so nervig ist es auch wenn man bei jedem neu Anlegen eines Containers immer wieder die selben Felder befüllen muss…
Doch das muss nicht sein. Mit „docker-compose“ gibt es eine Möglichkeit sämtliche Optionen für die Erstellung eines Containers in eine Konfigurationsdatei zu schreiben und den oder die Container voll automatisch daraus erstellen zu lassen.
Im Portainer nennt sich das Ganze „Stacks“. Wobei es sich aber letztendlich doch irgendwie um docker-compose handelt. 🙂
In diesem Tutorial werden wir am Beispiel des ioBroker-Containers die ersten Gehversuche mit Portainer Stacks unternehmen bevor wir dann zum Abschluss ioBroker und Redis einmal gemeinsam erstellen werden. Es also mal mit zwei Containern gleichzeitig versuchen.
Voraussetzungen
Auch hier gilt natürlich wieder die Voraussetzung dass unser Portainer bereits läuft und wir unseren Docker Dienst entsprechend administrieren können.
In unser Beispiel integrieren werden wir ein benutzerdefiniertes Bridge Netzwerk. Da wir das Bridge Netzwerk ebenfalls mit dem Stack erstellen lassen, benötigen wir hier keine Vorarbeit. Allerdings sollte natürlich der Netzbereich für das Bridge Netzwerk nach Möglichkeit nicht bereits durch ein anderes Netz belegt sein.
Da vor allem das ioBroker Image relativ groß ist bietet es sich an das Image vorab bereits über den Menüpunkt „Images“ herunter zu laden. Das spart uns später zeit beim deployen des Stacks.
Außerdem benötigen wir natürlich auch wieder Volumes bzw. Verzeichnisse auf dem Host in die wir unsere persistenten Daten speichern können. Siehe dazu zum Beispiel die Tutorials zum Bereitstellen des ioBroker bzw. des Redis Containers.
Stack File für den ioBroker Container schreiben
Wie bereits angesprochen beinhaltet des Stack File jegliche Information über die zu erstellenden Container, deren Netzwerke, Volumes, usw. Verfasst ist das Ganze in YAML, einer so genannten Auszeichnungssprache aus der gleichen Familie wie das vielleicht eher bekannte XML. Wie alle (Programmier-) Sprachen existiert auch in YAML eine (wenngleich sehr einfache) Syntax. Aber keine Angst, man kann sich die Syntax wunderbar an Beispielen aus dem Internet abschauen. 🙂
Hinweis
Zum Vorbereiten des Stack Files nutze ich übrigens gerne den Notepad++ Editor. Hier lässt sich unter „Sprachen“ auch das Syntax Highlighting für YAML aktivieren. Macht das Ganze schön übersichtlich.
Aber weiter im Text. Generell können die Informationen für den Stack im Portainer über einen „Web editor“, über den Upload eines Compose-Files oder per Git Repo bzw. „Custom template“ bereitgestellt werden. Für den Einstieg schlage ich vor, wir schreiben/ kopieren unser Stack File über den „Web editor“. Der hat zwar kein Syntax Highlighting, zeigt aber Fehler auch recht zuverlässig mit einem roten X-Symbol an.
Öffnen wir also als erstes mal den Web editor. Dies geschieht über einen Klick auf „Stacks“ und dann „Add stack“ über die Weboberfläche im Portainer.
Wie immer gilt es dann dem Kind (hier dem Stack) einen Namen zu geben. Ich nenne ihn einfach „iob“.
Und dann nichts wie ran an den Web editor.
Erster Schritt im Compose-File: Wir geben die Format-Version an.
version: "2"
Hinweis
Portainer Stacks unterstützt aktuell nur das Compose File Format in Version 2. Eine ausführliche Doku dazu findet sich in der Docker Doku.
Weiter geht es mit dem Abschnitt der Services. Ein Service entspricht dabei einem Container. Für ioBroker definieren wir also:
services: iobroker:
Dann geht es weiter mit den Informationen zum Container. Bis unser Compose File so ausschaut. Zur Erläuterung habe kurze Bemerkungen (grün) hinter die einzelnen Parameter geschrieben.
version: "2" services: iobroker: container_name: iobroker # Name des Containers image: buanet/iobroker:latest-v5 # Verwendetes Image hostname: iobroker # Hostname des Containers restart: always # Restart Policy networks: # Netzwerk(e) des Containers internal: # Name des Netzwerks ipv4_address: 172.18.0.2 # IP-Adresse im Netzwerk ports: # Ports die nach Außen durchgereicht werden sollen - "8081:8081" # Port für die ioBroker Admin Oberfläche volumes: # Volumes/Verzeichnisse - /volume1/docker/iobroker_data:/opt/iobroker # Verzeichnis für ioBroker im Format: /pfad/auf/dem/host:/pfad/im/container
Aber Moment mal. Da fehlt doch noch was.
Richtig. Es fehlt noch die Definition des Netzwerks. Denn wie oben bereits versprochen wollen wir auch das Netzwerk durch den Stack erstellen lassen.
Das Netzwerk wird in einem separaten Block definiert. Mit einer Leerzeile stellen wir also folgenden Block noch unten an. Syntaktisch wieder beginnend am Zeilenanfang.
networks: # Definition der Netzwerke internal: # Name des zu erstellenden Netzwerks driver: bridge # Treiber des Netzwerks ipam: # IP Adress Management Sektion config: # Konfiguration des Netzwerks - subnet: 172.18.0.0/16 # Subnetz gateway: 172.18.0.1 # Gateway ip_range: 172.18.0.1/24 # IP-Adressbereich
Ohne Kommentare und syntaktisch „copy & paste“-fähig sieht unser komplettes Stack File für den standalone ioBroker Container im Bridge Netzwerk dann so aus:
version: "2" services: iobroker: container_name: iobroker image: buanet/iobroker:latest-v5 hostname: iobroker restart: always networks: internal: ipv4_address: 172.18.0.2 ports: - "8081:8081" volumes: - /volume1/docker/iobroker_data:/opt/iobroker networks: internal: driver: bridge ipam: config: - subnet: 172.18.0.0/16 gateway: 172.18.0.1 ip_range: 172.18.0.1/24
Hinweis
Wer statt des Bridge Netzwerks ein MACVLAN verwenden möchte sollte einen Blick in dieses Tutorial riskieren: MACVLAN über Portainer einrichten
Stack erstellen
Soweit so gut. Jetzt wird es Zeit unser Stack File auszuprobieren. Dazu brauchen wir im Portainer nichts weiter zu tun als auf den Button „Deploy the stack“ zu klicken.
Achtung
Wenn ihr als Host eine Synology Disk Station nutzt und euch Portainer beim Erstellen eines Stacks mit „bla bla mem_swappiness bla bla“ anmeckert, dann fügt bitte unterhalb der Definition der volumes, also ans Ende der Definition des ioBroker Containers, noch die folgende Definition an (Ein Beispiel ist auch weiter unten einmal zu sehen):
mem_swappiness: -1
Das umgeht einen bekannten Bug der, wie gesagt, meines Wissens nur DiskStation Besitzer betrifft.
Sollte etwas im Stack File nicht passen, dann erscheint in der rechten oberen Ecke eine rote Fehlermeldung. Wenn alles glatt läuft landen wir in der Übersicht unserer Stacks. Mit einem Klick auf den Namen des gerade erstellten Stacks können wir einen Blick auf die Details werfen.
Damit läuft unser Stack bzw. der darin definierte ioBroker Container.
Mein Vorschlag wäre nun, dass ihr euch ein wenig mit dem ioBroker Stack vertraut macht. Probiert doch mal aus was passiert wenn ihr den Stack löscht und wieder neu erstellt. 🙂 Schaut dabei auch mal in den Menüpunkt „Networks“.
Oder wie verhält es sich wenn ihr das Stack File im „laufenden Betrieb“ editiert und z.B. eine Umgebungsvariable hinzu fügt. Probiert es doch einfach mal aus.
...und jetzt mal mit zwei Containern
Wie oben bereits versprochen nehme ich zu unserem ioBroker Stack File jetzt noch einen weiteren Container hinzu. Bei diesem handelt es sich um den Redis Container (mehr Infos).
Ohne lang drum herum zu reden, so sieht mein fertiges Stack File mit zwei Containern aus:
version: "2" services: iobroker: container_name: iobroker image: buanet/iobroker:latest-v5 hostname: iobroker restart: always networks: internal: ipv4_address: 172.18.0.2 ports: - "8081:8081" environment: - IOB_STATESDB_HOST=redis - IOB_STATESDB_PORT=6379 - IOB_STATESDB_TYPE=redis volumes: - /volume1/docker/iobroker_data:/opt/iobroker depends_on: - redis mem_swappiness: -1 redis: container_name: redis image: redis:latest hostname: redis restart: always networks: internal: ipv4_address: 172.18.0.3 ports: - "6379:6379" volumes: - /volume1/docker/redis_data:/data mem_swappiness: -1 networks: internal: driver: bridge ipam: config: - subnet: 172.18.0.0/16 gateway: 172.18.0.1 ip_range: 172.18.0.1/24
Wenn ihr mal genauer hin schaut werdet ihr sehen, dass neben dem weiteren „service“ auch beim ioBroker weitere Definitionen hinzu gekommen sind.
Zum Einen existiert jetzt die Definition „environment“ bei der es sich um die Umgebungsvariablen handelt, zum Anderen in die Definition „depends_on“ hinzugekommen. Bei letzterem handelt es sich um die Konfiguration von Abhängigkeiten. Dies sorgt dafür, dass der ioBroker Container erst startet, wenn die Redis Datenbank zur Verfügung steht.
Außerdem habe ich in diesem File den Workaround für das mem_swappiness-Problem auf Synology DiskStations einmal drin gelassen.
Probiert es (und euch) einfach mal aus. Mit Stacks lässt es sich eigentlich sehr komfortabel Arbeiten. Und wer sich seine Stack-Files immer gut weg sichert, der kann seine Container im schlimmsten Fall in wenigen Minuten wiederherstellen.
Das solle es zu diesem Thema erst einmal gewesen sein. Bei Fragen und Anregungen nutzt gerne die Kommentare oder kontaktiert mich über einen der öffentlichen Kanäle wie z.B. über das ioBroker Forum oder den ioBroker Discord Channel.
Grundsätzlich biete ich keinen persönlichen Support per Messenger bzw. E-Mail an. Fragen sollten meiner Meinung nach immer öffentlich gestellt und beantwortet werden, damit auch andere User mit der selben Frage Zugriff auf die Antworten bekommen. 🙂 Falls ihr mal irgendwo keine Antwort bekommt, nutzt gerne das Kontaktformular und macht mich auf euren Kommentar, Post, Beitrag oder Thread aufmerksam! Danke.
MfG,
André
Änderungshistorie
2021-01-06 Hinweis zu MACVLAN hinzugefügt.
2021-01-01 Erste Veröffentlichung.