DockerコンテナとしてWebアプリケーションを動かしてNginxをリバースプロキシとして利用する場合, docker-gen や nginx-proxy で設定を自動化していることが多いと思います.
バーチャルホストの設定を自動的に生成できて便利ですが,Nginxがコンテナではなくホスト環境で動作していると設定の更新が煩雑になりがちで悩ましいです.Nginxもコンテナ化してしまうのも手ですが,歴史的経緯や外的要因で既に動いているNginxをそのまま使いたい場合もあります.
暫定の解決方法
コンテナとして起動したdocker-genでNginxの設定ファイルを生成して,ホストのNginxに読み込ませます.
Docker と Nginx と docker-gen の使い方についてはこの文書では触れません.
docker-genでコンテナを監視し,設定をファイルを生成して,NginxのプロセスにSIGHUPを送るだけで良さそうです.(Nginxのドキュメントを見る限り nginx -s reload
は kill -HUP
相当です)
dokcer-genに渡す必要があるもの:
- /var/run/docker.sock (ReadOnly)
- /var/run/nginx.pid (ReadOnly)
- /etc/nginx/conf.d/ (Read/Write)
NginxにSIGHUPを送るために,ホストのPIDと/var/run/nginx.pidにアクセスする必要があるので,--pid=host
必須な上,nginx.pid
はファイルが再作成される可能性があるので,ファイル自体ではなく /var/run
をコンテナに渡す必要があります.nginx.pidを別のディレクトリ移動すればマシになりますが,ホストのNginxはあまり触らない方針.
そもそも論から言えば,docker.sockを渡すのも嫌な感じがしますが,これはdocker-genを使う以上仕方なさそうです.
docker-gen用のテンプレートとdocker image
nginx.tmpl
は SynologyのNASを買ったら最初からインストールされてたNginxに80番と443番ポートが握られてて困って書いたやつですが,他の環境でも使えるはずです.
docker run -d --restart=always --name nginx-conf-gen \
--pid=host \
-v /var/run:/tmp/run:ro \
-v /etc/nginx/conf.d:/tmp/dst \
binzume/nginx-conf-gen
使い方はnginx-proxyに入ってるテンプレートと似た感じですが,HTTP_PATH, HTTP_PROXY_PATH環境変数で同じバーチャルホストで複数アプリケーションを動かせます.
サンプル出力
docker run -d --name app01_instance01 -p :8080 -e VIRTUAL_HOST=example.com -e HTTP_PATH=/app01/ -e HTTP_PROXY_PATH=/ mendhak/http-https-echo
docker run -d --name app01_instance02 -p :8080 -e VIRTUAL_HOST=example.com -e HTTP_PATH=/app01/ -e HTTP_PROXY_PATH=/ mendhak/http-https-echo
docker run -d --name app02 -p :8080 -e VIRTUAL_HOST=example.com -e HTTP_PATH=/app02/ -e HTTP_PROXY_PATH=/ mendhak/http-https-echo
こんな感じで色々起動すると,以下のようなconfが生成されます.-p
で指定するホスト側のポートは省略して自動的に割り当てて大丈夫です.
upstream example.com.app02. {
server 0.0.0.0:32780; # app02
}
upstream example.com.app01. {
server 0.0.0.0:32779; # app01_instance02
server 0.0.0.0:32778; # app01_instance01
}
server {
gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript;
proxy_buffering off;
server_name example.com;
listen 80;
listen [::]:80;
listen 443 ssl;
listen [::]:443 ssl;
include /etc/nginx/default.d/*.conf;
include /etc/nginx/sites-customizations/example.com.*.conf;
location /app02/ {
proxy_pass http://example.com.app02./;
proxy_http_version 1.1;
proxy_read_timeout 3600s;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Connection "";
}
location /app01/ {
proxy_pass http://example.com.app01./;
proxy_http_version 1.1;
proxy_read_timeout 3600s;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Connection "";
}
}
default.d
とsites-customizations
下のconfも存在すればincludeするようにして追加の設定を置いたりしています.nginx-conf-gen起動時に -e HTTP_MODE=redirect
を付けるとHTTPをHTTPSにリダイレクトしたりします.
最後に
色々悩ましいので,ベストプラクティス的なものがあれば知りたいです.