はじめに
- Dockerで外部に公開する時、以下のようにnginxのリバースプロキシサーバのみを公開させ、FQDNでそれぞれのDockerコンテナにproxyしている。
- それぞれのDockerコンテナ(compose)は必ず同一のDockerネットワーク上に置く。
- そうするとglobal IPは1つでよく、それぞれのコンテナ内のポートも443や80を固定にして使用できる。
- 公開reverse proxy以外は公開しなくてもよいので、セキュリティも高くなる。
Dockerの名前解決の仕組み
- Docker内部では組み込みDNSサーバ(127.0.0.11)があり、内部ではIPを意識しなくてもコンテナ名でアクセスできる。
reverse proxyの設定
reverse proxyのnginx.confのserverディレクティブの部分
nginx.conf
# 1) Backend railsコンテナ側のngixnにproxy
server {
listen 80;
server_name xxx.hoge.com;
location / {
proxy_set_header X-Forwarded-for $remote_addr;
proxy_set_header Host $host;
proxy_pass http://xxx-nginx/;
}
}
# 2) Backend Flaskコンテナ側のngixnにproxy
server {
listen 80;
server_name yyy.hoge.com;
location / {
proxy_set_header X-Forwarded-for $remote_addr;
proxy_set_header Host $host;
proxy_pass http://yyy-nginx/;
}
}
本題
やっと本題。
この構成において、railsコンテナを再起動すると、Docker内部のIPが変わってしまう。
そのため、フロントのreverse proxyを再起動させる必要がある。
これだと、関係のないFlaskコンテナにも影響が出てしまい、運用上まずい。
reverse proxyは起動時にしかDNSを参照しないため、proxy先のコンテナのIPが変わったら再起動するしかない。
解決方法
reverse proxyにDocker内部のDNSを定期的に参照するようにする。
resolverに127.0.0.11 valid=10sの設定をすれば、10秒ごとに参照するようになる。
serverディレクティブも変数で設定。
ただし、”http://xxx-nginx;"のように最後にスラッシュを入れないこと。
nginx.conf
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
# 以下のようにすることで、Dockerの内部DNSに10秒ごとに問い合わせ
resolver 127.0.0.11 valid=10s ipv6=off;
....
}
server {
listen 80;
server_name xxx.hoge.com;
location / {
proxy_set_header X-Forwarded-for $remote_addr;
proxy_set_header Host $host;
#変数を使うのがポイント。ただしURLの最後に/を入れないこと
set $backend http://xxx-nginx;
proxy_pass $backend;
}
}
server {
listen 80;
server_name yyy.hoge.com;
location / {
proxy_set_header X-Forwarded-for $remote_addr;
proxy_set_header Host $host;
#変数を使うのがポイント。ただしURLの最後に/を入れないこと
set $backend http://yyy-nginx;
proxy_pass $backend;
}
}
おしまい
これでフロントエンドのreverse proxyがDockerの内部DNSを参照するため、バックエンドのコンテナを再起動してもreverse proxyを再起動する必要がなくなる。