推薦一款自動更新Docker鏡像與容器的神器Watchtower
前言
Docker 容器的部署有一種在手機上裝 App 的感覺,但 Docker 容器并不會像手機 App 那樣會自動更新,而如果我們需要更新容器一般需要以下四個步驟:
- 停止容器:docker stop <CONTAINER>
- 刪除容器:docker rm <CONTAINER>
- 更新鏡像:docker pull <IMAGE>
- 啟動容器:docker run <ARG> ... <IMAGE>
停止容器這個步驟可以在刪除容器時使用 -f 參數來代替,即使這樣還是需要三個步驟。如果部署了大量的容器需要更新使用這種傳統的方式工作量是巨大的。
Watchtower 是一個可以實現自動化更新 Docker 基礎鏡像與容器的實用工具。它監視正在運行的容器以及相關的鏡像,當檢測到 registry 中的鏡像與本地的鏡像有差異時,它會拉取最新鏡像并使用最初部署時相同的參數重新啟動相應的容器,一切好像什么都沒發生過,就像更新手機上的 App 一樣。
快速開始
Watchtower 本身被打包為 Docker 鏡像,因此可以像運行任何其他容器一樣運行它:
- docker run -d \
- --name watchtower \
- -v /var/run/docker.sock:/var/run/docker.sock \
- containrrr/watchtower
然后所有容器都會自動更新,也包括 Watchtower 本身。
選項參數
- $ docker run --rm containrrr/watchtower -h
- Watchtower automatically updates running Docker containers whenever a new image is released.
- More information available at https://github.com/containrrr/watchtower/.
- Usage:
- watchtower [flags]
- Flags:
- -a, --api-version string api version to use by docker client (default "1.24")
- -c, --cleanup remove previously used images after updating
- -d, --debug enable debug mode with verbose logging
- --enable-lifecycle-hooks Enable the execution of commands triggered by pre- and post-update lifecycle hooks
- -h, --help help for watchtower
- -H, --host string daemon socket to connect to (default "unix:///var/run/docker.sock")
- -S, --include-stopped Will also include created and exited containers
- -i, --interval int poll interval (in seconds) (default 300)
- -e, --label-enable watch containers where the com.centurylinklabs.watchtower.enable label is true
- -m, --monitor-only Will only monitor for new images, not update the containers
- --no-pull do not pull any new images
- --no-restart do not restart any containers
- --notification-email-delay int Delay before sending notifications, expressed in seconds
- --notification-email-from string Address to send notification emails from
- --notification-email-server string SMTP server to send notification emails through
- --notification-email-server-password string SMTP server password for sending notifications
- --notification-email-server-port int SMTP server port to send notification emails through (default 25)
- --notification-email-server-tls-skip-verify
- Controls whether watchtower verifies the SMTP server's certificate chain and host name.
- Should only be used for testing.
- --notification-email-server-user string SMTP server user for sending notifications
- --notification-email-subjecttag string Subject prefix tag for notifications via mail
- --notification-email-to string Address to send notification emails to
- --notification-gotify-token string The Gotify Application required to query the Gotify API
- --notification-gotify-url string The Gotify URL to send notifications to
- --notification-msteams-data The MSTeams notifier will try to extract log entry fields as MSTeams message facts
- --notification-msteams-hook string The MSTeams WebHook URL to send notifications to
- --notification-slack-channel string A string which overrides the webhook's default channel. Example: #my-custom-channel
- --notification-slack-hook-url string The Slack Hook URL to send notifications to
- --notification-slack-icon-emoji string An emoji code string to use in place of the default icon
- --notification-slack-icon-url string An icon image URL string to use in place of the default icon
- --notification-slack-identifier string A string which will be used to identify the messages coming from this watchtower instance (default "watchtower")
- -n, --notifications strings notification types to send (valid: email, slack, msteams, gotify)
- --notifications-level string The log level used for sending notifications. Possible values: panic, fatal, error, warn, info or debug (default "info")
- --remove-volumes remove attached volumes before updating
- --revive-stopped Will also start stopped containers that were updated, if include-stopped is active
- -R, --run-once Run once now and exit
- -s, --schedule string the cron expression which defines when to update
- -t, --stop-timeout duration timeout before a container is forcefully stopped (default 10s)
- -v, --tlsverify use TLS and verify the remote
自動清除舊鏡像
官方給出的默認啟動命令在長期使用后會堆積非常多的標簽為 none 的舊鏡像,如果放任不管會占用大量的磁盤空間。要避免這種情況可以加入 --cleanup 選項,這樣每次更新都會把舊的鏡像清理掉。
- docker run -d \
- --name watchtower \
- --restart unless-stopped \
- -v /var/run/docker.sock:/var/run/docker.sock \
- containrrr/watchtower \
- --cleanup
--cleanup 選項可以簡寫為 -c:
- docker run -d \
- --name watchtower \
- --restart unless-stopped \
- -v /var/run/docker.sock:/var/run/docker.sock \
- containrrr/watchtower -c
選擇性自動更新
某些容器可能需要穩定的運行,經常更新或重啟可能會造成一些問題,這時我們可以使用一些選項參數來選擇與控制容器的更新。
- 容器更新列表
假設我們只想更新 nginx、redis 這兩個容器,我們可以把容器名稱追加到啟動命令的最后面,就像下面這個例子:
- docker run -d \
- --name watchtower \
- --restart unless-stopped \
- -v /var/run/docker.sock:/var/run/docker.sock \
- containrrr/watchtower -c \
- nginx redis
博主覺得把需要更新的容器名稱寫在啟動命令中不利于管理,于是想了個更好的方法,建立一個更新列表文件。
- $ cat ~/.watchtower.list
- aria2-pro
- unlockmusic
- mtg
- ...
通過變量的方式去調用這個列表:
- docker run -d \
- --name watchtower \
- --restart unless-stopped \
- -v /var/run/docker.sock:/var/run/docker.sock \
- containrrr/watchtower -c \
- $(cat ~/.watchtower.list)
這樣只需要調整列表后刪除 Watchtower 容器并重新執行上面的命令重新啟動 Watchtower 即可。
2. 設置單個容器自動更新特征
給容器添加 com.centurylinklabs.watchtower.enable 這個 LABEL 并設置它的值為 false,或者在啟動命令中加入 --label com.centurylinklabs.watchtower.enable=false 參數可以排除相應的容器。下面這個例子是博主的 openwrt-mini 鏡像的容器啟動命令,Watchtower 將永遠忽略它的更新,即使它包含在自動更新列表中。
- docker run -d \
- --name openwrt-mini \
- --restart always \
- --network openwrt \
- --privileged \
- --label com.centurylinklabs.watchtower.enable=false \
- p3terx/openwrt-mini \
- /sbin/init
當容器啟動命令中加入 --label com.centurylinklabs.watchtower.enable=true 參數,并且給 Watchtower 加上 --label-enable 選項時,Watchtower 將只更新這些包含此參數的容器。
- docker run -d \
- --name watchtower \
- --restart unless-stopped \
- -v /var/run/docker.sock:/var/run/docker.sock \
- containrrr/watchtower -c \
- --label-enable
--label-enable 可以簡寫為 -e:
- docker run -d \
- --name watchtower \
- --restart unless-stopped \
- -v /var/run/docker.sock:/var/run/docker.sock \
- containrrr/watchtower -ce
因為需要在容器啟動時進行設置,且設置后就無法直接更改,只能重建容器,所以這種方式的靈活性不如更新列表法。尤其是在設置 com.centurylinklabs.watchtower.enable=false 參數后容器將永遠被 Watchtower 忽略,也包括后面將要提到的手動更新方式,所以一般不推薦這樣做,除非你愿意手動重建的原生方式更新。
設置自動更新檢查頻率
默認情況下 Watchtower 每 5 分鐘會輪詢一次,如果你覺得這個頻率太高了可以使用如下選項來控制更新檢查的頻率,但二者只能選擇其一。
--interval, -i - 設置更新檢測時間間隔,單位為秒。比如每隔 1 個小時檢查一次更新:
- docker run -d \
- --name watchtower \
- --restart unless-stopped \
- -v /var/run/docker.sock:/var/run/docker.sock \
- containrrr/watchtower -c \
- --interval 3600
--schedule, -s - 設置定時檢測更新時間。格式為 6 字段 Cron 表達式,而非傳統的 5 字段,即第一位是秒。比如每天凌晨 2 點檢查一次更新:
- docker run -d \
- --name watchtower \
- --restart unless-stopped \
- -v /var/run/docker.sock:/var/run/docker.sock \
- containrrr/watchtower -c \
- --schedule "0 0 2 * * *"
手動更新
前面的使用方式都是讓 Watchtower 以 detached(后臺)模式在運行并自動更新容器,而 Watchtower 也支持以 foreground(前臺)模式來使用,即運行一次退出并刪掉容器,來實現手動更新容器。這對于偶爾更新一次那些不在自動更新列表中的容器非常有用。
對于 foreground 模式,需要加上 --run-once 這個專用的選項。下面的例子 Docker 會運行一次 Watchtower 并檢查 aria2-pro 容器的基礎鏡像更新,最后刪掉本次運行創建的 Watchtower 容器。
- docker run --rm \
- -v /var/run/docker.sock:/var/run/docker.sock \
- containrrr/watchtower -c \
- --run-once \
- aria2-pro
--run-once 可以簡寫為 -R:
- docker run --rm \
- -v /var/run/docker.sock:/var/run/docker.sock \
- containrrr/watchtower -cR \
- aria2-pro
需要注意的是當這個容器設置過 com.centurylinklabs.watchtower.enable=false 參數時不會更新。
尾巴
以上是博主在使用 Watchtower 中總結的一些使用方式和方法,當然它還有一些其它的功能與使用方式,比如電子郵件通知、監視私人注冊表的鏡像、更新遠程主機上的容器等,這些對于一般用戶來說可能很少會用到,所以這里就不贅述了,感興趣的小伙伴可以去研究 Watchtower 官方文檔。