Introduction: Persistenz-Spiele in Rancher

In meiner letzten Anleitung habe ich mal meine ersten Gehversuche vorgestellt. Das größte Thema daran war, dass keinerlei Persistenz gegeben war. D.h. wenn man irgendetwas stoppt oder neu startet, dann ist alles wieder auf Null gesetzt. Das ist natürlich kein Zustand. Daher diesmal eine Anleitung, was man im einfachen Fall dagegen tun kann.

Mal noch als Rahmenbedingung: ich möchte am Ende, wenn irgendwann mal alles fertig ist, eine Umgebung haben, mit der ich schnell verschiedene Versionen von wie auch immer gearteten Software-Modulen in wechselnden Kombination aus einem Repository als Zusammenstellung von Containern laden können. Es geht nicht darum, eine Hochverfügbarkeit, wie sie in produktiven Umgebungen benötigt wird, herzustellen. Daher sind mir einfache Lösungen meist lieber. Insbesondere dann, wenn sich alles innerhalb eines Hosts ohne externe Referenz abspielt.

Und noch eins: Auch diesmal gilt wieder

  • Alles was ich hier zeige, ist erstmal nur so zusammengestellt, dass es irgendwie nach bestem Wissen und Gewissen läuft.
  • Was Sicherheit, Stabilität und Effizienz angeht, muss sich jeder so seine eigenen Gedanken machen und hin und wieder auch was selbst lesen. Insbesondere dann, wenn es denn in irgend einer Weise produktiv genutzt werden soll.
  • Auch in Sachen Lizenzen muss jeder für sich schauen, in wie weit die vorgestellten Softwareteile für ihn nutzbar sind.
  • Um auch das klar zu stellen: alles was hier verwendet wird, ist ein eingetragenes Warenzeichen oder stellt eine Marke der jeweiligen Hersteller dar. Die jeweiligen Produktnamen werden nur zur Identifikation der Produkte verwendet. Ich selbst habe keinerlei Rechte an diesen. Die jeweiligen Lizenzbestimmungen müssen eingehalten werden.

Step 1: Allgemein

Rancher bietet verschiedene Möglichkeiten, Persistenz in einem Container herzustellen. Allen gemeinsam, so wie ich es verstanden habe, ist, dass sie auf sogenannten Volumes aufsetzen. Da Änderungen an Daten nicht im Container gespeichert werden, liegen die Volumes immer außerhalb des Containers. D.h. aber auch, dass ohne weiteres nur der Container den Inhalt des Volumes sieht bzw. das Volume in sein Filesystem mounten kann. Benötigt es ein gemeinsames Filesystem, dann findet man im Catalog Lösungen für NFS, EFS usw. Diesen wiederum ist gemeinsam, dass sie mir eine zu komplexe Infrastruktur benötigen und für mich damit rausfallen.

Eine Runde Stöbern fördert ein einfaches Plugin von CWSpear zu Tage. Schauen wir mal, ob wir das zum Laufen bekommen. Startpunkt ist dabei die im ersten Teil erstellte VM in dem Status Rancher läuft, ist aber ansonsten leer.

Step 2: Installation Local Persist Volume Plugin for Docker

Das Plugin kann sowohl innerhalb als auch außerhalb eines Containers erstell werden. Die API-Dokumentation empfiehlt zwar die Variante außerhalb zu verwenden aber aus den Anfangs genannten Gründen und weil mir die Installation im Container einfacher erscheint, entscheide ich mich für die Conatiner-Variante.

Zur Installation des Plugins wird mit INFRASTRUKTUR/Containers/Add Container erstmal ein neuer Container PersistenceContainer erstellt. CWSpear stellt hierzu ein entsprechende Image unter cwspear/docker-local-persist-volume-plugin bereit, was dann auch der Image-Pfad ist.

Der reine Docker-Installation-Weg würde nun vorsehen, dass man einen run ausführt.

docker run -d \<br>    -v /run/docker/plugins/:/run/docker/plugins/ \
    -v /path/to/store/json/for/restart/:/var/lib/docker/plugin-data/ \
    -v /path/to/where/you/want/data/volume/:/path/to/where/you/want/data/volume/ \
        cwspear/docker-local-persist-volume-plugin

Damit würde man allerdings einen nicht gemanagten Container erstellen. Das soll vermieden werden. Daher wird der Befehl mal etwas mit der Command line reference analysiert. Der Parameter -d sorgt dafür, dass der Prozess in Docker im Hintergrund laufen soll. cwspear/docker-local-persist-volume-plugin stellt die Referenz auf das Image dar. Bleibt als Geheimnis nur noch der -v Parameter übrig. Hierzu sagt die Dokumentation

-v, --volume=[host-src:]container-dest[:options<options>]
                                Bind mount a volume. The comma-delimited
                                `options` are [rw|ro], [z|Z], or
                                [[r]shared|[r]slave|[r]private]. The
                                'host-src' is an absolute path or a name
                                value.</options>

Das heißt, mit -v werden Volumes eingebunden. Diese Option steht in der Rancher UI ebenfalls zur Verfügung. Also ein Versuch wert.

Das Plugin benötig im einfachsten Fall drei Volume. run/docker/plugins mountet das Host-Verzeichnis in dem sich das Plugin beim Start registrieren muss. path/to/store/json/for/restart stell ein Volume bereit, in dem das Plugin selbst Konfigurationsdaten für den nächsten Start bereitstellen kann. path/to/where/you/want/data/volume wird dann unser Volume, in dem dann unsere Arbeitsdaten der Stacks/Services liegen werden. Der Pfad hierfür wird dann später /data sein. Also das alles mal eingetragen und dann wäre die Plugin Konfiguration schon fast abgeschlossen. Also den Reiter Volumes öffnen und los geht es.

Nach dem beherzten Klick auf Create und einer kurzen Wartezeit ist der Container dann auch da.

Was nun folgt ist nur noch die Erstellung der allgemein zugänglichen Volumes. Diese könnten zwar auch mit einem Service erstellt werden. Aber der Weg über den Host schließt die Installation erstmal ab. Es werden alos zwei allgemein gültige Volumes auf der Basis des Plugins erstellt

docker volume create -d local-persist -o mountpoint=/data/db --name=dbdata
docker volume create -d local-persist -o mountpoint=/data/services --name=servicedata

Das alles soweit geklappt hat, kann man sich dann auch mal mit

docker volume ls
docker volume inspect dbdata servicedata

anschauen. Damit ist der erste Teil dann schon mal abgeschlossen.

Step 3: Installation Eines Service

Um mal testen zu können, ob unsere Volumes dann auch verfügbar und wirklich persistent ist, benötigt es mal eine ein kleines Beispiel. Einfach und schnell geht dabei Ghost. D.h. wir installieren schnell einen Blog und verweisen dann auf unsere Volumes.

Also, wie schon bekannt, über den Hub Ghost in einem Stack Web ausgewählt und konfiguriert. Entscheidend ist hier, das Ghost das Volume servicedata auf den Pfad/var/lib/ghost mountet.

Mit der Console von des ghost 1 Service findet man dann auch erstmal das erwartetet Ergebnis. Das Gleiche im PersistenceContainer zeigt, dass die Daten allerdings dort angekommen sind. Sehr schön. Jetzt mal noch schnell einen ersten Blog-Eintrag gemacht und geschaut, was daraus wird. In dem Zuge wird auch mal ein Neustart gemacht.

Gehen tut es schon mal, auch nachdem 1.000.000 Worte eingefügt wurden.Und nach dem Neustart ist auch noch alles da.

Step 4: Und Jetzt Die PostgreSQL?

Ja, installiert habe ich sie. Aber, was beim letzten mal noch nicht so in das Gedächtnis gesickert ist, ist die Tatsache, dass die Installation aus dem Catalog mit einer Sidekick kommt. Aha, und was ist das?

Um das herauszubekommen schauen wir uns mal die docker-compose.yml an.

version: '2'
services:
  postgres-lb:
    image: rancher/lb-service-haproxy:v0.6.2
    ports:
    - 5432:5432/tcp
    labels:
      io.rancher.container.agent.role: environmentAdmin
      io.rancher.container.create_agent: 'true'
  postgres-data:
    image: busybox
    volumes:
    - /var/lib/postgresql/data/pgdata
    labels:
      io.rancher.container.start_once: 'true'
  postgres:
    image: postgres:latest
    environment:
      PGDATA: /var/lib/postgresql/data/pgdata
      POSTGRES_DB: Enterprise
      POSTGRES_PASSWORD: db#user*2017
      POSTGRES_USER: dbdbo
    stdin_open: true
    tty: true
    volumes_from:
    - postgres-data
    labels:
      io.rancher.sidekicks: postgres-data

Oh, da kommt einem doch einiges bekannt vor. Anscheinend macht die Installation einen eigenen Service postgres-data auf. Und im postgres Service wird dann im Sinne eines Volumes darauf verwiesen. Na, das war ja mal nix. Für die Postgres, die ja auch keine Daten aus anderen gemeinsamen Verzeichnissen benötigt. wäre der Aufstand komplett umsonst gewesen. Aber als Lösung für einen Service des gleichen Typs, also ohne externe Abhängigkeiten auch schnell gemacht. Im Grunde muss hier nur beim Hinzufügen eines Service mit Add Service noch die Schaltfläche Add Sidekick Container geklickt werden. Autostart wird auf Never gestellt und unter Volume wird dann ein Volume hinzugefügt. Im Primary Service wird dann nur noch Volumes From Sidekick#1 ausgewählt. Und schon wird das Volume erzeugt und eingebunden.

Gemäß der Composer-Dokumentation kann ein so erstelltes Volume wohl auch von verschiedenen Services genutzt werden. Womit sich gleich die Frage stellt, was jetzt zu bevorzugen ist. Da bedarf wohl noch genauerer Betrachtung, weil noch nicht wirklich klar ist, wo denn nun die Unterschiede liegen. Feststellen kann man aber, dass die Anforderung, Daten dauerhaft zu speichern, erstmal erfüllt ist, egal über welchen Weg.

Step 5: Was Fehlt?

Für meine Anforderungen erstmal nichts mehr. Da ich damit leben kann, dass nach einem Test einer Software (jetzt auch in mehreren Schritten) alle Container verworfen werden und damit die Daten verloren sind, braucht es weiter eigentlich nicht mehr. Themen, die man sich aber sicherlich nochmal anschauen muss, gerade wenn es in Richtung produktive Nutzung geht, wären zumindest mal Backup und Restore.

Step 6: Quellennachweis