こんにちは、てつです!
Dockerコンテナの自動更新ツール「Watchtower」、前回の記事でDiscordやSlackへの通知設定まで完了しましたね。
これで「裏側で何が起きているか」がいつでも見えるようになり、自動運用の基盤がガッチリ固まりました。
まだ導入や通知設定が終わっていない方は、先に以下の記事をチェックしてみてくださいね。
- 関連記事:【10分で自動化】Watchtowerで行うDockerコンテナの自動アップデート導入ガイド
- 関連記事:【10分で可視化】Dockerコンテナ自動更新ツール「Watchtower」の通知設定をDiscordとSlackで徹底解説
さて、通知ができるようになって一安心…と、このままWatchtowerを放置していると、近いうちに「ある恐怖の瞬間」を迎えることになります。
それは、「データベースの勝手なアップデート」です。
WordPressの裏側で動いているMySQLや、Webアプリのデータを握っているPostgreSQLなどが、ある日突然、あなたの知らない間に自動更新されてしまう。
その結果、データの互換性が失われてサイトが真っ白になったり、最悪の場合は大切なデータが破損して起動しなくなったりするリスクがあります。
さらに、アクセスが集中する真っ昼間に突然アップデートが走り、サーバーが一時停止してしまうのも避けたいですよね。
自動化は素晴らしい仕組みですが、「すべてを闇雲にアップデートすればいい」というわけではありません。
今回は、Watchtowerをさらに安全に、そしてスマートに制御するための「特定のコンテナの更新除外」と「深夜のスケジュール管理」を徹底解説します。
これは、実際の開発現場やプロのインフラエンジニアが24時間365日のシステム運用で必ず導入している、最高峰のベストプラクティスです。
この記事を読めば、コピペではない「現場で通用する安全な自動化スキル」が10分で身につきます。大切なデータを守りつつ、アクセスが最も少ない深夜に賢くアップデートを走らせる、プロ仕様の環境を構築していきましょう!
1. Docker Watchtowerのスケジュール管理・更新除外に必要な前提環境
本題に入る前に、今回の作業を行うための環境を確認しておきましょう。
Docker環境とWatchtowerが導入済みであることの確認
- OS: Linuxサーバー(Ubuntuなど)、AWS(EC2など)、またはローカルのDocker環境(macOS / Windows)
- Docker / Docker Compose: インストール済みであること
- ベースとなる環境: 第1回・第2回で構築した、
docker-compose.ymlにWatchtowerが記載され、通知設定が完了している状態の環境を使用します。
初学者が知っておくべき「コンテナ」と「イメージ」の基本概念
- コンテナとイメージの違い:
Dockerにおける「イメージ」は、アプリを動かすための全ての材料が詰まった「冷凍パックの料理」のようなものです。そして「コンテナ」は、それを解凍して実際に食べられる状態にした「実体」です。Watchtowerは、新しい冷凍パック(イメージ)が公開されたら、自動で古いコンテナを捨てて新しく解凍し直してくれるツールです。 - テキストエディタの基本操作:
docker-compose.ymlを編集するため、サーバー上のnanoやvim、または使い慣れたVS Codeなどの操作ができる状態で進めてください。
2. 【全手順】Docker Watchtowerで特定のコンテナを自動アップデートから更新除外・スケジュール管理する4ステップ
それでは、具体的な設定に入っていきます。
今回は、最も実務でよくある構成として、「Webサーバー(Nginx)は自動アップデートしたいけれど、データベース(MySQL)は絶対に自動更新させず、さらに実行時間を深夜4時に固定する」というプロ仕様の設定を組んでいきます。
全体の完成形となる docker-compose.yml のコードを先に提示します。後から1ステップずつ細かく解説するので、まずは全体像を眺めてみてください。
version: '3.8'
services:
# 1. 守りたいデータベース(自動更新から除外)
db:
image: mysql:8.0
container_name: database_app
environment:
MYSQL_ROOT_PASSWORD: secret_password
volumes:
- db_data:/var/lib/mysql
# 【最重要】Watchtowerに「このコンテナは無視して!」と伝えるラベル
labels:
- "com.centurylinklabs.watchtower.enable=false"
# 2. 自動更新させたいWebサーバー
web:
image: nginx:latest
container_name: web_server
ports:
- "80:80"
# 3. 全体を管理するWatchtower
watchtower:
image: containrrr/watchtower:latest
container_name: watchtower
volumes:
- /var/run/docker.sock:/var/run/docker.sock
environment:
# 前回の通知設定(例としてSlackを指定)
- WATCHTOWER_NOTIFICATIONS=slack
- WATCHTOWER_NOTIFICATION_SLACK_WEBHOOK_URL=[https://hooks.slack.com/services/XXXXX](https://hooks.slack.com/services/XXXXX)
# 【新規追加】ラベルがついているコンテナの指示を厳守するモード
- WATCHTOWER_LABEL_ENABLE=true
# 【新規追加】実行時間を日本時間の深夜4時に固定する
- WATCHTOWER_SCHEDULE=0 0 4 * * *
- TZ=Asia/Tokyo
restart: always
volumes:
db_data:
では、なぜこの記述が必要なのか、1ステップずつロジックを解き明かしていきましょう!
ステップ1:Watchtowerに「ラベル感知モード(WATCHTOWER_LABEL_ENABLE)」を有効化する
まず、Watchtowerの設定(watchtower サービスの environment)に、以下の環境変数を追加します。
- WATCHTOWER_LABEL_ENABLE=true
💡 なぜやるのか(Why)
デフォルトのWatchtowerは、サーバー内で動いている全てのコンテナを「お、これも更新しちゃおう!」と親切心で片っ端からアップデートしてしまいます。
これに対し、WATCHTOWER_LABEL_ENABLE=true を指定することで、「コンテナに貼られている目印(ラベル)をちゃんと確認して、その指示に従って動いてね」という賢いモードに切り替えることができます。
これを入れないと、いくら次のステップで除外設定を書いても無視されてしまうため、必須の設定です。
ステップ2:MySQLなどの更新したくないコンテナに「除外ラベル」を記述する
次に、絶対に勝手にアップデートされたくないコンテナ(今回の例では db サービス)の直下に labels: という項目を作り、以下の文字列を記述します。
labels:
- "com.centurylinklabs.watchtower.enable=false"
💡 なぜやるのか(Why)
ここで登場する 「ラベル(Labels)」 とは、Dockerコンテナに貼り付ける「付箋(ふせん)」のようなものです。 Watchtowerは先ほどステップ1で「ラベル感知モード」になっているため、各コンテナの付箋をチェックしながら巡回します。そして、この "com.centurylinklabs.watchtower.enable=false" という付箋を見つけると、「あ、このデータベースは『自動更新を有効(enable)にするか?=いいえ(false)』って書いてあるから、触らずにおこう!」と判断してスルーしてくれます。これにより、大切なデータが勝手に書き換わるリスクを100%シャットアウトできるのです。
ステップ3:cron式(WATCHTOWER_SCHEDULE)を使ってアップデートを深夜4時に固定する
続いて、Watchtowerの実行タイミングをコントロールするために、以下の2行をWatchtowerの環境変数に追加します。
- WATCHTOWER_SCHEDULE=0 0 4 * * *
- TZ=Asia/Tokyo
💡 なぜやるのか(Why)
デフォルトのWatchtowerは、5分ごと、あるいは1時間に1回といった高頻度で「新しいイメージはないか?」と裏でチェックしに行きます。
しかし、ユーザーがサイトを見ている昼間に突然アップデートが始まると、一瞬ですがサービスが切断されてしまいます。 そこで、WATCHTOWER_SCHEDULE を使って実行時間をスケジュール管理します。
ここで使われている 0 0 4 * * * という記述は 「cron(クーロン)式」 と呼ばれる、Linuxの世界で時間を指定するための世界共通の言語(文法)です。
左から順に 「秒(0)分(0)時(4)日()月()曜日(*)」 を表しており、「毎日、朝の4時0分0秒に実行せよ」という意味になります。 一番ユーザーのアクセスが少なく、万が一トラブルが起きても深夜のうちに対処できる「午前4時」に固定するのが、プロのインフラ運用の現場でも鉄板のスケジュールとなっています。
ステップ4:docker composeで設定を反映し、Watchtowerの起動ログを確認する
設定が書き終わったら、ファイルを保存して以下のコマンドを実行し、設定をシステムに反映させます。
# -d はバックグラウンド(裏側)で実行するという意味です
docker compose up -d
起動したら、本当にWatchtowerが新しいスケジュールと除外ルールを認識したか、以下のコマンドでログ(システムの日記帳のようなもの)を確認します。
docker compose logs watchtower
💡 なぜやるのか(Why)
プロのエンジニアは、設定ファイルを書き換えて満足することはありません。
「本当に自分の意図通りにシステムが認識したか」を、エビデンス(証拠ログ)で確認するまでが仕事です。 ログを表示した際、エラーが出ておらず、以下のようなメッセージが流れていれば大成功です。
time="2026-06-19T20:30:00Z" level=info msg="Scheduling first run: 2026-06-20 04:00:00 +0900 JST"
「最初の実行は、明日の朝4:00(日本時間:JST)にスケジュールしたよ」とWatchtowerが宣言してくれていれば、あなたの狙い通りに動いています!
3. インフラ運用のプロが解説!Docker自動アップデートに潜む2つの罠
ここでは、実際の企業のインフラを預かる運用監視チームなどの視点から、なぜこの設定が「単に動くだけでなく、必須のベストプラクティス」なのかを一歩深掘りして解説します。
なぜMySQLなどデータを持つ「ステートフル」なコンテナの自動更新は危険なのか?
ITの世界には「ステートレス(状態を持たない)」と「ステートフル(状態を持つ)」という重要な概念があります。
- NginxなどのWebサーバー(ステートレス): コンテナの中に大切なデータは保存されていません。最新版にアップデートして、コンテナが丸ごと新品に置き換わっても何も困りません。
- MySQLなどのデータベース(ステートフル): コンテナの外部(ボリューム)に、ユーザーのパスワードやブログの本文など、すべての「状態(データ)」が蓄積されています。
もしデータベースのメジャーアップデート(例: MySQL 5.7から8.0など)が勝手に走ると、データの保存形式(スキーマ)が内部で強制的に書き換わることがあります。
すると、古いデータ構造のまま新しいシステムが起動しようとしてエラーを起こし、「データが壊れて二度と復旧できない」という最悪の事態を招きます。
そのため、プロの現場では「データを持つコンテナの自動更新は絶対にNG」とされており、必ず手動でバックアップを取得した上で、慎重にアップデート作業を行います。
スケジュール指定時に大惨事を防ぐ「タイムゾーン(TZ=Asia/Tokyo)」の重要性
ステップ3で、何気なく - TZ=Asia/Tokyo という設定を入れました。実は、これが無いと大惨事になります。
Dockerコンテナの内部は、世界中のどこで動かしても同じになるよう、基本的には「ロンドン時間(世界標準時:UTC)」で動いています。
日本(JST)とは 「9時間の時差」 があります。
もし、TZ=Asia/Tokyo を書き忘れた状態で 0 0 4 * * *(朝4時)を設定すると、Watchtowerは「ロンドン時間の朝4時」に動いてしまいます。
ロンドン時間の朝4時は、日本時間でいうと「13時(真っ昼間)」 です。
「アクセスが一番少ない深夜4時に設定したはずが、一番アクセスが多いお昼の13時にシステムが止まってしまった…」という初心者エンジニアが非常に多いので、タイムゾーンの明示は絶対に忘れないようにしてください。
4. Watchtowerのスケジュール管理・更新除外でよくある2大エラーと対処法
初学者がこの設定をするときに、高確率で遭遇するエラーメッセージとその解決のチェックポイントをまとめました。
エラーが出たら、答えをすぐに探すのではなく、まずは「エラーメッセージのどこに原因が書かれているか」に注目してみましょう。
エラー1:設定した時間になっても動かない(cronフォーマットの記述エラー)
Watchtowerのログを見たとき、以下のようなメッセージが出ている場合があります。
time="2026-06-19T20:34:00Z" level=error msg="Cron expression does not match required format"
🔍 どこに注目すべきか?
メッセージ内の level=error の後ろ、Cron expression does not match required format(cronの表現が要求されたフォーマットと一致しません)という部分に注目してください。
✅ 解決策
Linuxの一般的なcronは「分・時・日・月・曜日」の5項目で書くことが多いですが、Watchtowerのcron式は「秒」を含めた6項目で記述する必要があります。
- ❌ 悪い例:
0 4 * * *(5項目しかない) - ⭕ 正しい例:
0 0 4 * * *(先頭に「0秒」を足した6項目にする)
スペースの数や項目の数を見直してみましょう。
エラー2:除外したはずのコンテナが更新された(インデント・階層のエラー)
「MySQLに更新除外ラベルを貼ったはずなのに、通知を見たらアップデートされてしまっていた…」というケースです。
🔍 どこに注目すべきか?
docker-compose.yml の記述において、「インデント(字下げ)」の縦のラインに注目してください。
✅ 解決策
YAML形式のファイルは、スペースの数(階層構造)をミリ単位で厳密にチェックします。よくある失敗は、labels: を書く位置がズレているパターンです。
❌ 悪い例(environment: の中に labels: が入り込んでしまっている):
db:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: secret_password
labels: # 階層がズレているため無視される!
- "com.centurylinklabs.watchtower.enable=false"
⭕ 正しい例(db: の直下に並列で labels: がある):
db:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: secret_password
labels: # db: から見てスペース2個分下がった正しい位置
- "com.centurylinklabs.watchtower.enable=false"
一字一句、インデントの縦のラインが揃っているか確認してください。
5. まとめと次のステップ
今回の振り返り:安全な自動化こそが「真の効率化」
お疲れ様でした!今回の要点を一言でまとめます。
WATCHTOWER_LABEL_ENABLE=trueと各コンテナのlabels:で、特定の重要コンテナを確実に守る。WATCHTOWER_SCHEDULEで実行時間をアクセスが少ない「深夜4時」に固定し、TZ=Asia/Tokyoで時差の罠を防ぐ。
これで、あなたのサーバーは「守るべきものは守り、攻めるべきものは深夜に自動で最新にする」という、まさにプロのインフラエンジニアと同じ安全な自動運用環境へと進化しました。
もう予期せぬアップデートに怯えて夜怯える必要はありません。安心してシステムを眠らせておきましょう!
これにて、全3回にわたるWatchtowerでの「導入・通知・制御」の自動アップデート連載はコンプリートです。仕組みを理解して実装できた自分自身を、ぜひ褒めてあげてくださいね。
🚀 【週末限定】さらに一歩進んだ「AI自動化」の世界へ!初期モニター募集中
インフラの自動化に成功し、テクノロジーによる効率化の快感を覚えたあなたへ、次なるステップのご案内です。
サーバーの管理が自動化できたなら、次は「あなた自身の作業(コンテンツ作成やブログ執筆)」も完全に自動化してみませんか?
副業ブログやnoteの運用において、「AIに記事を書かせようとしたけれど、後半になるにつれて同じ話をループしたり、もっともらしい嘘(架空の実績など)を勝手に捏造されて、結局手直しに何時間もかかった…」という経験はありませんか?
そんなAI執筆の弱点を完全に克服した、『note記事自動生成システム(Gemini対応・Windows用デスクトップアプリ)』を開発しました!
本ツールは、1発で長文を書かせるのではなく、内部で特別な「3段階の分割リレー執筆パイプライン」を採用しています。全体の骨組み(プロット)を作ってから、1章ずつ前の文章の文脈を引き継いで肉付けし、最後に一番惹きつけるタイトルと導入文を仕上げるため、人間のプロブロガーが書いたような一貫性と深みのある高品質な下書きが、1クリックで瞬時に完成します。
実は、このツールは私の開発環境では完璧に動作していますが、「まだ自分以外の様々なPC環境で動かした実績」がありません。
そこで、「もし小さなエラーが出たら、画面のスクショを撮って教えてあげるよ!」「一緒にツールを育てる感覚で試してあげるよ!」と言ってくださる心優しい初期モニター様を【金土日限定】で募集します。
その開発協力(バグ出し)のお礼として、BOOTHでの通常価格2,980円のところ、この週末(日曜日 23:59まで)限定で【50%OFF】の「1,490円」にて完全版をご提供します!
一度購入いただければ、今後の機能追加や修正が行われても【永久に無料】で最新バージョンを再ダウンロード可能な安心仕様です。今手に入れるのが、間違いなく一番お得なタイミングとなります。
インフラだけでなく、あなたのビジネスのコアである「コンテンツ作成」も自動化し、圧倒的な生産性を手に入れてみませんか?興味のある方は、ぜひ以下のリンクから詳細をチェックしてください!

👉 【1クリック自動化】note記事自動生成システムを半額で手に入れる(BOOTH販売ページへ)
(※月曜日の0:00には自動的に通常価格の2,980円に戻りますのでご注意ください)
筆者のnote👇



コメント