🎄

supervisordでコンテナ内の設定ファイルの変更検知と自動リロードをする(自動同期を添えて)

に公開

この記事は SKIYAKI Tech Blog Advent Calendar 2025 の1日目の記事になります。


「Dockerで動かしているconf変更してわざわざ再起動させるの面倒だな…」
「設定変更したのに上手く動かない…と思ってたらDockerコンテナの再起動忘れてた…やったと思ってたんだけどな…」

そんな経験あると思います。私はあります。

本記事では、設定ファイルを書き換えたら変更を検知して自動でリロードしてくれるDockerイメージを作ります。
さらに、ローカルファイルとコンテナ上のファイルを同期させる Docker Compose 環境も作ってみます。
今回は nginx の設定を自動リロードしてくれるDockerイメージを作ってみましょう。

以下の環境で試してみます。

名前 バージョン
Docker 28.5.2
Docker Desktop 4.51.0 (210443)
Docker Compose v2.40.3-desktop.1
nginx(Docker image) 1.29.3-alpine

supervisord とは

supervisord (Supervisor) は、UNIX系OS上で複数のプロセスを管理・監視するためのクライアント/サーバーシステムです。

通常、Dockerコンテナは「1コンテナにつき1プロセス」という原則で設計されており、コンテナ起動時に指定したメインプロセスが終了するとコンテナ自体も停止してしまいます。
しかし、今回のように「Nginx(メインのWebサーバー)」と「設定ファイルの変更を監視するスクリプト」といった複数のプロセスを1つのコンテナ内で同時に稼働させたい場合には、それらを統括するプロセスマネージャーが必要になります。
そのために supervisord を稼働させ、 supervisord 越しに nginx プロセスの起動と、Nginxの設定リロードを実施する監視スクリプトの起動を実現してみます。

今回は supervisord を採用し、nginx と監視スクリプトの両方を稼働させるという役割を担わせます。

これにより、Dockerコンテナのメリットを活かしつつ、柔軟な開発環境を構築することができます。

Dockerイメージを作る

作業用のディレクトリを作って移動しておきます。
ここに一連のファイルを保存していきます。

$ mkdir -p nginx_autoreload && cd $_

Dockerfile

既存のDockerイメージを元にして、Dockerfileを書いていきます。
まず必要になるのは、メインで稼働させる nginx ですが、これは元にするnginxのDockerイメージに既に導入されているため別途導入しなくてもOKですね。
他に必要となるのは inotify-toolssupervisord となります。
今回元にするDockerイメージのディストリビューションはalpineのため、上記のツールは apk を使って導入します。
また、その他必要なファイルをローカルに作っておき、それぞれ COPY でDockerイメージのビルド時に組み込みます。

では早速Dockerfileを書いていきましょう。
以下のようなDockerfileを用意します。
COPY でDockerイメージに追加しているファイルはこの後用意していきます。

Dockerfile
FROM nginx:1.29.3-alpine-slim

RUN apk update \
 && apk upgrade \
 && apk add inotify-tools supervisor \
 && apk cache clean

COPY ./nginx.conf /etc/nginx/nginx.conf
COPY ./conf.d /etc/nginx/conf.d

COPY --chmod=755 ./entrypoint.sh /opt/entrypoint.sh
COPY ./supervisord.conf /opt/supervisord.conf

EXPOSE 80
EXPOSE 443

ENTRYPOINT ["/opt/entrypoint.sh"]
CMD ["start"]

ENTRYPOINT には自前で作った entrypoint.sh を指定します。
CMD には、デフォルト引数として start を指定しておきます。
引数は複数使用できる予定で、詳細は次で解説しますが、 start の場合は単純にnginxを起動させるだけとなっています。

次に COPY で追加するファイルを作成していきます。

entrypoint.sh

entrypoint.sh も以下のように新たに作ります。
作っている関数や引数に指定できる文字列は以下の通りです。

関数名 引数名 説明
log_info() - 標準出力に日付付きで指定した文字列を出力するための内部関数
nginx_autoreloader() nginx-autoreloader /etc/nginx 以下の変更を検知したらnginxのreloadを実行する
nginx_start() start nginxを起動する
nginx_reload() reload nginxのreloadを実行する
nginx_check() check nginxのconfを確認する
- supervisord supervisordを起動する
- exec 引数をコマンドとして実行する

今回の自動リロードを実現するにあたって、 enrypoint.sh で肝になる関数は、 nginx_autoreloader() と、 supervisord になります。
まずは entrypoint.sh の全文を記載します。

entrypoint.sh
#!/bin/sh

function usage() {
  local _script_name="$0"
  cat <<EOL >&2
${_script_name} is script for starting nginx

Usage:
    ${_script_name} [[command] [arguments]]

Command:
    start               start nginx
    check               check nginx config
    reload              reload nginx process
    nginx-autoreloader  start nginx-autoreloder
    supervisord         start supervisord
    exec                execute linux command on Docker container(default option)
                        required [arguments]

    exec e.g)
        $ ${_script_name} exec ls -la
        or
        $ ${_script_name} ls -la
EOL
}

function log_info() {
  time=$(date "+%Y/%m/%d %H:%M:%S")
  echo "${time} [info] $@" > /dev/stdout
}

function nginx_autoreloader() {
  while inotifywait -e create -e modify -e delete -e move -r /etc/nginx > /dev/null 2>&1; do
    # 15秒の待機時間を置く
    sleep 15
    # nginxのステータスチェックをして成功(0)であればnginxをreloadする
    nginx_status
    if [ $? -eq 0 ]; then
      log_info "Detected Nginx Configuration Change"
      log_info "Executing: nginx -s reload"
      nginx_reload
    fi
  done
}

function nginx_start() {
  exec nginx -g 'daemon off;'
}

function nginx_reload() {
  nginx -s reload
}

function nginx_check() {
  nginx -t
}

_ARG="$1"

if [ ! -z "${_ARG}" ]; then
  case "${_ARG}" in
    --help|-h|help|--usage|usage )
      usage
    ;;
    start )
      nginx_start
    ;;
    check )
      nginx_check
    ;;
    reload )
      nginx_reload
    ;;
    nginx-autoreloader )
      nginx_autoreloader
    ;;
    supervisord )
      exec /usr/bin/supervisord -c /opt/supervisord.conf
    ;;
    exec )
      shift 1
      exec "$@"
    ;;
    * )
      exec "$@"
    ;;
  esac
else
  usage
  exit 1
fi

これで全文です。かなり短めのスクリプトになっています。
全体の解説はせず、肝である nginx_autoreloader() と、 supervisord を見ていきましょう。
最初に nginx_autoreloader() から見ていきます。

nginx_autoreloader()

nginx_autoreloader() は以下のような関数になっています。

nginx_autoreloader()
function nginx_autoreloader() {
  while inotifywait -e create -e modify -e delete -e move --exclude .swp -r /etc/nginx > /dev/null 2>&1; do
    # 15秒の待機時間を置く
    sleep 15
    # nginxのステータスチェックをして成功(0)であればnginxをreloadする
    nginx_status
    if [ $? -eq 0 ]; then
      log_info "Detected Nginx Configuration Change"
      log_info "Executing: nginx -s reload"
      nginx_reload
    fi
  done
}

どんな処理をしているのか

while を使ったループの流れとしては以下のような形です。

  1. while を使って inotifywait を繰り返し実行し、 /etc/nginx 以下のイベントを監視します。
  2. ファイルの作成/変更/削除がされると、 inotifywait コマンドは成功(終了コード 0)して終了します。
  3. while はコマンドの成功を受けて、 while 内部の処理へ移行します。
  4. まず最初に sleep 15 としています。これはファイルの変更を短時間に何度も検知した場合、その回数だけnginxのreloadが走ってしまうのを防ぐための措置になります。
  5. 次に nginx_status を実行し、設定ファイルに不備がないかを確認します。もし不備があってチェックが失敗した場合はreloadされません。
  6. 不備がなければ標準出力にログを出力し、 nginx_reload を実行して、設定のreloadを実施します。
  7. ループ内の処理が終わると、 while は再び inotifywait を実行し、次のイベントを待ち受けます。

inotifywait というコマンドを使って /etc/nginx 以下のファイルの変更をリアルタイムで監視します。
/etc/nginx 以下でファイルの作成/変更/削除がされたら、 inotifywait コマンドの実行が終了し、 while 内の処理に進むというものです。
これで /etc/nginx 以下のファイルの変更検知ができます。

supervisord

supervisord はシンプルで、単純に supervisord コマンドを実行させているだけのものとなります。

supervisord
    supervisord )
      exec /usr/bin/supervisord -c /opt/supervisord.conf
    ;;

引数に COPY でDockerイメージに組み込んだ /opt/supervisord.conf を指定しているだけとなっています。

supervisord.conf

supervisord.conf の内容も大したことはしていません。
supervisordnodaemon で稼働させ、
/opt/entrypoint.sh startnginx を稼働させ、
/opt/entrypoint.sh nginx-autoreloadernginx_autoreloader を稼働させているだけとなります。

[supervisord]
nodaemon = true
user = root
stdout_logfile = /dev/stdout
stdout_logfile_maxbytes = 0
stderr_logfile = /dev/stderr
stderr_logfile_maxbytes = 0

[program:nginx]
command = /opt/entrypoint.sh start
stdout_logfile = /dev/stdout
stdout_logfile_maxbytes = 0
stderr_logfile = /dev/stderr
stderr_logfile_maxbytes = 0

[program:nginx_autoreloader]
command = /opt/entrypoint.sh nginx-autoreloader
stdout_logfile = /dev/stdout
stdout_logfile_maxbytes = 0
stderr_logfile = /dev/stderr
stderr_logfile_maxbytes = 0

プロセス一覧を確認してみると、PID1に supervisord が存在していて、他のプロセスとして nginx/opt/entrypoint.sh nginx-autoreloader が稼働している形となっていることがわかります。

ps auxwwf
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root         1  0.8  0.3  34624 27436 pts/0    Ss+  12:32   0:00 /usr/bin/python3 /usr/bin/supervisord -c /opt/supervisord.conf
root         6  0.0  0.0  10052  5896 pts/0    S    12:32   0:00 nginx: master process nginx -g daemon off;
nginx        9  0.0  0.0  10508  2896 pts/0    S    12:32   0:00  \_ nginx: worker process
nginx       10  0.0  0.0  10508  2896 pts/0    S    12:32   0:00  \_ nginx: worker process
nginx       11  0.0  0.0  10508  2896 pts/0    S    12:32   0:00  \_ nginx: worker process
nginx       12  0.0  0.0  10508  2896 pts/0    S    12:32   0:00  \_ nginx: worker process
root         7  0.0  0.0   1708  1012 pts/0    S    12:32   0:00 /bin/sh /opt/entrypoint.sh nginx-autoreloader
root         8  0.0  0.0   1160   664 pts/0    S    12:32   0:00  \_ inotifywait -e create -e modify -e delete -e move --exclude .swp -r /etc/nginx

この nginxnginx-autoreloader を同時に動かさないと、今回の自動リロードが実現できないのです。
そのため、わざわざ supervisord を用いて複数プロセスを稼働させています。

nginx.conf など

後はnginxの設定ファイルですね。
これらも以下のように一旦テキトーに作っておきましょう。
ちなみにこの設定ファイルはnginxのDockerイメージから引っ張ってきてコメントなどを消したものになるので、ほとんどデフォルトの状態となっています。

nginx.conf
user  nginx;
worker_processes  auto;

error_log  /var/log/nginx/error.log notice;
pid        /run/nginx.pid;

events {
    worker_connections  1024;
}

http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;
    sendfile        on;
    keepalive_timeout  65;
    include /etc/nginx/conf.d/*.conf;
}

conf.d/default.conf も作っておきます。
これも同じくDockerイメージから引っ張ってきたファイルです。

conf.d/default.conf
server {
    listen       80;
    server_name  localhost;

    location / {
        root   /usr/share/nginx/html;
        index  index.html index.htm;
    }

    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;
    }
}

ここまで作ったら、Dockerイメージに組み込むファイルは完成です。

ファイルの確認

カレントディレクトリに作ったファイルは以下のような形になると思います。

ファイル構成
.
├── conf.d
│   └── default.conf
├── Dockerfile
├── entrypoint.sh
├── nginx.conf
└── supervisord.conf

Dockerコンテナの動作確認

ここまでできたら一旦ビルドして実行してみましょう。

docker image build && docker container run

nginx:1.29.3-autoreload という名前のDockerイメージにしてみます。

docker image build
$ docker image build -t nginx:1.29.3-autoreload .

ビルドが完了したらDockerコンテナとして実行してみます。
引数には supervisord を指定します。
また、Dockerコンテナには名前も付けてあげましょう。ここでは nginx_autoreload としておきます。

docker container run(foregroud)
$ docker container run --rm --name nginx_autoreload \
  -itd nginx:1.29.3-autoreload supervisord

/usr/lib/python3.12/site-packages/supervisor/options.py:13: UserWarning: pkg_resources is deprecated as an API. See https://setuptools.pypa.io/en/latest/pkg_resources.html. The pkg_resources package is slated for removal as early as 2025-11-30. Refrain from using this package or pin to Setuptools<81.
  import pkg_resources
2025-11-19 14:34:47,870 INFO Set uid to user 0 succeeded
2025-11-19 14:34:47,871 INFO supervisord started with pid 1
2025-11-19 14:34:48,876 INFO spawned: 'nginx' with pid 6
2025-11-19 14:34:48,879 INFO spawned: 'nginx-autoreloader' with pid 7
2025/11/19 14:34:48 [notice] 6#6: using the "epoll" event method
2025/11/19 14:34:48 [notice] 6#6: nginx/1.29.3
2025/11/19 14:34:48 [notice] 6#6: built by gcc 14.2.0 (Alpine 14.2.0)
2025/11/19 14:34:48 [notice] 6#6: OS: Linux 6.12.54-linuxkit
2025/11/19 14:34:48 [notice] 6#6: getrlimit(RLIMIT_NOFILE): 1048576:1048576
2025/11/19 14:34:48 [notice] 6#6: start worker processes
2025/11/19 14:34:48 [notice] 6#6: start worker process 9
2025/11/19 14:34:48 [notice] 6#6: start worker process 10
2025/11/19 14:34:48 [notice] 6#6: start worker process 11
2025/11/19 14:34:48 [notice] 6#6: start worker process 12
2025-11-19 14:34:49,891 INFO success: nginx entered RUNNING state, process has stayed up for > than 1 seconds (startsecs)
2025-11-19 14:34:49,891 INFO success: nginx-autoreloader entered RUNNING state, process has stayed up for > than 1 seconds (startsecs)

Dockerコンテナを稼働させたら、別ターミナルで docker container exec で、実行させたコンテナの sh を起動させて、 /etc/nginx/nginx.conf に文字列を追記してみます。
ここではコメントとして現在日時を追記してみます。
date コマンドで YYYY/MM/DD hh:mm:ss を出し、 tee -a/etc/nginx/nginx.conf に文字列を追記します。

docker container exec(別ターミナル)
$ docker container exec -it nginx_autoreload sh
/ #
/ # echo "# $(date +'%Y/%m/%d %H:%M:%S')" | tee -a /etc/nginx/nginx.conf
# 2025/11/19 14:34:57

docker container run で起動させた方の元のターミナルに戻ります。
標準出力に約15秒経過後に nginx -t の出力と、 nginx -s reload の出力がされるはずです。

docker container run(foreground)
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
2025/11/19 14:35:13 [info] Detected Nginx Configuration Change
2025/11/19 14:35:13 [info] Executing: nginx -s reload
2025/11/19 14:35:13 [notice] 26#26: signal process started
2025/11/19 14:35:13 [notice] 6#6: signal 1 (SIGHUP) received from 26, reconfiguring
2025/11/19 14:35:13 [notice] 6#6: reconfiguring
2025/11/19 14:35:13 [notice] 6#6: using the "epoll" event method
2025/11/19 14:35:13 [notice] 6#6: start worker processes
2025/11/19 14:35:13 [notice] 6#6: start worker process 28
2025/11/19 14:35:13 [notice] 6#6: start worker process 29
2025/11/19 14:35:13 [notice] 6#6: start worker process 30
2025/11/19 14:35:13 [notice] 6#6: start worker process 31
2025/11/19 14:35:13 [notice] 10#10: gracefully shutting down
2025/11/19 14:35:13 [notice] 9#9: gracefully shutting down
2025/11/19 14:35:13 [notice] 9#9: exiting
2025/11/19 14:35:13 [notice] 10#10: exiting
2025/11/19 14:35:13 [notice] 9#9: exit
2025/11/19 14:35:13 [notice] 10#10: exit
2025/11/19 14:35:13 [notice] 11#11: gracefully shutting down
2025/11/19 14:35:13 [notice] 11#11: exiting
2025/11/19 14:35:13 [notice] 12#12: gracefully shutting down
2025/11/19 14:35:13 [notice] 12#12: exiting
2025/11/19 14:35:13 [notice] 11#11: exit
2025/11/19 14:35:13 [notice] 12#12: exit
2025/11/19 14:35:13 [notice] 6#6: signal 17 (SIGCHLD) received from 12
2025/11/19 14:35:13 [notice] 6#6: worker process 12 exited with code 0
2025/11/19 14:35:13 [notice] 6#6: signal 29 (SIGIO) received
2025/11/19 14:35:13 [notice] 6#6: signal 17 (SIGCHLD) received from 9
2025/11/19 14:35:13 [notice] 6#6: worker process 9 exited with code 0
2025/11/19 14:35:13 [notice] 6#6: worker process 10 exited with code 0
2025/11/19 14:35:13 [notice] 6#6: signal 29 (SIGIO) received
2025/11/19 14:35:13 [notice] 6#6: signal 17 (SIGCHLD) received from 11
2025/11/19 14:35:13 [notice] 6#6: worker process 11 exited with code 0
2025/11/19 14:35:13 [notice] 6#6: signal 29 (SIGIO) received

ここまで確認できればDockerイメージの作成は完了となります。

Docker Compose Watch でローカルのファイルと同期させる

Dockerイメージの用意はできました。
でもわざわざコンテナのシェルを実行して変更するというのは利便性に欠けますね。
そこで、 Docker Compose Watch を使って、ローカルファイルとコンテナ上のファイルの同期をするようにします。
これをすることで、ローカルファイルに変更を加えればコンテナ上のファイルも同期され、更に同期されるということは「ファイルの内容に変更が加えられる」ということなので、コンテナ上の変更検知に引っ掛かり、自動リロードされる…という仕組みです。

compose.yml

docker compose 用の compose.yml を書いていきます。
watch でローカルファイルと同期をさせるために、通常の設定以外に develop を用いた同期設定用文言を書いていきます。

watchの例
develop:
  watch:
  - action: [Watchのアクション指定/ sync|rebuild]
    path: [同期元となるローカルファイルのファイルパス]
    target: [同期先となるDockerコンテナ上のファイルパス]

これを踏まえて compose.yml を書いてみます。

compose.yml
name: autoreload

services:
  nginx_autoreload:
    image: nginx:1.29.3-autoreload
    build:
      context: ./
      dockerfile: ./Dockerfile
    container_name: nginx_autoreload
    ports:
    - 127.0.0.1:80:80/tcp
    - 127.0.0.1:443:443/tcp
    command:
    - "supervisord"
    # 以下がDocker Compose Watch用の設定
    develop:
      watch:
      - action: sync
        path: ./conf.d
        target: /etc/nginx/conf.d
      - action: sync
        path: ./nginx.conf
        target: /etc/nginx/nginx.conf

簡単ですね。

Docker Compose Watch で動作確認

compose.yml を作ったので docker compose up -w で立ち上げてみます。
Watch を有効化するために -w オプションを付与しています。

docker compose up -w
$ docker compose up -w
[+] Running 2/2
 ✔ Network autoreload_default  Created                                                                0.0s
 ✔ Container nginx_autoreload  Created                                                                0.0s
        ⦿ Watch enabled
Attaching to nginx_autoreload
nginx_autoreload  | /usr/lib/python3.12/site-packages/supervisor/options.py:13: UserWarning: pkg_resources is deprecated as an API. See https://setuptools.pypa.io/en/latest/pkg_resources.html. The pkg_resources package is slated for removal as early as 2025-11-30. Refrain from using this package or pin to Setuptools<81.
nginx_autoreload  |   import pkg_resources
nginx_autoreload  | 2025-11-20 12:08:26,152 INFO Set uid to user 0 succeeded
nginx_autoreload  | 2025-11-20 12:08:26,153 INFO supervisord started with pid 1
nginx_autoreload  | 2025-11-20 12:08:27,156 INFO spawned: 'nginx' with pid 7
nginx_autoreload  | 2025-11-20 12:08:27,158 INFO spawned: 'nginx-autoreloader' with pid 8
nginx_autoreload  | 2025/11/20 12:08:27 [notice] 7#7: using the "epoll" event method
nginx_autoreload  | 2025/11/20 12:08:27 [notice] 7#7: nginx/1.29.3
nginx_autoreload  | 2025/11/20 12:08:27 [notice] 7#7: built by gcc 14.2.0 (Alpine 14.2.0)
nginx_autoreload  | 2025/11/20 12:08:27 [notice] 7#7: OS: Linux 6.12.54-linuxkit
nginx_autoreload  | 2025/11/20 12:08:27 [notice] 7#7: getrlimit(RLIMIT_NOFILE): 1048576:1048576
nginx_autoreload  | 2025/11/20 12:08:27 [notice] 7#7: start worker processes
nginx_autoreload  | 2025/11/20 12:08:27 [notice] 7#7: start worker process 10
nginx_autoreload  | 2025/11/20 12:08:27 [notice] 7#7: start worker process 11
nginx_autoreload  | 2025/11/20 12:08:27 [notice] 7#7: start worker process 12
nginx_autoreload  | 2025/11/20 12:08:27 [notice] 7#7: start worker process 13
nginx_autoreload  | 2025-11-20 12:08:28,176 INFO success: nginx entered RUNNING state, process has stayed up for > than 1 seconds (startsecs)
nginx_autoreload  | 2025-11-20 12:08:28,177 INFO success: nginx-autoreloader entered RUNNING state, process has stayed up for > than 1 seconds (startsecs)

別のターミナルを開きます。
Dockerコンテナの動作確認と同じような形で、今度はローカルファイルの nginx.conf に追記してみます。

$ echo "# $(date +'%Y/%m/%d %H:%M:%S')" | tee -a nginx.conf
# 2025/11/20 21:08:35

元のターミナルに戻って同期を示す Syncing service "nginx_autoreload" after 1 changes were detected と、その後に設定ファイルチェック、リロードのログが出力されればOKです。

docker compose up -w(続き)
                  ⦿ Syncing service "nginx_autoreload" after 1 changes were detected
nginx_autoreload  | nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx_autoreload  | nginx: configuration file /etc/nginx/nginx.conf test is successful
nginx_autoreload  | 2025/11/20 12:08:50 [info] Detected Nginx Configuration Change
nginx_autoreload  | 2025/11/20 12:08:50 [info] Executing: nginx -s reload
nginx_autoreload  | 2025/11/20 12:08:50 [notice] 18#18: signal process started
nginx_autoreload  | 2025/11/20 12:08:50 [notice] 7#7: signal 1 (SIGHUP) received from 18, reconfiguring
nginx_autoreload  | 2025/11/20 12:08:50 [notice] 7#7: reconfiguring
nginx_autoreload  | 2025/11/20 12:08:50 [notice] 7#7: using the "epoll" event method
nginx_autoreload  | 2025/11/20 12:08:50 [notice] 7#7: start worker processes
nginx_autoreload  | 2025/11/20 12:08:50 [notice] 7#7: start worker process 20
nginx_autoreload  | 2025/11/20 12:08:50 [notice] 7#7: start worker process 21
nginx_autoreload  | 2025/11/20 12:08:50 [notice] 7#7: start worker process 22
nginx_autoreload  | 2025/11/20 12:08:50 [notice] 7#7: start worker process 23
nginx_autoreload  | 2025/11/20 12:08:50 [notice] 11#11: gracefully shutting down
nginx_autoreload  | 2025/11/20 12:08:50 [notice] 13#13: gracefully shutting down
nginx_autoreload  | 2025/11/20 12:08:50 [notice] 10#10: gracefully shutting down
nginx_autoreload  | 2025/11/20 12:08:50 [notice] 12#12: gracefully shutting down
nginx_autoreload  | 2025/11/20 12:08:50 [notice] 12#12: exiting
nginx_autoreload  | 2025/11/20 12:08:50 [notice] 13#13: exiting
nginx_autoreload  | 2025/11/20 12:08:50 [notice] 10#10: exiting
nginx_autoreload  | 2025/11/20 12:08:50 [notice] 13#13: exit
nginx_autoreload  | 2025/11/20 12:08:50 [notice] 12#12: exit
nginx_autoreload  | 2025/11/20 12:08:50 [notice] 10#10: exit
nginx_autoreload  | 2025/11/20 12:08:50 [notice] 11#11: exiting
nginx_autoreload  | 2025/11/20 12:08:50 [notice] 11#11: exit
nginx_autoreload  | 2025/11/20 12:08:50 [notice] 7#7: signal 17 (SIGCHLD) received from 10
nginx_autoreload  | 2025/11/20 12:08:50 [notice] 7#7: worker process 10 exited with code 0
nginx_autoreload  | 2025/11/20 12:08:50 [notice] 7#7: signal 29 (SIGIO) received
nginx_autoreload  | 2025/11/20 12:08:50 [notice] 7#7: signal 17 (SIGCHLD) received from 12
nginx_autoreload  | 2025/11/20 12:08:50 [notice] 7#7: worker process 11 exited with code 0
nginx_autoreload  | 2025/11/20 12:08:50 [notice] 7#7: worker process 12 exited with code 0
nginx_autoreload  | 2025/11/20 12:08:50 [notice] 7#7: signal 29 (SIGIO) received
nginx_autoreload  | 2025/11/20 12:08:50 [notice] 7#7: signal 17 (SIGCHLD) received from 13
nginx_autoreload  | 2025/11/20 12:08:50 [notice] 7#7: worker process 13 exited with code 0
nginx_autoreload  | 2025/11/20 12:08:50 [notice] 7#7: signal 29 (SIGIO) received

もっと簡単にやりたいな…え!?できるんですか!?

compose.yml は良いけど、わざわざ Dockerfile を書いたりしたくないなあ…。
そうですよね。
はい。もっとシンプルにできます。
それが watchのactionに指定できる sync+restart です。
その名の通り、「同期してコンテナをリスタートする」というものです。

sync+restart
    develop:
      watch:
      - action: sync+restart
        path: ./conf.d
        target: /etc/nginx/conf.d
      - action: sync+restart
        path: ./nginx.conf
        target: /etc/nginx/nginx.conf

これをすれば独自で Dockerfile を書かなくても良いのです。
え…じゃあこれでイイじゃん…?ねぇ…?(ちゃぶ台返し)
…とはいえ「最初にローカルファイルを COPY しておきたい」といったことがあればDockerfileを書かないといけません。
また、設定ファイル等のチェックは一切しないため、変更した設定ファイルの文法がおかしかった場合、コンテナが立ち上がってこない…なんてことも考えられます。

そんなわけで、色々安全にしたいなら Dockerfile を自前で書いて、 ENTRYPOINT も自前で用意するのが…良いように思います…。
…が… docker compose って基本的にローカルでしか使わないですよね…。
watchなんか特にローカルでしか使わないし…基本的に sync+restart だけで事足りるんじゃないですかね…。
文法ミスってた時も「自動リロードされない」よりも「コンテナ立ち上がって来ない」の方がわかりやすいような…。

どちらを選ぶべきか

ここまで長々と Dockerfile を書く方法を説明してきましたが、実際にはどちらを選ぶべきでしょうか。

最後にそれぞれのメリット/デメリットを整理してみます。

Dockerfile + supervisord で自動リロード

メリット:

  • 設定ファイルの検証が可能。文法エラーがあってもサービスは継続稼働
  • コンテナの再起動不要。Nginxのリロードだけで済むため接続が切れない
  • リロードのタイミングや動作を細かく制御できる

デメリット:

  • Dockerfileentrypoint.shsupervisord.conf など複数ファイルの作成・管理が必要
  • supervisordinotify-tools の知識が必要
  • Dockerfilesupervisord のconfigや自前スクリプトのメンテナンスが発生

sync+restart での自動再起動

メリット:

  • compose.yml に数行追加するだけで実現
  • Docker Composeの標準機能のみで完結
  • 自前のスクリプトやツールが不要
  • 文法エラーがあればコンテナが起動しないため、問題にすぐ気づける

デメリット:

  • 毎回コンテナがフルリスタートするため、ダウンタイムが発生
  • 開発中のテスト接続などが切れる可能性がある
  • あくまでローカル開発専用の仕組み

以上のことからローカル開発環境で使うだけなら、sync+restart で十分だと思います。
シンプルな方が後々のメンテナンスも楽ですしね。
私は思い付かないのですが、特殊な環境下であれば、自前で Dockerfile などを用意してダウンタイムを極力避ける今回の手法も、有効な場合があるかもしれません。

まぁこういうやり方も実はありますよ…という事でひとつ…。

脚注
  1. https://gitlab.alpinelinux.org/alpine/aports/-/issues/17391 ↩︎

SKIYAKI Tech Blog

Discussion