Centrálne automatické aktualizácie Docker kontajnerov pomocou Watchtoweru, mTLS a e-mailových notifikácií

Pri väčšom počte Docker hostov začne byť ručné kontrolovanie nových image pomerne otravné. Na jednom serveri beží monitoring, na inom mailové služby, inde vlastné aplikácie a postupne sa z jednoduchého prostredia stáva infraštruktúra, kde treba mať aktualizácie pod kontrolou.

Cieľom tejto dokumentácie je ukázať, ako som nasadil centrálne riadený Watchtower, ktorý automaticky aktualizuje iba vybrané Docker kontajnery na vzdialených hostoch.

1. Návrh riešenia a architektúra

Riešenie som navrhol tak, aby Watchtower:

  • bežal centrálne na jednom serveri,
  • pristupoval k vzdialeným Docker daemon-om cez zabezpečené mTLS spojenie,
  • aktualizoval iba explicitne povolené kontajnery,
  • neposielal zbytočné notifikácie pri každej kontrole,
  • poslal e-mail pri úspešnom update alebo chybe,
  • nezasahoval do kritických služieb ako databázy, Mailcow, FreeIPA alebo ďalšie infraštruktúrne komponenty.

Použitá architektúra vyzerá nasledovne:

Na serveri 10.10.8.6 teda bežia dve nezávislé Watchtower inštancie:

watchtower-84
watchtower-85

Každá z nich sa pripája k jednému konkrétnemu Docker hostu.

Prvá spravuje:

10.10.8.4

Druhá spravuje:

10.10.8.5

čiže logika je:

Výhodou tohto riešenia je, že na vzdialených serveroch nemusí bežať ďalší Watchtower kontajner. Centrálne miesto zároveň umožňuje jednoduchšie spravovať certifikáty, notifikácie a harmonogram aktualizácií.

Prečo nepoužiť Docker API bez TLS

Docker daemon je veľmi privilegovaná služba. Klient, ktorý má plný prístup k Docker API, môže vytvárať kontajnery, mountovať filesystem hosta a v praxi tým môže získať veľmi vysoké oprávnenia na danom serveri.

Preto som nepoužil nezabezpečený Docker API endpoint:

tcp://10.10.8.4:2375

Namiesto toho používam:

tcp://10.10.8.4:2376
tcp://10.10.8.5:2376

s mTLS autentifikáciou.

Pri mTLS sa neoveruje iba server voči klientovi, ale aj klient voči serveru.

To znamená, že samotná znalosť IP adresy a portu nestačí.

Bez správneho klientského certifikátu Docker spojenie odmietne.

Pri teste bez klientského certifikátu sme dostali:

tlsv13 alert certificate required

a pri použití správneho certifikátu:

OK

To je presne stav, ktorý chceme.

Prečo nepovoliť automatické aktualizácie všetkého

Watchtower vie veľmi jednoducho aktualizovať všetky kontajnery, ale pri produkčnom alebo domácom infra prostredí to podľa mňa nie je dobrý prístup.

Niektoré služby môžu pri novej verzii:

meniť databázovú schému,
vyžadovať migráciu,
meniť formát konfigurácie,
meniť API,
vyžadovať koordinovaný upgrade viacerých komponentov.

Preto používam label-only režim.

Watchtower aktualizuje iba kontajnery, ktoré majú explicitne:

labels:
  - "com.centurylinklabs.watchtower.enable=true"

V mojom prípade sú automaticky aktualizované napríklad:

Element
ChangeDetection
Browserless Chrome
Grafana

Naopak automaticky neaktualizujem:

Mailcow
Synapse
Zabbix
MariaDB
PostgreSQL
Passbolt
NetBox
FreePBX
FreeIPA
vlastné kontajnery

Pri týchto službách preferujem klasický postup:

backup
kontrola release notes
ručný update
kontrola aplikácie

To je bezpečnejšie a dáva väčšiu kontrolu nad prípadnými migráciami alebo zmenami.

E-mailové notifikácie

Súčasťou riešenia sú aj e-mailové notifikácie.

Watchtower odosiela správy cez SMTP účet:

updater@ibasterisk.eu

Používa sa samostatný App Password s povoleným iba SMTP protokolom.

Komunikácia prebieha cez:

SMTP port 587
STARTTLS

Heslo nie je uložené priamo v docker-compose.yml, ale v samostatnom súbore s prístupom iba pre root.

Watchtower neposiela mail pri každej nočnej kontrole.

Správa sa odošle iba vtedy, keď:

sa kontajner aktualizuje
alebo
update skončí chybou

Tým sa zabráni zbytočnému spamu.

2. Vytvorenie vlastnej Docker CA a certifikátov pre mTLS

Pre zabezpečenú komunikáciu medzi centrálnym Watchtower serverom a vzdialenými Docker daemonmi som použil vlastnú certifikačnú autoritu určenú výhradne pre Docker API.

Certifikáty vytváram centrálne na serveri:

10.10.8.6
freeipa.ibasterisk.local

Docker CA bude následne podpisovať:

serverový certifikát pre 10.10.8.4
serverový certifikát pre 10.10.8.5
klientsky certifikát pre Watchtower

Architektúra certifikátov teda vyzerá nasledovne:

Vďaka tomu Docker daemon vie overiť, že prichádzajúci klient je skutočne náš Watchtower, a Watchtower zároveň overí identitu vzdialeného Docker servera.

Vytvorenie adresára pre PKI

Na serveri 10.10.8.6 som vytvoril samostatný adresár:

sudo mkdir -p /etc/watchtower-pki
sudo chmod 700 /etc/watchtower-pki

Následne som prešiel do root shellu:

sudo -i
cd /etc/watchtower-pki

Obsah tohto adresára je dostupný iba používateľovi root.

Vytvorenie Docker CA

Najskôr som vytvoril privátny kľúč certifikačnej autority:

openssl genrsa -out docker-ca-key.pem 4096

Potom samotný CA certifikát:

openssl req \
  -new \
  -x509 \
  -days 3650 \
  -key docker-ca-key.pem \
  -sha256 \
  -out docker-ca.pem \
  -subj "/CN=iBasterisk Docker CA"

CA je platná desať rokov. Privátny kľúč CA je najcitlivejší súbor v celom riešení.

Nastavil som preto práva:

chmod 400 docker-ca-key.pem
chmod 444 docker-ca.pem

Privátny kľúč:

docker-ca-key.pem

zostáva iba na 10.10.8.6.

Na vzdialené Docker servery sa nikdy nekopíruje.

Serverový certifikát pre Docker host 10.10.8.4

Pre prvý Docker host som vytvoril samostatný privátny kľúč:

openssl genrsa -out docker-10.10.8.4-key.pem 4096
openssl req \
  -subj "/CN=10.10.8.4" \
  -sha256 \
  -new \
  -key docker-10.10.8.4-key.pem \
  -out docker-10.10.8.4.csr

Samotné CN však pri modernom TLS nestačí. Certifikát musí obsahovať správny Subject Alternative Name.

Preto som vytvoril:

cat > docker-10.10.8.4-ext.cnf <<'EOF'
subjectAltName = IP:10.10.8.4,DNS:mail-ibasterisk
extendedKeyUsage = serverAuth
EOF

Certifikát som následne podpísal Docker CA:

openssl x509 \
  -req \
  -days 825 \
  -sha256 \
  -in docker-10.10.8.4.csr \
  -CA docker-ca.pem \
  -CAkey docker-ca-key.pem \
  -CAcreateserial \
  -out docker-10.10.8.4-cert.pem \
  -extfile docker-10.10.8.4-ext.cnf

Dôležitá je najmä hodnota:

extendedKeyUsage = serverAuth

Tým explicitne určujeme, že certifikát slúži na autentifikáciu TLS servera.

Výsledok som overil:

openssl x509 \
  -in docker-10.10.8.4-cert.pem \
  -noout \
  -subject \
  -issuer \
  -dates \
  -ext subjectAltName \
  -ext extendedKeyUsage

Výstup obsahoval:

subject=CN = 10.10.8.4
issuer=CN = iBasterisk Docker CA

a:

IP Address:10.10.8.4
DNS:mail-ibasterisk

plus:

TLS Web Server Authentication

SAN som si ešte samostatne overil:

openssl x509 \
  -in docker-10.10.8.4-cert.pem \
  -noout -text | grep -A2 "Subject Alternative Name"

Výsledok:

X509v3 Subject Alternative Name:
    IP Address:10.10.8.4, DNS:mail-ibasterisk

Serverový certifikát pre Docker host 10.10.8.5

Rovnakým spôsobom som vytvoril certifikát pre monitoring server:

10.10.8.5
mon.ibasterisk.local

Privátny kľúč:

openssl genrsa -out docker-10.10.8.5-key.pem 4096

CSR:

openssl req \
  -subj "/CN=10.10.8.5" \
  -sha256 \
  -new \
  -key docker-10.10.8.5-key.pem \
  -out docker-10.10.8.5.csr

SAN konfigurácia:

cat > docker-10.10.8.5-ext.cnf <<'EOF'
subjectAltName = IP:10.10.8.5,DNS:mon.ibasterisk.local
extendedKeyUsage = serverAuth
EOF

A podpis:

openssl x509 \
  -req \
  -days 825 \
  -sha256 \
  -in docker-10.10.8.5.csr \
  -CA docker-ca.pem \
  -CAkey docker-ca-key.pem \
  -CAserial docker-ca.srl \
  -out docker-10.10.8.5-cert.pem \
  -extfile docker-10.10.8.5-ext.cnf

Kontrola SAN:

openssl x509 \
  -in docker-10.10.8.5-cert.pem \
  -noout -text | grep -A2 "Subject Alternative Name"

Výsledok:

X509v3 Subject Alternative Name:
    IP Address:10.10.8.5, DNS:mon.ibasterisk.local

Klientsky certifikát pre Watchtower

Serverové certifikáty máme hotové. Teraz potrebujeme certifikát, ktorým sa bude Watchtower autentifikovať voči Docker daemonu.

Vytvoril som privátny kľúč:

openssl genrsa -out watchtower-key.pem 4096

A CSR:

openssl req \
  -subj "/CN=watchtower-10.10.8.6" \
  -new \
  -sha256 \
  -key watchtower-key.pem \
  -out watchtower.csr

Tentokrát nejde o serverový, ale o klientsky certifikát.

Preto som vytvoril:

cat > watchtower-ext.cnf <<'EOF'
extendedKeyUsage = clientAuth
EOF

Certifikát som podpísal rovnakou Docker CA:

openssl x509 \
  -req \
  -days 825 \
  -sha256 \
  -in watchtower.csr \
  -CA docker-ca.pem \
  -CAkey docker-ca-key.pem \
  -CAserial docker-ca.srl \
  -out watchtower-cert.pem \
  -extfile watchtower-ext.cnf

Privátny kľúč klienta som zabezpečil:

chmod 400 watchtower-key.pem
chmod 444 watchtower-cert.pem

Kontrola:

openssl x509 \
  -in watchtower-cert.pem \
  -noout \
  -subject \
  -issuer \
  -dates \
  -ext extendedKeyUsage

Výsledok:

subject=CN=watchtower-10.10.8.6
issuer=CN=iBasterisk Docker CA

a hlavne:

TLS Web Client Authentication

To potvrdzuje, že certifikát je určený na autentifikáciu klienta.

Čo máme v tejto chvíli pripravené

Na centrálnom serveri máme približne:

/etc/watchtower-pki/
│
├── docker-ca.pem
├── docker-ca-key.pem
├── docker-ca.srl
│
├── docker-10.10.8.4-cert.pem
├── docker-10.10.8.4-key.pem
├── docker-10.10.8.4.csr
│
├── docker-10.10.8.5-cert.pem
├── docker-10.10.8.5-key.pem
├── docker-10.10.8.5.csr
│
├── watchtower-cert.pem
├── watchtower-key.pem
└── watchtower.csr

Z pohľadu bezpečnosti je najdôležitejšie:

docker-ca-key.pem

Tento súbor nesmie opustiť centrálny PKI server.

Na vzdialené Docker hosty pôjdu iba ich vlastné serverové certifikáty, serverové privátne kľúče a verejný certifikát CA.

Na 10.10.8.4 teda neskôr skončí:

ca.pem
server-cert.pem
server-key.pem

a rovnako na 10.10.8.5.

Watchtower na 10.10.8.6 bude používať:

docker-ca.pem
watchtower-cert.pem
watchtower-key.pem

3. Konfigurácia Docker daemonu pre vzdialený prístup cez mTLS

Po vytvorení certifikátov je ďalším krokom sprístupnenie Docker API na vzdialených hostoch.

V mojom prípade ide o:

10.10.8.4
10.10.8.5

Docker bude na oboch serveroch naďalej používať lokálny socket:

/var/run/docker.sock

a zároveň pribudne zabezpečený TCP listener:

10.10.8.4:2376
10.10.8.5:2376

Port 2376 používam výhradne s TLS a overovaním klientského certifikátu.

Architektúra vyzerá takto:

Kontrola existujúcej Docker konfigurácie

Pred akoukoľvek zmenou odporúčam najskôr zistiť, ako je Docker daemon aktuálne spúšťaný:

sudo systemctl cat docker | grep -E '^\[Service\]|^ExecStart'

V mojom prípade bol Docker spúšťaný takto:

ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock

Taktiež som skontroloval:

sudo ss -lntp | grep -E ':(2375|2376)\b'

Pred konfiguráciou nevystupoval žiadny listener:

2375/2376 momentalne nepocuvaju

To je správny východiskový stav.

Prenos serverových certifikátov

Na každý Docker host potrebujeme iba:

CA certificate
server certificate
server private key

Nikdy tam neposielame:

docker-ca-key.pem

Privátny kľúč CA zostáva iba na centrálnom PKI serveri.

Na Docker hoste som vytvoril:

sudo mkdir -p /etc/docker/tls
sudo chmod 700 /etc/docker/tls

Výsledné súbory sú:

/etc/docker/tls/ca.pem
/etc/docker/tls/server-cert.pem
/etc/docker/tls/server-key.pem

Nastavenie práv:

sudo chmod 444 /etc/docker/tls/ca.pem
sudo chmod 444 /etc/docker/tls/server-cert.pem
sudo chmod 400 /etc/docker/tls/server-key.pem

Výsledok:

-r--r--r-- ca.pem
-r--r--r-- server-cert.pem
-r-------- server-key.pem

Overenie certifikátu

Pred reštartom Dockeru som overil, že serverový certifikát je skutočne podpísaný našou CA:

sudo openssl verify \
  -CAfile /etc/docker/tls/ca.pem \
  /etc/docker/tls/server-cert.pem

Výsledok musí byť:

/etc/docker/tls/server-cert.pem: OK

Ďalej som overil, že certifikát a privátny kľúč patria k sebe.

Certifikát:

sudo openssl x509 \
  -in /etc/docker/tls/server-cert.pem \
  -pubkey -noout | sha256sum

Privátny kľúč:

sudo openssl pkey \
  -in /etc/docker/tls/server-key.pem \
  -pubout | sha256sum

Obidva SHA256 hashe musia byť rovnaké.

Napríklad:

25b4724dd654398c4da2b89acf2402f424682ea171c527de363854278acb03f4
25b4724dd654398c4da2b89acf2402f424682ea171c527de363854278acb03f4

Až potom pokračujem konfiguráciou Docker daemonu.

Zapnutie live-restore

Keďže na Docker hostoch bežia produkčné služby, nechcel som, aby krátky reštart samotného Docker daemonu automaticky ukončil všetky bežiace kontajnery.

Preto používam:

"live-restore": true

Na 10.10.8.4, kde pôvodne daemon.json neexistoval, som vytvoril:

sudo nano /etc/docker/daemon.json
{
  "live-restore": true
}

Na 10.10.8.5 som už mal definované DNS servery, takže výsledok vyzeral napríklad takto:

{
  "dns": ["10.10.8.2", "8.8.8.8", "1.1.1.1"],
  "live-restore": true
}

Pred použitím som syntax vždy overil:

sudo dockerd --validate --config-file=/etc/docker/daemon.json

Správny výsledok:

configuration OK

Následne stačí reload:

sudo systemctl reload docker

A kontrola:

sudo docker info | grep -i "Live Restore"

Výsledok:

Live Restore Enabled: true

Systemd override pre Docker API

Keďže Docker už bol spúšťaný cez:

-H fd://

nepridával som parameter hosts do daemon.json.

Namiesto toho som použil systemd override.

Pre host 10.10.8.4:

sudo mkdir -p /etc/systemd/system/docker.service.d
sudo tee /etc/systemd/system/docker.service.d/remote-tls.conf >/dev/null <<'EOF'
[Service]
ExecStart=
ExecStart=/usr/bin/dockerd -H fd:// -H tcp://10.10.8.4:2376 --tlsverify --tlscacert=/etc/docker/tls/ca.pem --tlscert=/etc/docker/tls/server-cert.pem --tlskey=/etc/docker/tls/server-key.pem --containerd=/run/containerd/containerd.sock
EOF

Pre 10.10.8.5 je konfigurácia rovnaká, mení sa iba IP:

sudo tee /etc/systemd/system/docker.service.d/remote-tls.conf >/dev/null <<'EOF'
[Service]
ExecStart=
ExecStart=/usr/bin/dockerd -H fd:// -H tcp://10.10.8.5:2376 --tlsverify --tlscacert=/etc/docker/tls/ca.pem --tlscert=/etc/docker/tls/server-cert.pem --tlskey=/etc/docker/tls/server-key.pem --containerd=/run/containerd/containerd.sock
EOF

Dôležitá je dvojica:

-H fd://
-H tcp://10.10.8.x:2376

Prvá zachováva lokálny Docker socket.

Druhá pridáva vzdialený TLS listener.

Parameter:

--tlsverify

znamená, že Docker nebude iba šifrovať komunikáciu, ale bude zároveň vyžadovať platný klientsky certifikát podpísaný našou CA.

Načítanie systemd konfigurácie

Po vytvorení override:

sudo systemctl daemon-reload

Pred reštartom som si ešte skontroloval výsledný ExecStart:

sudo systemctl show docker -p ExecStart --no-pager

Na 10.10.8.5 napríklad:

/usr/bin/dockerd
-H fd://
-H tcp://10.10.8.5:2376
--tlsverify
--tlscacert=/etc/docker/tls/ca.pem
--tlscert=/etc/docker/tls/server-cert.pem
--tlskey=/etc/docker/tls/server-key.pem
--containerd=/run/containerd/containerd.sock

Ak to sedí, Docker môžeme reštartovať:

sudo systemctl restart docker

Kontrola služby

Po reštarte:

sudo systemctl is-active docker

Výsledok:

active

A kontrola TCP listenera:

sudo ss -lntp | grep 2376
Na prvom hoste:

LISTEN ... 10.10.8.4:2376 ... dockerd

Na druhom hoste:

LISTEN ... 10.10.8.5:2376 ... dockerd

Tým je TLS Docker API aktívne.

Kontrola kontajnerov po reštarte

Po zásahu som si vždy overil existujúce kontajnery:

sudo docker ps --format 'table {{.Names}}\t{{.Status}}\t{{.Image}}'

Keďže som mal zapnuté:

Live Restore Enabled: true

kontajnery zostali počas reštartu Docker daemonu bežať.

Pri produkčnom hoste je to veľmi užitočné, ale stále odporúčam robiť podobnú zmenu v čase, keď prípadný krátky výpadok nie je kritický.

Test mTLS z Watchtower servera

Teraz môžeme z 10.10.8.6 overiť, či Docker API skutočne vyžaduje klientsky certifikát.

Prejdeme do PKI adresára:

sudo -i
cd /etc/watchtower-pki

Test so správnym klientskym certifikátom

Pre 10.10.8.4:

curl \
  --cacert docker-ca.pem \
  --cert watchtower-cert.pem \
  --key watchtower-key.pem \
  https://10.10.8.4:2376/_ping

Správny výsledok:

OK

Pre druhý host:

curl \
  --cacert docker-ca.pem \
  --cert watchtower-cert.pem \
  --key watchtower-key.pem \
  https://10.10.8.5:2376/_ping

Výsledok:

OK

To znamená, že:

server certificate       OK
CA trust                 OK
client certificate       OK
private key              OK
network connectivity     OK
Docker TLS API           OK

Test bez klientského certifikátu

Veľmi dôležitý je aj opačný test.

curl \
  --cacert docker-ca.pem \
  https://10.10.8.4:2376/_ping

Docker spojenie odmietne:

OpenSSL SSL_read:
tlsv13 alert certificate required

Rovnako na .5:

curl \
  --cacert docker-ca.pem \
  https://10.10.8.5:2376/_ping

opäť:

Odporúčané dodatočné zabezpečenie firewallom

mTLS je hlavná ochranná vrstva, ale v produkčnom prostredí by som port 2376 navyše obmedzil firewallom tak, aby bol dostupný iba z Watchtower servera:

10.10.8.6

Logicky teda:

10.10.8.6 → 10.10.8.4:2376    ALLOW
10.10.8.6 → 10.10.8.5:2376    ALLOW

ostatné zdrojové IP             DENY

V mojom pôvodnom nasadení bol UFW na hostoch vypnutý, takže toto je ďalšia hardening vrstva, ktorú je vhodné doplniť podľa používaného firewallu.

Ak sa používa UFW, princíp môže byť napríklad:

sudo ufw allow from 10.10.8.6 to any port 2376 proto tcp

Samotné zapnutie UFW však netreba robiť naslepo na vzdialenom serveri — pred jeho aktiváciou treba mať povolené aj SSH a všetky ostatné produkčné porty.

Upratanie PKI materiálu

Po úspešnom nasadení odporúčam z Docker hostov odstrániť všetky dočasné CSR súbory a najmä akékoľvek omylom prenesené CA privátne kľúče.

Na vzdialenom Docker hoste majú zostať iba:

/etc/docker/tls/
├── ca.pem
├── server-cert.pem
└── server-key.pem

Privátny kľúč CA:

docker-ca-key.pem

má zostať výhradne na PKI serveri.

Výsledok

Po dokončení tejto kapitoly máme pripravenú zabezpečenú komunikačnú vrstvu:

Docker API je dostupné vzdialene, ale klient bez platného certifikátu sa k nemu nedostane.

V ďalšej kapitole môžeme spraviť 4. Nasadenie centrálneho Watchtoweru na 10.10.8.6 — celé docker-compose.yml pre watchtower-84 a watchtower-85, plánovanie o 03:00/03:30, label-enable, cleanup a vysvetlenie, prečo používame dve Watchtower inštancie.

4. Inštalácia centrálneho Watchtower servera

Watchtower v tomto riešení neinštalujem ako systémový balík. Beží ako klasický Docker kontajner na centrálnom serveri:

10.10.8.6
freeipa.ibasterisk.local

Predpokladom je funkčný Docker a Docker Compose.

Kontrola:

docker version
docker compose version

Ak používateľ nemá prístup k /var/run/docker.sock, príkazy je možné spúšťať cez:

sudo docker ...

V mojom prípade používam udržiavaný Watchtower image:

nickfedor/watchtower:latest

Na serveri som vytvoril dva samostatné projekty:

sudo mkdir -p /opt/watchtower-84
sudo mkdir -p /opt/watchtower-85

Každá inštancia spravuje jeden vzdialený Docker daemon:

watchtower-84 → 10.10.8.4
watchtower-85 → 10.10.8.5

Takto zostáva konfigurácia jednoduchá a každá inštancia môže mať vlastný harmonogram.

Helper skript na vytvorenie Docker CA

Namiesto ručného zadávania všetkých príkazov môžeme v dokumentácii ponúknuť aj skript.

Napríklad:

sudo nano /usr/local/sbin/create-docker-ca.sh

Obsah:

#!/usr/bin/env bash
set -Eeuo pipefail
umask 077

PKI_DIR="/etc/watchtower-pki"

mkdir -p "$PKI_DIR"
chmod 700 "$PKI_DIR"

cd "$PKI_DIR"

if [[ -f docker-ca-key.pem || -f docker-ca.pem ]]; then
    echo "ERROR: Docker CA already exists."
    exit 1
fi

echo "Creating Docker CA private key..."

openssl genrsa \
    -out docker-ca-key.pem \
    4096

echo "Creating Docker CA certificate..."

openssl req \
    -new \
    -x509 \
    -days 3650 \
    -key docker-ca-key.pem \
    -sha256 \
    -out docker-ca.pem \
    -subj "/CN=iBasterisk Docker CA"

chmod 400 docker-ca-key.pem
chmod 444 docker-ca.pem

echo
echo "Docker CA created:"
echo "  $PKI_DIR/docker-ca.pem"
echo "  $PKI_DIR/docker-ca-key.pem"

Nastavenie práv:

sudo chmod 700 /usr/local/sbin/create-docker-ca.sh

Spustenie:

sudo /usr/local/sbin/create-docker-ca.sh

Výhodou je, že skript skončí chybou, ak CA už existuje. Nemôže teda nepozornosťou prepísať existujúcu certifikačnú autoritu.

Skript na vytvorenie serverového Docker certifikátu

Ďalší helper môže generovať certifikát pre ľubovoľný Docker host.

sudo nano /usr/local/sbin/create-docker-server-cert.sh

Obsah:

#!/usr/bin/env bash
set -Eeuo pipefail
umask 077

PKI_DIR="/etc/watchtower-pki"

if [[ $# -ne 2 ]]; then
    echo "Usage:"
    echo "  $0 <IP_ADDRESS> <DNS_NAME>"
    echo
    echo "Example:"
    echo "  $0 10.10.8.5 mon.ibasterisk.local"
    exit 1
fi

IP="$1"
DNS="$2"

cd "$PKI_DIR"

CA_CERT="docker-ca.pem"
CA_KEY="docker-ca-key.pem"

KEY="docker-${IP}-key.pem"
CSR="docker-${IP}.csr"
CERT="docker-${IP}-cert.pem"
EXT="docker-${IP}-ext.cnf"

if [[ ! -f "$CA_CERT" || ! -f "$CA_KEY" ]]; then
    echo "ERROR: Docker CA not found."
    exit 1
fi

if [[ -f "$KEY" || -f "$CERT" ]]; then
    echo "ERROR: Certificate for $IP already exists."
    exit 1
fi

echo "Creating private key for $IP..."

openssl genrsa \
    -out "$KEY" \
    4096

echo "Creating CSR..."

openssl req \
    -subj "/CN=${IP}" \
    -sha256 \
    -new \
    -key "$KEY" \
    -out "$CSR"

cat > "$EXT" <<EOF
subjectAltName = IP:${IP},DNS:${DNS}
extendedKeyUsage = serverAuth
EOF

echo "Signing certificate..."

openssl x509 \
    -req \
    -days 825 \
    -sha256 \
    -in "$CSR" \
    -CA "$CA_CERT" \
    -CAkey "$CA_KEY" \
    -CAserial docker-ca.srl \
    -CAcreateserial \
    -out "$CERT" \
    -extfile "$EXT"

chmod 400 "$KEY"
chmod 444 "$CERT"

echo
echo "Certificate created:"
echo "  $CERT"
echo "  $KEY"
echo
echo "Certificate details:"
openssl x509 \
    -in "$CERT" \
    -noout \
    -subject \
    -issuer \
    -dates

openssl x509 \
    -in "$CERT" \
    -noout -text |
    grep -A2 "Subject Alternative Name"

Práva:

sudo chmod 700 /usr/local/sbin/create-docker-server-cert.sh

Pre prvý host:

sudo /usr/local/sbin/create-docker-server-cert.sh \
  10.10.8.4 \
  mail-ibasterisk

Pre druhý:

sudo /usr/local/sbin/create-docker-server-cert.sh \
  10.10.8.5 \
  mon.ibasterisk.local

Takto sa veľmi pekne zjednoduší celá PKI časť dokumentácie.

Skript na vytvorenie Watchtower klientského certifikátu

Rovnako môžeme automatizovať aj klientsky certifikát.

sudo nano /usr/local/sbin/create-watchtower-client-cert.sh

Obsah:

#!/usr/bin/env bash
set -Eeuo pipefail
umask 077

PKI_DIR="/etc/watchtower-pki"

cd "$PKI_DIR"

if [[ ! -f docker-ca.pem || ! -f docker-ca-key.pem ]]; then
    echo "ERROR: Docker CA not found."
    exit 1
fi

if [[ -f watchtower-key.pem || -f watchtower-cert.pem ]]; then
    echo "ERROR: Watchtower certificate already exists."
    exit 1
fi

openssl genrsa \
    -out watchtower-key.pem \
    4096

openssl req \
    -subj "/CN=watchtower-10.10.8.6" \
    -new \
    -sha256 \
    -key watchtower-key.pem \
    -out watchtower.csr

cat > watchtower-ext.cnf <<'EOF'
extendedKeyUsage = clientAuth
EOF

openssl x509 \
    -req \
    -days 825 \
    -sha256 \
    -in watchtower.csr \
    -CA docker-ca.pem \
    -CAkey docker-ca-key.pem \
    -CAserial docker-ca.srl \
    -out watchtower-cert.pem \
    -extfile watchtower-ext.cnf

chmod 400 watchtower-key.pem
chmod 444 watchtower-cert.pem

echo
echo "Watchtower client certificate created."
echo

openssl x509 \
    -in watchtower-cert.pem \
    -noout \
    -subject \
    -issuer \
    -dates \
    -ext extendedKeyUsage

Spustenie:

sudo chmod 700 /usr/local/sbin/create-watchtower-client-cert.sh
sudo /usr/local/sbin/create-watchtower-client-cert.sh

Na konci chceme:

TLS Web Client Authentication

Bezpečné vytvorenie SMTP secretu

Určite by som do článku dal aj helper, ktorý sme používali na SMTP.

Výhoda je, že App Password nemusíme zadávať priamo do shell príkazu a tým pádom sa neobjaví v shell histórii.

Najprv:

sudo mkdir -p /etc/watchtower-notify
sudo chmod 700 /etc/watchtower-notify

Helper:

sudo nano /tmp/create-watchtower-smtp.py

Obsah:

import os
import getpass
from urllib.parse import quote, urlencode

smtp_host = input("SMTP hostname: ").strip()
mail_to = input("Notification recipient: ").strip()
password = getpass.getpass(
    "App Password for updater@ibasterisk.eu: "
)

username = "updater@ibasterisk.eu"

query = urlencode({
    "fromaddress": username,
    "toaddresses": mail_to,
    "encryption": "ExplicitTLS",
    "usestarttls": "yes",
    "auth": "Plain",
    "timeout": "30s",
})

url = (
    "smtp://"
    + quote(username, safe="")
    + ":"
    + quote(password, safe="")
    + "@"
    + smtp_host
    + ":587/?"
    + query
)

path = "/etc/watchtower-notify/notification-url.txt"

with open(path, "w") as f:
    f.write(url + "\n")

os.chmod(path, 0o600)

print("SMTP secret created:", path)

Spustenie:

sudo python3 /tmp/create-watchtower-smtp.py

Program sa opýta:

SMTP hostname:
Notification recipient:
App Password for updater@ibasterisk.eu:

Pri zadávaní hesla sa nič nezobrazuje.

Po vytvorení:

sudo rm -f /tmp/create-watchtower-smtp.py

Kontrola:

sudo ls -l /etc/watchtower-notify/notification-url.txt

Výsledok:

-rw------- 1 root root ... notification-url.txt

Dôležité:

cat /etc/watchtower-notify/notification-url.txt

nepoužívame, pretože URL obsahuje SMTP App Password.

Inštalácia samotného Watchtoweru

Po pripravení PKI nemusíme inštalovať žiadny ďalší balík.

Vytvoríme Compose projekt:

sudo mkdir -p /opt/watchtower-84

A napríklad:

sudo nano /opt/watchtower-84/docker-compose.yml

Minimálna verzia ešte bez mailov môže vyzerať:

services:
  watchtower-84:
    image: nickfedor/watchtower:latest
    container_name: watchtower-84
    restart: unless-stopped

    environment:
      TZ: Europe/Bratislava

      DOCKER_HOST: tcp://10.10.8.4:2376
      DOCKER_TLS_VERIFY: "1"
      DOCKER_CERT_PATH: /certs

      WATCHTOWER_LABEL_ENABLE: "true"
      WATCHTOWER_CLEANUP: "true"
      WATCHTOWER_SCHEDULE: "0 0 3 * * *"

    volumes:
      - /etc/watchtower-pki/docker-ca.pem:/certs/ca.pem:ro
      - /etc/watchtower-pki/watchtower-cert.pem:/certs/cert.pem:ro
      - /etc/watchtower-pki/watchtower-key.pem:/certs/key.pem:ro

Kontrola:

cd /opt/watchtower-84
sudo docker compose config

Stiahnutie image:

sudo docker compose pull

Spustenie:

sudo docker compose up -d

Kontrola:

sudo docker ps --filter name=watchtower-84

A log:

sudo docker logs watchtower-84 --tail 50

Pri úspešnom pripojení sme napríklad videli:

Watchtower 1.22.1 using Docker API v1.55
Next scheduled run: 2026-09-15 03:00:00 CEST

Pre druhý Docker host vytvoríme samostatne:

/opt/watchtower-85/

s:

DOCKER_HOST: tcp://10.10.8.5:2376
WATCHTOWER_SCHEDULE: "0 30 3 * * *"

Teda:

03:00 → Docker 10.10.8.4
03:30 → Docker 10.10.8.5

5. Finálna konfigurácia Watchtoweru s e-mailovými notifikáciami

Po overení komunikácie cez mTLS a základnom spustení Watchtoweru môžeme prejsť na finálnu konfiguráciu, ktorú používam v produkcii.

Na centrálnom serveri 10.10.8.6 bežia dve samostatné Watchtower inštancie:

watchtower-84 → Docker host 10.10.8.4
watchtower-85 → Docker host 10.10.8.5

Každá inštancia má vlastný harmonogram, vlastné označenie v notifikáciách a pripája sa iba k jednému vzdialenému Docker daemonu.

Aktualizácie som rozdelil časovo:

03:00 → 10.10.8.4
03:30 → 10.10.8.5

Tým sa oba servery nekontrolujú a prípadne neaktualizujú naraz.

5.1 Šablóna e-mailových notifikácií

Najskôr som vytvoril spoločnú šablónu, ktorú používajú obe Watchtower inštancie:

sudo nano /etc/watchtower-notify/update-template.txt

Obsah:

{{- if .Report -}}
{{- with .Report -}}
{{- if or .Updated .Failed -}}
Watchtower - {{.Host}}

Scanned: {{len .Scanned}}
Updated: {{len .Updated}}
Failed: {{len .Failed}}

{{- range .Updated}}

UPDATED: {{.Name}}
Image: {{.ImageName}}
{{- end}}

{{- range .Failed}}

FAILED: {{.Name}}
Image: {{.ImageName}}
Error: {{.Error}}
{{- end}}
{{- end -}}
{{- end -}}
{{- end -}}

Následne som nastavil práva:

sudo chmod 444 /etc/watchtower-notify/update-template.txt

Táto šablóna je zámerne navrhnutá tak, aby vytvorila obsah správy iba v prípade, že:

kontajner bol aktualizovaný
alebo
aktualizácia skončila chybou

Ak Watchtower iba skontroluje image a nič sa nezmenilo, šablóna nevytvorí obsah správy a zbytočný e-mail sa neodošle.

Výsledný adresár s notifikačnými súbormi teda obsahuje:

/etc/watchtower-notify/
├── notification-url.txt
└── update-template.txt

SMTP URL obsahujúce App Password zostáva:

-rw------- root root notification-url.txt

zatiaľ čo samotná šablóna môže byť iba na čítanie:

-r--r--r-- root root update-template.txt

5.2 Finálna konfigurácia watchtower-84

Prvá inštancia spravuje Docker host:

10.10.8.4

Konfigurácia sa nachádza v:

/opt/watchtower-84/docker-compose.yml

Súbor som vytvoril:

sudo nano /opt/watchtower-84/docker-compose.yml

Finálna konfigurácia:

services:
  watchtower-84:
    image: nickfedor/watchtower:latest
    container_name: watchtower-84
    restart: unless-stopped

    environment:
      TZ: Europe/Bratislava

      DOCKER_HOST: tcp://10.10.8.4:2376
      DOCKER_TLS_VERIFY: "1"
      DOCKER_CERT_PATH: /certs

      WATCHTOWER_LABEL_ENABLE: "true"
      WATCHTOWER_CLEANUP: "true"
      WATCHTOWER_SCHEDULE: "0 0 3 * * *"

      WATCHTOWER_NOTIFICATION_URL: /notify/notification-url.txt
      WATCHTOWER_NOTIFICATION_REPORT: "true"
      WATCHTOWER_NOTIFICATION_TEMPLATE_FILE: /notify/update-template.txt
      WATCHTOWER_NO_STARTUP_MESSAGE: "true"
      WATCHTOWER_NOTIFICATIONS_HOSTNAME: "docker-10.10.8.4"

    volumes:
      - /etc/watchtower-pki/docker-ca.pem:/certs/ca.pem:ro
      - /etc/watchtower-pki/watchtower-cert.pem:/certs/cert.pem:ro
      - /etc/watchtower-pki/watchtower-key.pem:/certs/key.pem:ro

      - /etc/watchtower-notify/notification-url.txt:/notify/notification-url.txt:ro
      - /etc/watchtower-notify/update-template.txt:/notify/update-template.txt:ro

Pred spustením som konfiguráciu overil:

cd /opt/watchtower-84
sudo docker compose config

Ak Compose nehlási chybu, image môžeme stiahnuť:

sudo docker compose pull

a následne spustiť:

sudo docker compose up -d

Kontrola:

sudo docker ps --filter name=watchtower-84

Log:

sudo docker logs watchtower-84 --tail 50

Pri správnej konfigurácii Watchtower oznámi, že sa pripojil k vzdialenému Docker API a vypočíta čas ďalšej kontroly.

5.3 Finálna konfigurácia watchtower-85

Druhá inštancia spravuje:

10.10.8.5

Compose súbor sa nachádza v:

/opt/watchtower-85/docker-compose.yml

Vytvorenie:

sudo nano /opt/watchtower-85/docker-compose.yml

Obsah:

services:
  watchtower-85:
    image: nickfedor/watchtower:latest
    container_name: watchtower-85
    restart: unless-stopped

    environment:
      TZ: Europe/Bratislava

      DOCKER_HOST: tcp://10.10.8.5:2376
      DOCKER_TLS_VERIFY: "1"
      DOCKER_CERT_PATH: /certs

      WATCHTOWER_LABEL_ENABLE: "true"
      WATCHTOWER_CLEANUP: "true"
      WATCHTOWER_SCHEDULE: "0 30 3 * * *"

      WATCHTOWER_NOTIFICATION_URL: /notify/notification-url.txt
      WATCHTOWER_NOTIFICATION_REPORT: "true"
      WATCHTOWER_NOTIFICATION_TEMPLATE_FILE: /notify/update-template.txt
      WATCHTOWER_NO_STARTUP_MESSAGE: "true"
      WATCHTOWER_NOTIFICATIONS_HOSTNAME: "docker-10.10.8.5"

    volumes:
      - /etc/watchtower-pki/docker-ca.pem:/certs/ca.pem:ro
      - /etc/watchtower-pki/watchtower-cert.pem:/certs/cert.pem:ro
      - /etc/watchtower-pki/watchtower-key.pem:/certs/key.pem:ro

      - /etc/watchtower-notify/notification-url.txt:/notify/notification-url.txt:ro
      - /etc/watchtower-notify/update-template.txt:/notify/update-template.txt:ro

Kontrola konfigurácie:

cd /opt/watchtower-85
sudo docker compose config

Stiahnutie image:

sudo docker compose pull

Spustenie:

sudo docker compose up -d

Kontrola:

sudo docker ps --filter name=watchtower-85

A log:

sudo docker logs watchtower-85 --tail 50

5.4 Čo znamenajú jednotlivé parametre

Najdôležitejšia časť konfigurácie je:

DOCKER_HOST: tcp://10.10.8.4:2376
DOCKER_TLS_VERIFY: "1"
DOCKER_CERT_PATH: /certs

DOCKER_HOST určuje vzdialený Docker daemon.

DOCKER_TLS_VERIFY zapína overovanie TLS certifikátov a DOCKER_CERT_PATH určuje adresár, kde Watchtower nájde:

ca.pem
cert.pem
key.pem

Tieto názvy vzniknú pomocou bind mountov:

- /etc/watchtower-pki/docker-ca.pem:/certs/ca.pem:ro
- /etc/watchtower-pki/watchtower-cert.pem:/certs/cert.pem:ro
- /etc/watchtower-pki/watchtower-key.pem:/certs/key.pem:ro

Watchtower teda privátny kľúč nekopíruje do kontajnera natrvalo. Súbor je do kontajnera pripojený iba na čítanie.

Parameter:

WATCHTOWER_LABEL_ENABLE: "true"

zapína label-only režim.

To znamená, že Watchtower nebude aktualizovať všetky kontajnery na vzdialenom serveri. Spracuje iba tie, ktoré majú:

labels:
  - "com.centurylinklabs.watchtower.enable=true"

Parameter:

WATCHTOWER_CLEANUP: "true"

spôsobí, že po úspešnej aktualizácii Watchtower odstráni starý image, ktorý už nie je potrebný.

Bez cleanupu by sa na Docker hostoch postupne hromadili staré image.

5.5 Harmonogram aktualizácií

Watchtower používa pri WATCHTOWER_SCHEDULE cron výraz so sekundami.

Prvá inštancia má:

WATCHTOWER_SCHEDULE: "0 0 3 * * *"

čo znamená:

sekunda:   0
minúta:    0
hodina:    3
deň:       každý
mesiac:    každý
deň týždňa: každý

Teda každý deň o:

03:00

Druhá inštancia používa:

WATCHTOWER_SCHEDULE: "0 30 3 * * *"

Čiže:

03:30

Časové pásmo zabezpečuje:

TZ: Europe/Bratislava

Takto sa harmonogram riadi lokálnym časom vrátane prechodu medzi letným a zimným časom.


5.6 Nastavenie notifikácií

Watchtower dostáva SMTP konfiguráciu zo súboru:

WATCHTOWER_NOTIFICATION_URL: /notify/notification-url.txt

Súbor je do kontajnera pripojený iba na čítanie:

- /etc/watchtower-notify/notification-url.txt:/notify/notification-url.txt:ro

Vďaka tomu sa SMTP App Password nenachádza priamo v:

docker-compose.yml

Reportovací režim zapína:

WATCHTOWER_NOTIFICATION_REPORT: "true"

a vlastnú šablónu určuje:

WATCHTOWER_NOTIFICATION_TEMPLATE_FILE: /notify/update-template.txt

Parameter:

WATCHTOWER_NO_STARTUP_MESSAGE: "true"

zabraňuje tomu, aby Watchtower posielal zbytočnú notifikáciu pri každom svojom spustení.

Nakoniec používam:

WATCHTOWER_NOTIFICATIONS_HOSTNAME: "docker-10.10.8.4"

alebo:

WATCHTOWER_NOTIFICATIONS_HOSTNAME: "docker-10.10.8.5"

V e-maile tak okamžite vidím, ktorého Docker hosta sa správa týka.

Napríklad:

Watchtower - docker-10.10.8.4

Scanned: 3
Updated: 1
Failed: 0

UPDATED: element
Image: vectorim/element-web:latest

Pri chybe môže report vyzerať napríklad:

Watchtower - docker-10.10.8.4

Scanned: 3
Updated: 0
Failed: 1

FAILED: changedetection
Image: dgtlmoon/changedetection.io
Error: ...

5.7 Kontrola pripojených súborov

Po spustení je vhodné overiť, že všetky bind mounty sú naozaj dostupné.

Použil som:

sudo docker inspect watchtower-84 \
  --format '{{range .Mounts}}{{println .Source "->" .Destination}}{{end}}'

A podobne:

sudo docker inspect watchtower-85 \
  --format '{{range .Mounts}}{{println .Source "->" .Destination}}{{end}}'

Výstup by mal obsahovať približne:

/etc/watchtower-pki/docker-ca.pem -> /certs/ca.pem
/etc/watchtower-pki/watchtower-cert.pem -> /certs/cert.pem
/etc/watchtower-pki/watchtower-key.pem -> /certs/key.pem
/etc/watchtower-notify/notification-url.txt -> /notify/notification-url.txt
/etc/watchtower-notify/update-template.txt -> /notify/update-template.txt

Watchtower image neobsahuje klasický shell, takže príkazy typu:

docker exec watchtower-84 sh

nemusia fungovať.

Na kontrolu konfigurácie je preto vhodnejšie používať:

docker inspect

docker inspect

sudo docker ps --filter name=watchtower

Očakávaný stav:

watchtower-84    Up ...
watchtower-85    Up ...

Logy:

sudo docker logs watchtower-84 --tail 30
sudo docker logs watchtower-85 --tail 30

V mojom nasadení sa Watchtower úspešne pripájal cez mTLS k obom vzdialeným Docker hostom a čakal na naplánované spustenie:

watchtower-84 → každý deň 03:00
watchtower-85 → každý deň 03:30

Tým máme centrálny Watchtower nakonfigurovaný. Stále však nebude automaticky aktualizovať žiadny kontajner, pokiaľ mu to explicitne nepovolíme pomocou Docker labelu.

6. Výber kontajnerov pomocou Docker labelov

Watchtower je už pripojený k vzdialeným Docker hostom, ale v konfigurácii používam:

WATCHTOWER_LABEL_ENABLE: "true"

To znamená, že automatická aktualizácia nie je povolená globálne pre všetky kontajnery.

Každý kontajner, ktorý má Watchtower spravovať, musí mať explicitne nastavený label:

labels:
  - "com.centurylinklabs.watchtower.enable=true"

Kontajner bez tohto labelu Watchtower pri aktualizácii ignoruje.

Týmto spôsobom môžem na rovnakom Docker hoste prevádzkovať napríklad desať kontajnerov, ale automatické aktualizácie povoliť iba dvom alebo trom.

6.1 Prečo používam opt-in model

Pri automatických aktualizáciách preferujem princíp:

defaultne zakázané
explicitne povolené

Namiesto toho, aby Watchtower aktualizoval všetko a následne som vytváral výnimky, automatickú aktualizáciu povoľujem jednotlivo.

Výsledok môže vyzerať napríklad takto:

10.10.8.4

Element                AUTO
ChangeDetection        AUTO
Browserless Chrome     AUTO
Synapse                MANUAL
Mailcow                MANUAL
ostatné kontajnery     MANUAL

Na druhom serveri:

10.10.8.5

Grafana                AUTO
Zabbix                 MANUAL
MariaDB                MANUAL
PostgreSQL             MANUAL
Passbolt               MANUAL
NetBox                 MANUAL
FreePBX                MANUAL

Takýto model výrazne znižuje riziko, že sa kritická aplikácia alebo databáza aktualizuje bez predchádzajúcej kontroly.

6.2 Povolenie automatickej aktualizácie pre Element

Na Docker hoste:

10.10.8.4

mám aplikáciu Element.

Do príslušnej služby v docker-compose.yaml som pridal:

services:

  element:
    image: vectorim/element-web:latest

    labels:
      - "com.centurylinklabs.watchtower.enable=true"

Nie je potrebné meniť ostatnú konfiguráciu služby. Dôležité je iba doplnenie sekcie:

labels:
  - "com.centurylinklabs.watchtower.enable=true"

Po úprave Compose súboru je potrebné konfiguráciu aplikovať.

V mojom prípade:

cd /home/ivan/docker/chat
sudo docker compose config

Ak je konfigurácia v poriadku:

sudo docker compose up -d element

Keďže sa zmenila konfigurácia kontajnera, Docker ho môže znovu vytvoriť.

Následne som overil label:

sudo docker inspect element \
  --format '{{ index .Config.Labels "com.centurylinklabs.watchtower.enable" }}'

Správny výsledok:

true

Od tejto chvíle je Element zaradený medzi kontajnery, ktoré môže watchtower-84 automaticky aktualizovať.

Synapse bežiaci v rovnakom prostredí som naopak ponechal bez Watchtower labelu.

6.3 ChangeDetection

Rovnaký postup som použil pri ChangeDetection.

Do služby:

services:

  changedetection:
    image: dgtlmoon/changedetection.io

    labels:
      - "com.centurylinklabs.watchtower.enable=true"

Po úprave konfigurácie:

cd /home/ivan/docker/changedetection

sudo docker compose config
sudo docker compose up -d changedetection

Kontrola:

sudo docker inspect changedetection \
  --format '{{ index .Config.Labels "com.centurylinklabs.watchtower.enable" }}'

Výsledok:

true

Watchtower teda môže kontrolovať, či existuje novšia verzia image:

dgtlmoon/changedetection.io

a v prípade potreby kontajner aktualizovať.

6.4 Browserless Chrome

ChangeDetection v mojom prostredí používa aj Browserless Chrome.

Aj tento kontajner som povolil pre automatickú aktualizáciu:

services:

  browserless-chrome:
    image: browserless/chrome

    labels:
      - "com.centurylinklabs.watchtower.enable=true"

Po úprave:

sudo docker compose up -d browserless-chrome

Kontrola:

sudo docker inspect browserless-chrome \
  --format '{{ index .Config.Labels "com.centurylinklabs.watchtower.enable" }}'

Očakávaný výsledok:

true

Na Docker hoste 10.10.8.4 tak Watchtower aktuálne sleduje:

element
changedetection
browserless-chrome

6.5 Grafana na druhom Docker hoste

Na serveri:

10.10.8.5

som pre automatické aktualizácie vybral Grafanu.

Do Compose konfigurácie som pridal:

services:

  grafana:
    image: grafana/grafana:latest

    labels:
      - "com.centurylinklabs.watchtower.enable=true"

Následne:

cd ~/grafana

sudo docker-compose \
  -f docker-compose-grafana.yml \
  config

Na tomto serveri používam samostatný príkaz docker-compose, preto aj aplikovanie konfigurácie vyzerá:

sudo docker-compose \
  -f docker-compose-grafana.yml \
  up -d

Kontrola labelu:

sudo docker inspect grafana \
  --format '{{ index .Config.Labels "com.centurylinklabs.watchtower.enable" }}'

Výsledok:

true

Grafanu následne spravuje:

watchtower-85

na centrálnom serveri 10.10.8.6.

6.6 Kontrola všetkých Watchtower labelov na hoste

Namiesto kontroly každého kontajnera samostatne môžeme vypísať všetky bežiace kontajnery spolu s hodnotou Watchtower labelu:

sudo docker ps -q | xargs -r sudo docker inspect \
  --format '{{.Name}} -> {{index .Config.Labels "com.centurylinklabs.watchtower.enable"}}'

Na 10.10.8.4 môže výsledok vyzerať približne:

/element -> true
/changedetection -> true
/browserless-chrome -> true
/synapse -> <no value>
...

Kontajnery s:

true

sú povolené pre automatické aktualizácie.

Kontajnery bez hodnoty zostávajú mimo automatickej správy Watchtoweru.

Podobne na 10.10.8.5:

/grafana -> true
/zabbix-server -> <no value>
/mariadb -> <no value>
...

6.7 Label nie je jednorazové nastavenie kontajnera

Dôležité je pridávať label priamo do:

docker-compose.yml

alebo:

docker-compose.yaml

Nie iba manuálne do momentálne bežiaceho kontajnera.

Compose súbor predstavuje požadovanú konfiguráciu aplikácie. Ak by sme label pridali iba nejakým jednorazovým príkazom a kontajner neskôr znovu vytvorili z Compose konfigurácie, nastavenie by sa stratilo.

Preto má byť napríklad:

labels:
  - "com.centurylinklabs.watchtower.enable=true"

súčasťou trvalej definície služby.

6.8 Čo sa deje počas automatickej aktualizácie

Ak Watchtower pri naplánovanej kontrole zistí novší image pre kontajner označený správnym labelom, typický postup je:

1. skontroluje aktuálne používaný image
2. overí dostupnosť novšej verzie
3. stiahne nový image
4. zastaví pôvodný kontajner
5. vytvorí nový kontajner s rovnakou konfiguráciou
6. spustí nový kontajner
7. pri zapnutom cleanup odstráni starý image
8. odošle report

Dáta uložené vo volume alebo bind mounte týmto postupom zostávajú zachované.

Preto je pri výbere kontajnerov na automatickú aktualizáciu dôležité, aby aplikácia mala svoje persistentné dáta uložené mimo zapisovateľnej vrstvy samotného kontajnera.

6.9 Výsledný stav

Po pridaní labelov vyzerá moja konfigurácia nasledovne:

Tým máme definované, ktoré kontajnery sa smú aktualizovať automaticky a ktoré zostávajú pod manuálnou správou.

7. Testovanie Watchtoweru a overenie reálnej aktualizácie

Po pridaní labelov je vhodné nečakať na nočný harmonogram, ale celé riešenie otestovať manuálne.

Na tento účel môžeme použiť:

/watchtower --run-once

Watchtower vykoná jednu kontrolu, prípadne aktualizáciu, a následne skončí.

7.1 Manuálny test watchtower-84

Na centrálnom serveri:

10.10.8.6

som spustil:

sudo docker exec watchtower-84 /watchtower --run-once

Watchtower sa cez mTLS pripojí k:

10.10.8.4:2376

a skontroluje iba kontajnery označené:

com.centurylinklabs.watchtower.enable=true

V mojom prípade:

Element
ChangeDetection
Browserless Chrome

Ak existuje novší image, Watchtower ho stiahne a kontajner znovu vytvorí.

Pri teste s Elementom bola aktualizácia úspešná.

Log obsahoval informácie v štýle:

Found new image
Stopping /element
Creating /element
Removing image
Session done

a výsledok:

failed=0
scanned=1
updated=1

Po aktualizácii som skontroloval stav:

sudo docker ps --filter name=element

a následne aj samotnú aplikáciu cez webové rozhranie.

Element fungoval korektne aj po automatickej aktualizácii.

7.2 Manuálny test watchtower-85

Rovnaký test som vykonal aj pre druhú inštanciu:

sudo docker exec watchtower-85 /watchtower --run-once

Táto inštancia sa pripája k:

10.10.8.5:2376

a v mojom prípade sleduje Grafanu.

Počas testu Watchtower našiel novšiu verziu image:

grafana/grafana:latest

starý kontajner zastavil, vytvoril nový a odstránil pôvodný image.

Výsledok bol:

failed=0
scanned=1
updated=1

Po aktualizácii:

sudo docker ps --filter name=grafana

a následne som overil Grafanu cez webové rozhranie.

Aj v tomto prípade prebehla automatická aktualizácia úspešne.

7.3 Overenie aktuálne používaného image

Po aktualizácii je vhodné overiť, aký image kontajner skutočne používa.

Napríklad:

sudo docker inspect element \
  --format '{{.Image}}'

alebo:

sudo docker inspect grafana \
  --format '{{.Image}}'

ID image môžeme porovnať s image dostupným lokálne:

sudo docker image inspect grafana/grafana:latest \
  --format '{{.Id}}'

Ak sa hodnoty zhodujú, kontajner používa aktuálne stiahnutý image.

7.4 Test SMTP notifikácie bez aktualizácie kontajnera

E-mailové notifikácie je dobré otestovať samostatne bez toho, aby sme kvôli testu reálne aktualizovali aplikáciu.

Na to môžeme použiť:

--monitor-only

Pre Grafanu som použil:

sudo docker exec \
  -e WATCHTOWER_NOTIFICATION_TEMPLATE_FILE= \
  watchtower-85 \
  /watchtower \
  --run-once \
  --monitor-only \
  --notification-template 'Watchtower SMTP TEST - docker 10.10.8.5' \
  grafana

Parameter:

--monitor-only

znamená, že Watchtower môže skontrolovať dostupnosť image, ale kontajner nebude zastavovať ani znovu vytvárať.

V logu som dostal:

Shoutrrr: Mail successfully sent to "updater@ibasterisk.eu"!

a testovací e-mail následne dorazil do mailboxu.

Rovnaký test môžeme spraviť pre prvý Docker host:

sudo docker exec \
  -e WATCHTOWER_NOTIFICATION_TEMPLATE_FILE= \
  watchtower-84 \
  /watchtower \
  --run-once \
  --monitor-only \
  --notification-template 'Watchtower SMTP TEST - docker 10.10.8.4' \
  element

Takto vieme samostatne overiť:

SMTP spojenie
STARTTLS
SMTP autentifikáciu
App Password
doručenie správy
Watchtower notification backend

bez zásahu do produkčného kontajnera.

7.5 Overenie notifikačnej konfigurácie

Nastavené premenné môžeme overiť pomocou:

sudo docker inspect watchtower-84 \
  --format '{{range .Config.Env}}{{println .}}{{end}}' |
  grep -E '^WATCHTOWER_(NOTIFICATION_URL|NOTIFICATION_REPORT|NOTIFICATION_TEMPLATE_FILE|NO_STARTUP_MESSAGE|NOTIFICATIONS_HOSTNAME)='

Rovnako:

sudo docker inspect watchtower-85 \
  --format '{{range .Config.Env}}{{println .}}{{end}}' |
  grep -E '^WATCHTOWER_(NOTIFICATION_URL|NOTIFICATION_REPORT|NOTIFICATION_TEMPLATE_FILE|NO_STARTUP_MESSAGE|NOTIFICATIONS_HOSTNAME)='

Výstup by mal obsahovať napríklad:

WATCHTOWER_NOTIFICATION_URL=/notify/notification-url.txt
WATCHTOWER_NOTIFICATION_REPORT=true
WATCHTOWER_NOTIFICATION_TEMPLATE_FILE=/notify/update-template.txt
WATCHTOWER_NO_STARTUP_MESSAGE=true
WATCHTOWER_NOTIFICATIONS_HOSTNAME=docker-10.10.8.4

alebo pre druhú inštanciu:

WATCHTOWER_NOTIFICATIONS_HOSTNAME=docker-10.10.8.5

7.6 Test správy pri reálnej aktualizácii

Pri reálnej aktualizácii už používame štandardnú šablónu.

E-mail môže vyzerať napríklad:

Watchtower - docker-10.10.8.4

Scanned: 3
Updated: 1
Failed: 0

UPDATED: element
Image: vectorim/element-web:latest

Pri chybe:

Watchtower - docker-10.10.8.4

Scanned: 3
Updated: 0
Failed: 1

FAILED: changedetection
Image: dgtlmoon/changedetection.io
Error: ...

Takto viem bez prihlasovania na server okamžite zistiť:

ktorý Docker host vykonal kontrolu
koľko kontajnerov bolo skontrolovaných
ktoré kontajnery boli aktualizované
či aktualizácia skončila chybou

7.7 Pozor na prerušenie --run-once

Počas testovania som narazil aj na jednu praktickú situáciu.

Príkaz:

sudo docker exec watchtower-84 /watchtower --run-once

môže počas sťahovania väčšieho image určitý čas neprodukovovať žiadny nový výstup.

To neznamená, že proces stojí.

Najmä image ako:

browserless/chrome

môže byť väčší a jeho sťahovanie chvíľu trvá.

Preto nie je dobré test prerušiť pomocou:

Ctrl+C

a následne okamžite spustiť druhý --run-once.

Pri mojom teste som presne toto urobil a následný Watchtower proces narazil na:

removal of container ... is already in progress

Dôvodom nebola chyba aplikácie, ale to, že pôvodný Watchtower proces už začal kontajner aktualizovať a druhý proces sa pokúsil pracovať s rovnakým kontajnerom.

7.8 Ako overiť stav po prerušenej aktualizácii

Pred ďalším zásahom som najskôr skontroloval kontajnery:

sudo docker ps -a

Následne konkrétny kontajner:

sudo docker inspect changedetection \
  --format 'Status={{.State.Status}} Image={{.Image}}'

A aktuálny image:

sudo docker image inspect \
  dgtlmoon/changedetection.io:latest \
  --format '{{.Id}}'

Ak ID kontajnera zodpovedá aktuálnemu image a kontajner má stav:

running

aktualizácia mohla v skutočnosti prebehnúť úspešne aj napriek tomu, že druhý Watchtower proces nahlásil chybu.

V mojom prípade ChangeDetection už používal nový image a aplikácia normálne fungovala.

Preto pri podobnom stave neodporúčam kontajner okamžite mazať alebo znova vytvárať.

Najskôr treba overiť jeho reálny stav.

7.9 Kontrola aplikácie po aktualizácii

Úspešný Watchtower log ešte automaticky neznamená, že aplikácia funguje správne.

Po každom prvom automatickom update konkrétnej služby preto odporúčam skontrolovať:

stav kontajnera
aplikačné logy
webové rozhranie
persistentné dáta
závislosti na ostatných službách

Kontrola logov napríklad:

sudo docker logs element --tail 50

alebo:

sudo docker logs grafana --tail 50

Prípadne:

sudo docker logs changedetection --tail 50

Aplikáciu následne overím rovnakým spôsobom ako používateľ.

Až keď toto prebehne bez problémov, nechávam kontajner zaradený do automatických aktualizácií.

7.10 Výsledok testovania

Po dokončení testov mám overené všetky hlavné časti riešenia:

mTLS komunikácia                         OK
Docker API                               OK
Watchtower remote connection             OK
label-only režim                         OK
automatická aktualizácia                 OK
cleanup starých image                    OK
SMTP cez STARTTLS                        OK
App Password                             OK
e-mail pri aktualizácii                  OK
e-mail pri chybe                         OK
bez e-mailu pri bežnej kontrole          OK

Tým je základné nasadenie hotové.

Watchtower teraz každý deň automaticky vykoná:

03:00 → kontrola 10.10.8.4
03:30 → kontrola 10.10.8.5

8. Troubleshooting a najčastejšie problémy

Pri nasadzovaní riešenia sa môže problém objaviť na viacerých miestach — od Docker daemonu, cez TLS certifikáty až po samotný Watchtower alebo SMTP notifikácie.

V tejto kapitole sú najčastejšie problémy, na ktoré som pri nasadení narazil, spolu s postupom kontroly.

8.1 Docker API na porte 2376 nepočúva

Ako prvé je vhodné overiť, či Docker daemon vôbec počúva na zabezpečenom TCP porte:

sudo ss -lntp | grep 2376

Správny výsledok by mal obsahovať napríklad:

LISTEN ... 10.10.8.4:2376 ... dockerd

alebo:

LISTEN ... 10.10.8.5:2376 ... dockerd

Ak sa nič nezobrazí, skontrolujem stav Docker služby:

sudo systemctl status docker --no-pager

a následne výsledný ExecStart:

sudo systemctl show docker -p ExecStart --no-pager

Mal by obsahovať:

-H fd://
-H tcp://10.10.8.x:2376
--tlsverify

Ak som menil systemd override, nezabudnem na:

sudo systemctl daemon-reload
sudo systemctl restart docker

Log Docker daemonu môžem skontrolovať:

sudo journalctl -u docker -n 100 --no-pager

8.2 Docker po zmene konfigurácie nenabehne

Ak sa Docker po zmene daemon.json alebo systemd override nespustí, prvým krokom je overenie syntaxe:

sudo dockerd --validate \
  --config-file=/etc/docker/daemon.json

Správny výsledok:

configuration OK

Následne:

sudo systemctl status docker --no-pager

a:

sudo journalctl -u docker -n 100 --no-pager

Častým problémom môže byť napríklad konflikt medzi:

/etc/docker/daemon.json

a parametrami použitými priamo v:

ExecStart=

V mojom prípade som preto parameter hosts nepridával do daemon.json, ale TCP listener som definoval cez systemd override.

8.3 tlsv13 alert certificate required

Ak pri teste:

curl \
  --cacert docker-ca.pem \
  https://10.10.8.4:2376/_ping

dostanem:

tlsv13 alert certificate required

nie je to chyba.

Práve naopak — znamená to, že Docker daemon vyžaduje klientsky certifikát.

Správny test musí obsahovať:

curl \
  --cacert docker-ca.pem \
  --cert watchtower-cert.pem \
  --key watchtower-key.pem \
  https://10.10.8.4:2376/_ping

Výsledok:

ok

Tým máme potvrdené, že mTLS funguje.

8.4 Chyba certifikátu alebo nesprávny SAN

Ak Watchtower alebo curl odmietne serverový certifikát, skontrolujem jeho Subject Alternative Name:

openssl x509 \
  -in docker-10.10.8.4-cert.pem \
  -noout -text |
  grep -A2 "Subject Alternative Name"

Pre prvý host očakávam napríklad:

IP Address:10.10.8.4
DNS:mail-ibasterisk

Pre druhý:

IP Address:10.10.8.5
DNS:mon.ibasterisk.local

Ak sa Watchtower pripája cez IP adresu:

10.10.8.4

musí byť táto IP uvedená v SAN.

Nestačí mať iba:

CN=10.10.8.4

8.5 Overenie, že certifikát patrí k privátnemu kľúču

Pri pochybnostiach môžem porovnať verejný kľúč certifikátu:

sudo openssl x509 \
  -in /etc/docker/tls/server-cert.pem \
  -pubkey -noout |
  sha256sum

s verejným kľúčom odvodeným z privátneho kľúča:

sudo openssl pkey \
  -in /etc/docker/tls/server-key.pem \
  -pubout |
  sha256sum

Obidve hodnoty musia byť rovnaké.

8.6 Watchtower sa nevie pripojiť k vzdialenému Docker hostu

Najskôr otestujem Docker API priamo z centrálneho servera:

curl \
  --cacert /etc/watchtower-pki/docker-ca.pem \
  --cert /etc/watchtower-pki/watchtower-cert.pem \
  --key /etc/watchtower-pki/watchtower-key.pem \
  https://10.10.8.4:2376/_ping

Ak dostanem:

ok

sieťová a TLS vrstva funguje.

Potom skontrolujem Watchtower:

sudo docker logs watchtower-84 --tail 100

a environment:

sudo docker inspect watchtower-84 \
  --format '{{range .Config.Env}}{{println .}}{{end}}' |
  grep -E '^DOCKER_'

Očakávam:

DOCKER_HOST=tcp://10.10.8.4:2376
DOCKER_TLS_VERIFY=1
DOCKER_CERT_PATH=/certs

8.7 Kontrola certifikátov namountovaných do Watchtoweru

Bind mounty môžem skontrolovať pomocou:

sudo docker inspect watchtower-84 \
  --format '{{range .Mounts}}{{println .Source "->" .Destination}}{{end}}'

Očakávam napríklad:

/etc/watchtower-pki/docker-ca.pem -> /certs/ca.pem
/etc/watchtower-pki/watchtower-cert.pem -> /certs/cert.pem
/etc/watchtower-pki/watchtower-key.pem -> /certs/key.pem

Rovnako by mali byť pripojené aj notifikačné súbory:

/etc/watchtower-notify/notification-url.txt -> /notify/notification-url.txt
/etc/watchtower-notify/update-template.txt -> /notify/update-template.txt

8.8 docker exec watchtower-84 sh nefunguje

Pri debugovaní som skúsil:

sudo docker exec watchtower-84 sh

ale Watchtower image neobsahuje klasický shell.

Preto sa konfigurácia nekontroluje vstupom do kontajnera, ale pomocou:

docker inspect
sudo docker inspect watchtower-84

alebo cielene:

sudo docker inspect watchtower-84 \
  --format '{{range .Mounts}}{{println .Source "->" .Destination}}{{end}}'

8.9 Watchtower kontajner neaktualizuje

Ak sa kontajner neaktualizuje, najskôr skontrolujem jeho label:

sudo docker inspect element \
  --format '{{ index .Config.Labels "com.centurylinklabs.watchtower.enable" }}'

Správny výsledok:

true

Ak sa nezobrazí nič, Watchtower ho pri zapnutom:

WATCHTOWER_LABEL_ENABLE: "true"

ignoruje.

Label musí byť pridaný priamo do Compose konfigurácie:

labels:
  - "com.centurylinklabs.watchtower.enable=true"

a následne treba kontajner znovu vytvoriť:

sudo docker compose up -d

8.10 Watchtower hlási Current container not cached for cleanup

Pri vzdialenom Docker daemon-e sa v logu môže objaviť upozornenie podobné:

Current container not cached for cleanup

V tomto nasadení je to očakávané.

Watchtower samotný beží na:

10.10.8.6

ale Docker daemon, ktorý spravuje, je napríklad:

10.10.8.4

Watchtower teda na vzdialenom Docker hoste nenájde svoj vlastný kontajner.

Táto hláška neznamená, že:

WATCHTOWER_CLEANUP: "true"

nefunguje.

Staré image aktualizovaných aplikácií môže Watchtower na vzdialenom Docker hoste naďalej odstrániť.

8.11 removal of container ... is already in progress

Pri manuálnom testovaní som narazil na chybu:

removal oStalo sa to po tom, čo som počas:f container ... is already in progress

Stalo sa to po tom, čo som počas:

sudo docker exec watchtower-84 /watchtower --run-once

proces prerušil cez:

Ctrl+C

a následne okamžite spustil nový --run-once.

Pôvodný proces už medzitým začal aktualizáciu a druhý proces sa pokúsil pracovať s rovnakým kontajnerom.

Preto je dôležité:

neprerušovať --run-once iba preto, že chvíľu nevypisuje nový text.

Sťahovanie väčších image môže trvať niekoľko minút.

Pred ďalším zásahom skontrolujem:

sudo docker ps -a

potom konkrétny kontajner:

sudo docker inspect changedetection \
  --format 'Status={{.State.Status}} Image={{.Image}}'

a aktuálny image:

sudo docker image inspect \
  dgtlmoon/changedetection.io:latest \
  --format '{{.Id}}'

Ak kontajner:

Status=running

a používa aktuálny image, aktualizácia už pravdepodobne prebehla.

8.12 Watchtower chvíľu nič nevypisuje

To nemusí znamenať, že zamrzol.

Pri väčšom image, napríklad:

browserless/chrome

môže sťahovanie trvať dlhšie.

V inom termináli môžem sledovať napríklad:

sudo docker ps

alebo stav image na vzdialenom Docker hoste:

sudo docker images

Najbezpečnejšie je nechať --run-once dokončiť.

8.13 E-mailová notifikácia nepríde

Najskôr overím SMTP server ešte mimo Watchtoweru:

openssl s_client \
  -starttls smtp \
  -connect mail.ibasterisk.eu:587 \
  -servername mail.ibasterisk.eu \
  -verify_return_error

TLS spojenie musí prebehnúť úspešne.

Následne skontrolujem existenciu secretu:

sudo ls -l \
  /etc/watchtower-notify/notification-url.txt

Práva by mali byť:

-rw------- root root

Obsah súboru nepublikujem ani nevypisujem, pretože obsahuje SMTP App Password.

Skontrolujem mount:

sudo docker inspect watchtower-84 \
  --format '{{range .Mounts}}{{println .Source "->" .Destination}}{{end}}'

a environment:

sudo docker inspect watchtower-84 \
  --format '{{range .Config.Env}}{{println .}}{{end}}' |
  grep '^WATCHTOWER_NOTIFICATION'

8.14 Bezpečný SMTP test

SMTP môžem otestovať bez reálnej aktualizácie kontajnera:

sudo docker exec \
  -e WATCHTOWER_NOTIFICATION_TEMPLATE_FILE= \
  watchtower-84 \
  /watchtower \
  --run-once \
  --monitor-only \
  --notification-template 'Watchtower SMTP TEST - docker 10.10.8.4' \
  element

Pri úspechu sa v logu objaví napríklad:

Shoutrrr: Mail successfully sent to "updater@ibasterisk.eu"!

Pre druhý host:

sudo docker exec \
  -e WATCHTOWER_NOTIFICATION_TEMPLATE_FILE= \
  watchtower-85 \
  /watchtower \
  --run-once \
  --monitor-only \
  --notification-template 'Watchtower SMTP TEST - docker 10.10.8.5' \
  grafana

Parameter:

--monitor-only

zabezpečí, že počas testu nedôjde k aktualizácii kontajnera.

8.15 Po aktualizácii aplikácia nefunguje

Watchtower môže technicky vykonať aktualizáciu úspešne, ale samotná aplikácia môže mať problém s novou verziou.

Preto kontrolujem:

sudo docker ps

a log aplikácie:

sudo docker logs <container> --tail 100

Napríklad:

sudo docker logs element --tail 100

alebo:

sudo docker logs grafana --tail 100

Dôležité je tiež overiť samotnú aplikáciu cez webové rozhranie.

Práve preto automaticky neaktualizujem kritické služby a databázy, pri ktorých môže nová verzia vyžadovať migráciu.

8.16 Kontajner používa nový image?

Aktuálny image použitý kontajnerom:

sudo docker inspect changedetection \
  --format '{{.Image}}'

ID image dostupného pod tagom:

sudo docker image inspect \
  dgtlmoon/changedetection.io:latest \
  --format '{{.Id}}'

Ak sú hodnoty rovnaké, kontajner používa aktuálne stiahnutý image.

8.17 Rýchla diagnostika

Ak niečo nefunguje, praktický postup je kontrolovať riešenie postupne od najnižšej vrstvy:

Takýto postup je lepší ako náhodne meniť viacero častí konfigurácie naraz.

Výsledok

Po vyriešení týchto bodov máme pomerne jednoducho diagnostikovateľné riešenie.

Najdôležitejšie je oddeliť jednotlivé vrstvy:

Ak každú vrstvu otestujeme samostatne, väčšina problémov sa dá lokalizovať pomerne rýchlo.

9. Záver

Cieľom celého riešenia bolo vytvoriť centrálne a zároveň bezpečne riadené automatické aktualizácie Docker kontajnerov bez toho, aby som musel nasadzovať Watchtower na každý Docker host samostatne.

Výsledná architektúra používa centrálny server 10.10.8.6, na ktorom bežia dve nezávislé Watchtower inštancie. Tie sa cez mTLS pripájajú k vzdialeným Docker daemon-om na 10.10.8.4 a 10.10.8.5.

Automatické aktualizácie sú povolené iba pre explicitne označené kontajnery pomocou labelu:

labels:
  - "com.centurylinklabs.watchtower.enable=true"

Vďaka tomu zostávajú kritické služby, databázy a infraštruktúrne komponenty mimo automatického update procesu a môžu byť aktualizované riadeným spôsobom po kontrole release notes a vytvorení zálohy.

Komunikácia s Docker API je zabezpečená pomocou vlastnej certifikačnej autority a obojstranne overovaného TLS spojenia. Docker daemon teda neprijme klienta bez platného certifikátu, čo výrazne znižuje riziko zneužitia vzdialeného API.

Súčasťou riešenia sú aj SMTP notifikácie. Watchtower neposiela e-mail pri každej kontrole, ale iba v prípade úspešnej aktualizácie alebo chyby. Výsledkom je menej zbytočných správ a zároveň okamžitá informácia v prípade, že sa na niektorom Docker hoste niečo zmení.

Výsledný proces je teda:

Takto mám aktualizácie vybraných Docker služieb automatizované, ale zároveň zostáva zachovaná kontrola nad tým, čo sa môže aktualizovať automaticky a čo musí zostať manuálne spravované.

Celé riešenie kombinuje:

Docker
Watchtower
mTLS
vlastnú Docker CA
label-only aktualizácie
cleanup starých image
SMTP cez STARTTLS
App Password
e-mailové reporty

Výsledkom je jednoduchý, centrálne spravovaný a relatívne bezpečný spôsob automatizácie aktualizácií Docker kontajnerov vo vlastnej infraštruktúre.

naspäť