Container absichern mit DNS: Unsinkbare Containerschiffe Teil 3

Container absichern mit DNS

English version: Click!

Weiter geht’s!
Das ist Teil drei von drei in von meinem Abenteuer, eine hochverfügbare Docker-Umgebung zu erstellen:
Container absichern mit DNS: Unsinkbare Containerschiffe Teil 3

Was haben wir bisher erreicht?
– ein verteiltes Dateisystem erstellt
– Docker Swarm sowie Traefik und Portainer eingesetzt

Was bleibt noch zu tun?

Wie ihr vielleicht festgestellt habt, hat mein Design noch einen Single Point of Failure, und das ist die Adressierung der Hosts selbst.
Um das in den Griff zu bekommen, müssen wir eine virtuelle IP erstellen und die Nodes so einrichten, dass sie darauf achten.

Wie so häufig findet man beim Nachforschen äußerst interessante oder aber auch skurrile Ideen.
Manche setzen einen Loadbalancer vor den Reverse-Proxy, manche setzen einen load balancing reverse proxy vor den Reverse-Proxy. Ich dachte, ich lese nicht richtig.

Zu kompliziert. Ich will es einfach haben.

Ich stelle vor: Keepalived.

Keepalived ist ein Linux Packet das auf VRRP basiert. Die Netzwerk-Admins hier kennen das Protokoll.
Es wird normalerweise benutzt um den Link zwischen Routern oder Firewalls herzustellen und ein HA Cluster zu formen, und es ist sehr ähnlich zu z.B. CARP in der FreeBSD Welt oder proprietären Dingen wie HSRP bei Cisco.

Bevor wir das installieren ,müssen wir eine Voraussetzung auf unseren Manager Knoten erledigen, damit diese an externe IP Adressen angebunden werden können.

nano /etc/sysctl.conf
net.ipv4.ip_nonlocal_bind=1

Leider erfordert dies einen Neustart auf jedem Manager, bei mir also swarm1-3.
Sobald sie wieder zurück sind, installieren wir das Paket:

apt install keepalived -y

Und erstellen die Konfigurationsdatei:

nano /etc/keepalived/keepalived.conf

Hier ist eine Beispielkonfiguration, von swarm1 bei mir:

vrrp_script chk_docker {
    script "pgrep dockerd"
    interval 1
    weight 20
}

vrrp_script chk_traefik {
    script "pgrep traefik"
    interval 30
    weight 10
}

vrrp_instance VI_1 {
     state MASTER
     interface ens160
     virtual_router_id 12
     priority 200
     advert_int 1
     unicast_src_ip 10.0.10.31
     unicast_peer{
         10.0.10.32
         10.0.10.33
     }

     authentication {
         auth_type PASS
         auth_pass pass1234
         }

    virtual_ipaddress {
         10.0.10.39/24
         }

   track_script {
    chk_docker
    chk_traefik
  }
}

Was passiert hier?

Das erste Element, die Scripts, überprüft die Verfügbarkeit des Prozesses, in einer Windowsumgebung würden wir dazu vermutlich ein Fileshare-Quorum im Windows Cluster Manager nutzen, aber das VRRP Protokoll arbeitet etwas anders.

Im instance Element beschreiben wir die tatsächliche Failover Situation.
Der Status ist entweder Master oder Backup, aber ich nutze Master auf allen drei Nodes und lasse das System dynamisch entscheiden.

Dies geschieht auf Grund von Verfügbarkeit und Gewichtung, und die Gewichtung kommt von der priority
Je höher, desto wichtiger ist der Knoten.
Src_ip ist die lokale IP und peers, nun ja, sind die peers.

Ich nutze vereinfachte Authentifizierung, und letztlich das wichtigste Element, die virtuelle IP, die zwischen den Nodes geteilt ist.

Auf der zweiten Node, swarm2 bei mir, nutze ich die gleiche Konfig aber setze die priority auf 100 herunter, und ändere die src_ip und die peers wie angebracht.
Auf swarm3 gehe ich mit der priority sogar bis auf 50 herunter, und passe auch hier src_ip und peers auf die anderen Knoten an.

Jeder Knoten erfordert ein:

sudo service keepalived restart

Status:

Aber schaut euch auch einmal die IP-Addressen an:

Die VIP .39 ist im Moment dem Knoten mit der höchsten Priorität zugewiesen, mein Kumpel swarm1.

DNS Tricks.

Bevor wir das Failover testen können, müssen wir uns noch um DNS kümmern.

Im vorherigen Teil haben wir Traefik und Portainer eingesetzt, und einen A Record erstellt der auf den Host verweist.
Das müssen wir jetzt auf die VIP ändern.

Achtung: Es gibt eine schrecklich wichtige Wahrheit beim Testen von DNS-Änderungen, oder eigentlich jeder Änderung, die irgendwie mit DNS zusammenhängt, und die lautet:
Cache ist ein Problem.

Also reinigt eure Caches. Alle. DNS-Server Cache, Update local data files, Caches auf der lokalen Maschine (flushdns etc) und letztendlich den Browsercache.
So viele vielversprechende und funktionale Konzepte sind frühzeitig verstorben, weil der Cache nicht gesäubert wurde, man man dachte, dass es nicht funktioniert hat.

Hier ist swarm2 als Momentaufnahme:

Jetzt kappe ich die (virtuelle) Netzwerkverbindung auf swarm1:

Ping auf die VIP funktioniert noch, alle Dashboards sind noch vorhanden. So muss es sein!

Hier noch etwas Hintergrund-Information:

Um 17:39 hat swarm2 die Führung übernommen. Jetzt aktiviere ich das Netzwerk auf swarm1 wieder:

Swarm2 hat sich an seinen Platz in der Hierarchie erinnert und ist zurück in den Backup Zustand, was swarm1 automatisch wieder zum Master gestuft hat. Perfekt!

Wir haben jetzt die Dreifaltigkeit aus Storage (Ceph), compute (Docker Swarm) und networking (VRRO) in hochverfügbarem Modus.

In der Theorie könnte man all das sogar mit einem Cluster aus Raspberries mit angeflanschten SSD erledigen, was ein äußerst günstiges hyper converged cluster darstellen würde.

Okay, der Zeitstempel im letzten Screenshot sagt mir, dass es nun endlich Zeit für ein Bier ist!

Letzte Aufräumarbeiten.

Ich setze meine Container normalerweise mit dem “latest” Tag für’s Image, aber die Neu-Erstellung des Containers bzw Services benötigt natürlich einen Trigger.
Klar, man könnte conrjobas nutzen, aber viel eleganter ist doch, einen Container zu nutzen, der andere Container aktualisiert.

Bisher habe ich watchtower genutzt, aber der unterstützt leider keinen Swarm Mode.

Eine Alternative ist shepherd.

Auf geht’s:

mkdir /var/data/containers/shepherd
cd  /var/data/containers/shepherd
nano docker-compose.yml
version: "3"
services:
  shepherd:
    image: mazzolino/shepherd
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
    deploy:
      placement:
        constraints:
        - node.role == manager
docker stack deploy shepherd -c docker-compose.yml

Man könnte auch Portainer nutzen, wenn man ein GUI bevorzugt.

In den Standardeinstellungen überprüft shepherd alle fünf Minuten, ob es ein neues Image gibt und aktualisiert den Service.
Weniger manuell Arbeit, mehr Zeit für Bier. Aber Moment, da gibt es noch etwas.

Über einen längeren Zeitraum sammeln Tools wie watchtower oder shepherd die alten und nicht mehr im Betrieb laufenden Images.

Ähnlich wie watchtower hat shepherd einen Schalter um unbenutzte Images automatisch zu löschen, hier -env IMAGEAUTOCLEANLIMIT=x,wobei X die Anzahl an Images ist, die ihr behalten wollte.
Leider ist mir das nicht flexibel genug, da ein wichtiges Feature fehlt: Exklusionen.

Also nutze ich einen weiteren Container namens docker-cleanup, der zwar nicht länger verwaltet wird, aber den Job einfach erledigt. Zur Not gibt es 100 Forks, irgendwas davon sollte noch weiterentwickelt werden.

Zuerst beschreibe ich die Ausnahmen:

nano docker-cleanup.env
KEEP_IMAGES=heimdall,xxx,xxx
DEBUG=1

Ich habe meine Heimdall Konfiguration schon zweimal verloren nach einem Update und mag nicht, dass das noch einmal geschieht, also kommt der Bereich oben mit in die compose Datei:

version: "3"
services:
  docker-cleanup:
    image: meltwater/docker-cleanup:latest
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - /var/lib/docker:/var/lib/docker
    networks:
      - internal
    deploy:
      mode: global
    env_file: /var/data/containers/cleanup/docker-cleanup.env

networks:
  internal:
    driver: overlay
docker stack deploy cleanup -c docker-compose.yml

Cleanup sucht nach unbenutzten volumes und löschte alles, was länger als 30 Minuten unbenutzt ist, was uns ein bequemes Fenster für Wartungsarbeiten gibt.

Bonus Level!

Die Basis für meine hoffentlich unsinkbaren Containerschiffe ist erstellt, und nun fülle ich das Cluster mit Services.

Man könnte jetzt noch Docker oder zumindest einzelne Container anstiften, Syslogs an Orion zu senden.

Leider nutzt Docker hier die Container ID anstatt den Namen, was die Identifizierung etwas erschwert:

Ein ordentliches Werkzeug wie z.B. SolarWinds Log Analyzer kann genutzt werden, um mittels einfacher Regeln ein Label an die Nachrichten zu hängen. 
Um Syslog in Docker zu aktivieren, folgt man hier der Dokumentation.

Darüber hinaus kommt Docker natürlich auch mit einer API, und ein simples /get info” klingt wie eine Einladung:

Sehr simplifiziert, aber das hat mich nur zwei Minuten gekostet. Ihr könnt jederzeit eine eigene Vorlage erstellen und mit der thwack Community teilen. Vielleicht mache ich das sogar selbst irgendwann.

Andererseits kenne ich mich selbst, und in wenigen Wochen wird mich das ganze hier vermutlich schon wieder langweilen, und ich versuche etwas anderes.
Vielleicht gehe ich zurück auf einzelne Nodes, aber dieses Mal mit ordentlichem Monitoring und Snapshots, für den Fall des Falles.

Mittelfristig präge ich, eine Vorlage für unsere API-Poller für Ceph zu erstellen, da es bereits einige Anfragen in thwack gibt, Metriken zu sammeln.
Die API Doku bei Ceph ist hervorragend, und anstatt Linux Scripts wie ein Höhlenmensch zu nutzen, warum nicht die viel eleganteren Optionen innerhalb der Orion Plattform einspannen?

Aber das ist ein Thema für die Zukunft.

Jetzt will ich erstmal mit etwas anderem spielen. Im wahrsten Sinne des Wortes – mit Stellaris.
Wohin sonst sollte man von Orion gehen?

Update: Beim Umzug des Blogs habe ich die Original-Screenshots dieses Artikels verloren und konnte nur noch auf die komprimierten Varianten zugreifen. Bitte entschuldigt die katastrophale Auflösung.

More homelab posts:

1 2 3 4

Leave a Comment

Your email address will not be published.