🗼

Watchtowerでコンテナの自動デプロイ

に公開

はじめに

本記事では、GitHub Container Registry(GHCR)などに登録済みのコンテナイメージを、Watchtowerを用いて自動デプロイ(自動更新)する方法を紹介します。

https://github.com/containrrr/watchtower

対象読者

  • 少数のコンテナをシンプルに運用したい
  • Kubernetesの学習コストが見合わず、まずは軽量に自動更新を導入したい

前提

  • ホストはLinux Ubuntu
  • GHCRに登録したイメージを自動更新対象とする
  • Docker/Docker Composeを利用する

自動デプロイの仕組み

Watchtowerは、起動中のDockerコンテナが参照するレジストリ(今回の例ではGHCR)のイメージ更新を定期的に監視し、更新が検出されると対象コンテナを再作成して最新イメージへ置き換えます。

基本動作は以下の通りです。

  1. 対象コンテナの現在のイメージのダイジェスト(またはタグ)を確認する
  2. レジストリの最新イメージと差分があればイメージをプルする
  3. 対象コンテナを停止 → 再作成 → 再起動する

特定のコンテナのみを監視対象とすることで、意図しない更新を避けることもできます。


セットアップ方法

GHCRに対しての認証

WatchtowerがGHCRのイメージをプルするための認証情報を作成します。
GHCRへのdocker loginを行います。パスワードはGitHub上でPersonal Access Token(PAT)を作成してください。

export CR_PAT=<作成したPAT>
echo $CR_PAT | docker login ghcr.io -u <GitHubのユーザ名> --password-stdin

ログインすると、Dockerの認証情報(~/.docker/config.json)が作成されます。Watchtowerコンテナからもこの認証情報が参照できるよう、ホストのDocker設定ディレクトリをマウントします。

docker-compose.ymlの定義

Watchtowerがラベル有効なサービスのみを監視し、GHCRの認証情報を用いてイメージを更新する例です。
社内環境などでプロキシがいる場合は、Watchtowerがプライベートコンテナレジストリへアクセスできるように、証明書やプロキシ設定が必要な場合があります。

version: "3.8"

services:
  app:
    image: ghcr.io/owner/app:latest
    container_name: app
    restart: unless-stopped
    labels:
        - com.centurylinklabs.watchtower.enable=true
    ports:
      - "8080:8080"
    networks:
      - app-net

  watchtower:
    image: containrrr/watchtower:1.7.1
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      # Dockerの認証情報
      - ~/.docker/config.json:/config.json:ro
      # GHCRの証明書
      - ./certs/ghcr.pem:/etc/ssl/certs/ghcr.pem:ro
    environment:
      # プロキシ設定(Linuxの環境変数を利用)
      - http_proxy=${HTTP_PROXY:-}
      - https_proxy=${HTTPS_PROXY:-}
      # スケジュール設定(cron式)
      - WATCHTOWER_SCHEDULE=<任意に指定>
      # ローリングアップデート
      - WATCHTOWER_ROLLING_RESTART=true
      # 古いイメージを自動的に削除
      - WATCHTOWER_CLEANUP=true
    labels:
        - com.centurylinklabs.watchtower.enable=false
    command:
        # 監視対象を指定可能にするオプション
        - --label-enable
    networks:
      - app-net
    restart: unless-stopped

networks:
  app-net:
    driver: bridge

ポイント:

  • Watchtowerの監視対象を指定する場合、監視対象のコンテナのlabelscom.centurylinklabs.watchtower.enabletrueとする。
  • 動作テストを行う場合は、environmentに以下を指定する。
    watchtower:
    # ...
    environment:
        # ログレベルの設定
        - WATCHTOWER_TRACE=true

動作確認

通常のdocker composeで起動します。

# コンテナを起動
cd <docker-compose.ymlのあるディレクトリ>
docker compose up -d

# ログ確認
docker logs -f watchtower --follow

一般的なログの流れ

  • 更新対象のイメージをチェック

  • イメージの更新があった場合、イメージをpull → コンテナ停止 → 再作成 → 再起動を行う
    これを1つのコンテナずつ順番に実施。イメージ更新に失敗した場合でも次のコンテナのチェックに移る。

  • 更新なし → 次回チェックまで待機 を繰り返す

  • プライベートコンテナレジストリへのアクセスや監視対象のコンテナにアクセスできない場合は、WARNINGERRORになります。
    コンテナの中に入ってcurl -v <URL>を実行するなどして切り分けが必要です。


運用フロー(どういう自動デプロイをするかの実態)

典型的なフロー:

  1. GHCRへのイメージ更新(GitHub Actions/手動登録など)
  2. Watchtowerが定期チェックで新イメージを検知
  3. 既存コンテナを最新イメージで再作成し、コンテナを起動
  4. コンテナ更新後に旧イメージは削除(WATCHTOWER_CLEANUPの設定次第)

コンテナ更新のチェックロジック

  • docker-composeで指定しているコンテナのバージョンで差分が無いかをWatchtowerがチェックします。そのため、特定のバージョンで固定しつつ、GHCRのコンテナを更新する必要があります。
    今回の例ではlatestですが、これは再現性が確かでは無いことを把握した上で利用してください。

ロールバック:

  • 直前の安定版タグへイメージを戻す
  • composeファイルで特定タグを指定し、再起動(docker compose up <コンテナ名> -d

注意点

Kubernetesと比較してWatchtowerではできないこと

Watchtowerの機能は限定的です。例えば、以下です。

  • コンテナ更新後にコンテナを起動できなかった場合、自動でロールバックする。
    この場合、手動でのロールバックが必要になります。
  • 自動でスケーリングする。

本番環境では非推奨(公式ドキュメントより)

  • Watchtowerは本番向けのオーケストレーションを目的としたツールではないです。
    本番環境では利用するのであれば、Kubernetesの利用を推奨と記載されていることに注意が必要です。

Discussion