Ich möchte, dass meine Docker Container sich zyklisch Updaten und ich nicht jede Woche manuel ein docker compose pull && docker compose up -d laufen lassen muss. In den Kommentaren von Goneuland hat ein User nach der Anleitung für Watchtower gefragt. Da ist mir doch direkt wieder eingefallen, dass ich Watchtower bereits kenne und auch schonmal konfiguriert habe. Watchtower schaut ob es für die Container neue latest Versionen gibt, pullt die und startet den Container ggf. neu. Es gibt eine ganz nette Anleitung in Kombination mit Portainer. Ich möchte es an dieser Stelle aber explizit ohne Portainer versuchen.

ACHTUNG: Watchtower macht automatische Updates! Wenn Watchtower eine Aktualisierung macht und das Latest-Image hat widererwartend einen Fehler könnte es passieren das nach der Aktualisierung der Container nicht mehr läuft oder es gar zum Datenverlust kam!

Versionierung

DatumÄnderung
17.06.2022Erweiterung um den Punkt „Images säubern“
16.06.2022Initialer Release

Verzeichnis erstellen

Zu erst erstelle ich mir das passende Verzeichnis:

mkdir -p /opt/containers/watchtower

Docker Compose Datei erstellen

Nun erstellen ich mir die Docker Compose Datei. In diese Datei kopiere ich mir mal das Beispiel aus der Dokumentation:

nano /opt/containers/watchtower/docker-compose.yml

Inhalt:

version: "3"
services:
  watchtower:
    image: containrrr/watchtower
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock

Watchtower starten

Ich starte diesen Container nun mal die beispielhafte Konfiguration:

docker compose -f /opt/containers/watchtower/docker-compose.yml up

Ausgabe:

Ausgabe auf der Konsole

Damit läuft der Container und gibt mir folgende Informationen aus:

  • msg=“Watchtower 1.4.0″
    –> Version des laufenden Watchtower
  • msg=“Using no notifications“
    –> Das keine Benachrichtigungen konfiguriert sind
  • msg=“Checking all containers (except explicitly disabled with label)“
    –> Es werden alle Container geprüft außer die die eine expliziten Hinweis gesetzt haben
  • msg=“Scheduling first run: 2022-06-17 18:57:19 +0000 UTC“
    –> Geplante erste durchführung
  • msg=“Note that the first check will be performed in 23 hours, 59 minutes, 59 seconds“
    –> Zeit bis zur ersten durchführung

Damit würde es grundsätzlich schonmal funktionieren und hat akut noch kein Update eingespielt sondern nur geplant. Wie ich den ausgegebene Informationen entnehmen kann gibt es wohl noch eine Vielzahl an möglichen Konfigurationen.

Weitere Konfigurationen

Benachrichtigungen konfigurieren

Es gibt einen Hinweis, dass ich Benachrichtigungen konfigurieren kann und es erscheint mir Sinnvoll diese auch zu konfigurieren damit ich einen Bericht bekomme über getätigte Updates bzw. Durchläufe. Dazu werfe ich einen kurzen Blick in die offizielle Dokumentation. Diese gibt mir folgende Möglichkeiten:

  • email -> Benachrichtigung via Email
  • slack -> Benachrichtigung via Slack
  • msteams -> Benachrichtigung via MSTeams
  • gotify -> Benachrichtigung via Gotify
  • shoutrrr -> Benachrichtigung via containrrr/shoutrrr

Da ich mehrere Server betreibe und den Watchtower auch auf allen einsetzten möchte zugleich aber nicht zugespamt werden möchte wähle ich für mich Slack. Innerhalb meines Slack Workspaces lege ich mir einen Channel an und füge die App „Eingehende Webhooks“ zu Slack hinzu. Diese gibt mir eine Hook-URL aus welchen ich mir in die Konfiguration der docker-compose.yml mit einarbeite:

Inhalt:

version: "3"
services:
  watchtower:
    image: containrrr/watchtower
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock

Geänderte Fassung:

version: "3"
services:
  watchtower:
    image: containrrr/watchtower
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
    environment:
      - WATCHTOWER_NOTIFICATIONS=slack
      - WATCHTOWER_NOTIFICATION_SLACK_HOOK_URL="https://hooks.slack.com/services/TXXXXX/BXXXXX/XXXXXXXX"  # Hier füge ich den Hook-URL ein
      - WATCHTOWER_NOTIFICATION_SLACK_IDENTIFIER=watchtower-server-01  # Hier lege ich meinen eigenen Identifier ein
      - WATCHTOWER_NOTIFICATION_SLACK_CHANNEL=#watchtower  # Hier füge ich den Channel ein

Wenn ich nun den Container wieder starte gibt er mir aus, dass Slack nun zur Benachrichtigung definiert wurde:

Ausgabe auf der Konsole

Zeitzone definieren

Mir ist aufgefallen, dass die Zeitzone bzw. die Zeit im Container auch nicht stimmt. Dazu gibt es in den Argumenten auch einen Hinweis es mit TZ zu definieren. Ich persönlich nutze lieber die Variante die Zeitzone vom Host zu übernehmen:

Inhalt:

version: "3"
services:
  watchtower:
    image: containrrr/watchtower
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
    environment:
      - WATCHTOWER_NOTIFICATIONS=slack
      - WATCHTOWER_NOTIFICATION_SLACK_HOOK_URL="https://hooks.slack.com/services/TXXXXX/BXXXXX/XXXXXXXX"  # Hier füge ich den Hook-URL ein
      - WATCHTOWER_NOTIFICATION_SLACK_IDENTIFIER=watchtower-server-01  # Hier lege ich meinen eigenen Identifier ein
      - WATCHTOWER_NOTIFICATION_SLACK_CHANNEL=#watchtower  # Hier füge ich den Channel ein

Geänderte Fassung:

version: "3"
services:
  watchtower:
    image: containrrr/watchtower
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - /etc/localtime:/etc/localtime:ro
    environment:
      - WATCHTOWER_NOTIFICATIONS=slack
      - WATCHTOWER_NOTIFICATION_SLACK_HOOK_URL="https://hooks.slack.com/services/TXXXXX/BXXXXX/XXXXXXXX"  # Hier füge ich den Hook-URL ein
      - WATCHTOWER_NOTIFICATION_SLACK_IDENTIFIER=watchtower-server-01  # Hier lege ich meinen eigenen Identifier ein
      - WATCHTOWER_NOTIFICATION_SLACK_CHANNEL=#watchtower  # Hier füge ich den Channel ein

Wenn ich diesen Container starte gibt er mir nun die Zeit + 24h aus. Diese Entspricht nun der Host-Zeit.

Container-Auswahl via Flag

Für mich ist es wichtig, dass nicht blind jeder Container aktualisiert wird, da ich auch Server habe auf denen zum Beispiel Mailcow läuft. Mailcow bringt sein eigenes Update-Script mit. Nun gibt es 2 Möglichkeiten:

  • Standard: Alle Container bekommen ein Update außer welche mit expliziter Flag
  • Kein Container bekommt ein Update außer welche mit expliziten Flag

Standardvariante

In der Standardvariante kann ich jedem beliebigen Container das Label com.centurylinklabs.watchtower.enable=false mitgeben, welches das Update unterbindet.

Beispiel:

version: "3"
services:
  watchtower:
    image: containrrr/watchtower
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - /etc/localtime:/etc/localtime:ro
    environment:
      - WATCHTOWER_NOTIFICATIONS=slack
      - WATCHTOWER_NOTIFICATION_SLACK_HOOK_URL="https://hooks.slack.com/services/TXXXXX/BXXXXX/XXXXXXXX"
      - WATCHTOWER_NOTIFICATION_SLACK_IDENTIFIER=watchtower-server-01
      - WATCHTOWER_NOTIFICATION_SLACK_CHANNEL=#watchtower
    labels:
      - "com.centurylinklabs.watchtower.enable=false" # False -> Es wird kein Update für diesen Container gemacht

Alternative Variante

Ich persönlich bevorzuge die Variante, dass kein Container aktualisiert wird. Nur die Container welche ich explizit definiere. Dazu erweitere ich meine docker-compose.yml um die notwendige Option:

Inhalt:

version: "3"
services:
  watchtower:
    image: containrrr/watchtower
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - /etc/localtime:/etc/localtime:ro
    environment:
      - WATCHTOWER_NOTIFICATIONS=slack
      - WATCHTOWER_NOTIFICATION_SLACK_HOOK_URL="https://hooks.slack.com/services/TXXXXX/BXXXXX/XXXXXXXX"
      - WATCHTOWER_NOTIFICATION_SLACK_IDENTIFIER=watchtower-server-01
      - WATCHTOWER_NOTIFICATION_SLACK_CHANNEL=#watchtower
      - WATCHTOWER_LABEL_ENABLE=true # Hiermit aktiviere ich die alternative Variante
    labels:
      - "com.centurylinklabs.watchtower.enable=true" # Jeder zu aktualisierender Container bekommt dies nun mitgegeben

Ab jetzt muss ich jedem Container entweder com.centurylinklabs.watchtower.enable=true oder --label-enable mitgeben damit Watchtower diese aktualisiert.

Zeitplan

Nun gilt es einen Zeitplan zu erstellen. Beim Zeitplan kann ich mit der bekannten Cron expression in 6 Feldern eine regelmäßigkeit in der docker-compose.yml Konfigurieren :

Inahlt:

version: "3"
services:
  watchtower:
    image: containrrr/watchtower
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - /etc/localtime:/etc/localtime:ro
    environment:
      - WATCHTOWER_NOTIFICATIONS=slack
      - WATCHTOWER_NOTIFICATION_SLACK_HOOK_URL="https://hooks.slack.com/services/TXXXXX/BXXXXX/XXXXXXXX"
      - WATCHTOWER_NOTIFICATION_SLACK_IDENTIFIER=watchtower-server-01
      - WATCHTOWER_NOTIFICATION_SLACK_CHANNEL=#watchtower
      - WATCHTOWER_LABEL_ENABLE=true
    labels:
      - "com.centurylinklabs.watchtower.enable=true"

Angepasse Konfiguration:

version: "3"
services:
  watchtower:
    image: containrrr/watchtower
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - /etc/localtime:/etc/localtime:ro
    environment:
      - WATCHTOWER_NOTIFICATIONS=slack
      - WATCHTOWER_NOTIFICATION_SLACK_HOOK_URL="https://hooks.slack.com/services/TXXXXX/BXXXXX/XXXXXXXX"
      - WATCHTOWER_NOTIFICATION_SLACK_IDENTIFIER=watchtower-server-01
      - WATCHTOWER_NOTIFICATION_SLACK_CHANNEL=#watchtower
      - WATCHTOWER_LABEL_ENABLE=true
      - WATCHTOWER_SCHEDULE=0 0 4 * * * # Hier anpassen. Im Beispiel: Jede Nacht um 04:00 Uhr
    labels:
      - "com.centurylinklabs.watchtower.enable=true"

In desem Beispiel würde jede Nacht um 04:00 Uhr das Update durchgeführt.

Images säubern

Wenn ich immer wieder Updates auf neue Images mache wird mein Docker-System ganz schön zuwuchern mit alten Images. Für diesen Fall gibt es in der Dokumentation abhilfe. Diese Pflege ich auch in meine docker-compose.yml ein:

Inhalt:

version: "3"
services:
  watchtower:
    image: containrrr/watchtower
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - /etc/localtime:/etc/localtime:ro
    environment:
      - WATCHTOWER_NOTIFICATIONS=slack
      - WATCHTOWER_NOTIFICATION_SLACK_HOOK_URL="https://hooks.slack.com/services/TXXXXX/BXXXXX/XXXXXXXX"
      - WATCHTOWER_NOTIFICATION_SLACK_IDENTIFIER=watchtower-server-01
      - WATCHTOWER_NOTIFICATION_SLACK_CHANNEL=#watchtower
      - WATCHTOWER_LABEL_ENABLE=true
      - WATCHTOWER_SCHEDULE=0 0 4 * * *
    labels:
      - "com.centurylinklabs.watchtower.enable=true"

Änderungen:

version: "3"
services:
  watchtower:
    image: containrrr/watchtower
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - /etc/localtime:/etc/localtime:ro
    environment:
      - WATCHTOWER_NOTIFICATIONS=slack
      - WATCHTOWER_NOTIFICATION_SLACK_HOOK_URL="https://hooks.slack.com/services/TXXXXX/BXXXXX/XXXXXXXX"
      - WATCHTOWER_NOTIFICATION_SLACK_IDENTIFIER=watchtower-server-01
      - WATCHTOWER_NOTIFICATION_SLACK_CHANNEL=#watchtower
      - WATCHTOWER_LABEL_ENABLE=true
      - WATCHTOWER_SCHEDULE=0 0 4 * * *
      - WATCHTOWER_CLEANUP=true # Mit dieser Option werden nach dem Start des neuen Images die alten entfernt
    labels:
      - "com.centurylinklabs.watchtower.enable=true"