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.