Photo by insung yoon / Unsplash

Docker Container mit Watchtower updaten

docker 14. Juli 2023

In der Docker Philosophie gibt es für jeden Dienst einen einzelnen Container. Sein Inhalt wird durch so genannte "Images" definiert. Diese liegen bei Docker Hub oder einer beliebigen anderen Registry und können von dort heruntergeladen und genutzt werden. Diese Images enthalten den Dienst und alle dafür notwendigen Systemkomponenten. Damit hat man eine fest definierte Systemumgebung und der Container wird auf jedem System gleich funktionieren. Es kann also zu keinen Seiteneffekten kommen, weil ein Tool nicht installiert ist oder in der falschen Version vorliegt.

Images sind unveränderlich

Docker Images werden einmal erstellt und dann zum Beispiel zu Docker Hub hochgeladen. Sie können nicht verändert werden. Das bedeutet aber auch, dass die Anwendung darin nicht einfach über einen Updater aktualisiert werden kann. Diese Änderungen würden verloren gehen, wenn der Container einmal neu aufgebaut wird, weil dann wieder nur die Daten aus dem ursprünglichen Image vorhanden sind.

Deswegen wird bei einer Aktualisierung ein neues Image erstellt und entsprechend zur Verfügung gestellt. Die Anwender müssen nun dafür sorgen, dass ihre Container mit der neueren Version laufen.

Manuelles Update

Wenn wir davon ausgehen, dass docker compose eingesetzt wird, wie es in den bisherigen Anleitungen in diesem Blog der Fall ist, sieht der Update-Prozess folgendermaßen aus:

# Mit "cd" in das Verzeichnis der Anwendung wechseln, in der auch die
# docker-compose.yml liegt.

# Container stoppen
docker compose stop

# Container löschen
docker compose down

# Neue Images laden
docker compose pull

# Container mit neuen Images erstellen und starten
docker compose up -d

Da wir docker compose nutzen gelten diese Schritte für alle Container, die in der docker-compose.yml definiert sind.

Automatisches Update

Da einige Images sehr häufig aktualisiert werden, teilweise sogar täglich, wäre es zu begrüßen wenn dieser Prozess automatisiert werden kann. Dabei ist anzumerken, dass unbeaufsichtigte automatische Updates immer ein gewisses Risiko beinhalten.

So kann es passieren, dass es eine Änderung gibt die ein manuelles Eingreifen erfordern, damit die Anwendung wieder läuft. Oder aber ein Anbieter hat ein fehlerhaftes Image hochgeladen, was zwar nach ein paar Stunden korrigiert wurde, der Auto-Updater hat aber ggf. in der Zwischenzeit das fehlerhafte Image gezogen und die Anwendung ist offline.

In den allermeisten Fällen kommt es aber zu keinen Problemen, es sollte einem aber bewusst sein, dass es diese Möglichkeit gibt. Ich persönlich nehme lieber die sehr geringe Wahrscheinlichkeit eines Ausfalls in Kauf, als dass meine Anwendungen veralten und diese ggf. ein Sicherheitsrisiko darstellen.

Watchtower

Die Anwendung Watchtower bietet so eine automatisierte Aktualisierung an. Sie ist selbst ebenfalls ein Docker Container, erkennt alle anderen Container und prüft in einem definierten Zeitintervall, ob für ein Container ein neues Image vorliegt. Ist dies der Fall wird das Image automatisch geladen, der betroffene Container gestoppt und gelöscht und mit den gleichen Einstellungen wieder auf Basis des neuen Images hochgefahren.

Voraussetzungen

Es wird davon ausgegangen, dass ihr mit eurem Benutzer auf eurem System angemeldet seid und dieser in den Gruppen sudo und docker ist. Dies ist der Fall, wenn ihr unseren anderen Anleitungen gefolgt seid. Desweiteren wird diese Ordnerstruktur angenommen:

├── /home/USERNAME/docker/
│   ├── watchtower
│   │   ├── docker-compose.yml

Sollte die Struktur passen, aber der Ordner noch nicht existieren, legt diesen einfach an und wechselt in das Verzeichnis:

mkdir -p ~/docker/watchtower
cd ~/docker/watchtower

Installation

Um Watchtower zu "installieren" bzw. eher als Container zu starten, legen wir eine neue "docker-compose.yml" an (nano docker-compose.yml) und füllen sie mit folgendem Inhalt:

version: '3'

services:
  watchtower:
    container_name: watchtower
    hostname: watchtower
    image: containrrr/watchtower
    restart: unless-stopped
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
    environment:
      TZ: Europe/Berlin
      WATCHTOWER_SCHEDULE: "0 0 5 * * *"
      WATCHTOWER_CLEANUP: true
      WATCHTOWER_INCLUDE_STOPPED: true

Speichern und schließen mit
Win: STRG+O, ENTER, STRG+X
Mac: CONTROL+O, ENTER, CONTROL+X

Anschließend wird der Container gestartet:

docker compose up -d

Wenn ihr euch die Ausgaben des Containers anzeigen lasst mit docker compose logs -f, sollte etwas in dieser Art zu sehen sein:

[+] Running 2/2
 ✔ Network watchtower_default  Created
 ✔ Container watchtower        Started
watchtower  | time="2023-07-14T16:21:14+02:00" level=info msg="Watchtower 1.5.3"
watchtower  | time="2023-07-14T16:21:14+02:00" level=info msg="Using no notifications"
watchtower  | time="2023-07-14T16:21:14+02:00" level=info msg="Only checking containers using enable label"
watchtower  | time="2023-07-14T16:21:14+02:00" level=info msg="Scheduling first run: 2023-07-15 05:00:00 +0200 CEST"
watchtower  | time="2023-07-14T16:21:14+02:00" level=info msg="Note that the first check will be performed in 12 hours, 38 minutes, 45 seconds"

Das Log verlasst ihr wieder mit STRG+C bzw. am Mac mit CONTROL+C

Erläuterung

Als Volume wird /var/run/docker.sock als readonly in den Container gegeben. Dadurch ist Watchtower in der Lage, die anderen Container zu sehen und sie zu steuern.

WATCHTOWER_SCHEDULE gibt an, wie oft auf neue Images geprüft werden soll. Die Angabe im Beispiel bedeutet "Jeden Tag um 05:00 Uhr". Dies kann beliebig auf eine andere Uhrzeit angepasst werden oder aber auch auf einen häufigeren Intervall verändert werden. Wenn ihr euch mit den Cron-Angaben nicht auskennt, kann crontab.guru weiterhelfen, um die richtige Angabe zu finden.

WATCHTWOER_CLEANUP sorgt dafür, dass die alten Images entfernt werden, damit der Speicher nicht mit alten Images zumüllt. Durch WATCHTOWER_INCLUDE_STOPPED werden auch Container aktualisiert, die aktuell gestoppt sind und nicht laufen, aber existieren.

Updatesuche einschränken

Mit den obigen Einstellungen sucht Watchtower ausnahmslos für alle Container, die er finden kann nach neuen Images und aktualisiert sie automatisch. Wenn ihr die Kontrolle darüber behalten wollt, welche Container automatisch aktualisiert werden sollen und welche nicht, ist auch dies möglich.

Dazu muss die docker-compose.yml im Bereich "environment" um folgende Umgebungsvariable ergänzt werden:

WATCHTOWER_LABEL_ENABLE: true

Damit überprüft Watchtower nur noch Container, die ein bestimmtes Label haben. Das bedeutet aber auch, dass ihr bei jedem Container, der automatisch aktualisiert werden soll, dieses Label ergänzen müsst. Die Datei von Watchtower sähe damit so aus:

version: '3'

services:
  watchtower:
    container_name: watchtower
    hostname: watchtower
    image: containrrr/watchtower
    restart: unless-stopped
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
    environment:
      TZ: Europe/Berlin
      WATCHTOWER_SCHEDULE: "0 0 5 * * *"
      WATCHTOWER_CLEANUP: true
      WATCHTOWER_LABEL_ENABLE: true
      WATCHTOWER_INCLUDE_STOPPED: "true"
    labels:
      com.centurylinklabs.watchtower.enable: true

Die letzten beiden Zeilen müssen auch in jeden weiteren Container, der zukünftig aktualisiert werden soll. Nicht vergessen nach der Anpassung die Container neu zu erstellen: docker compose down && docker compose up -d.

Abschluss

Mit Watchtower habt ihr nun eine einfache Möglichkeit im Einsatz, um eure Dienste jederzeit auf dem neuesten Stand zu halten. Zwar sollte man sich auch so immer regelmäßig auf die Systeme einloggen, wenn man selber Dienste hostet, aber in der Realität gibt es manchmal längere Abschnitte in denen das nicht passiert. Umso wichtiger ist es dann, dass die Dienste nicht veralten.

Bei Anmerkungen oder Fragen kommt gerne auf unseren Discord.

Join the IceFlom & maarsellow & Viertelwissen Discord Server!
Gemeinschaftsdiscord von IceFlom, Maarsellow und Viertelwissen

Tags