Dockerのnginxコンテナは/etc/hostsを参照しないためhost.docker.internalを名前解決できない

nginxコンテナでhost.docker.internalを利用しようとした際に一生名前解決ができなくて困った件を書きます。

TL;DR

nginxは/etc/hostsを参照しないので/etc/hostsに記載されても名前解決できない

172.17.0.1   host.docker.internal

そのためhostネットワークに接続して利用するか、172.17.0.1のようなすでに解決されたIPをハードコードするなどが必要

やりたかったこと

nginxのコンテナをリバースプロキシとして利用していました。 example.comへアクセスがあればcompose.ymlで定義したfrontへ example.com/api/へアクセスがあれば、ホストで別途立ち上げているサービスへ

という風に流してあげる必要があったので、host.docker.internalを使って「dockerを動かしているホストのネットワークの8000に」という意味でproxy_pass http://host.docker.internal:8000;と記載しました。

server {
    listen 80;
    server_name example.com;

    location / {
        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_pass http://front;
        }
    location /api/ {
        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_pass http://host.docker.internal:8000;
        }
}

すると何故か名前解決ができなかったので困っていました。

そもそもLinuxでhost.docker.internalを使うには設定する必要があったりとヒントを得て、試してみましたがこれもだめ。

extra_hosts:
      - "host.docker.internal:host-gateway"

いろいろ試してもだめだったんですが、githubのissueを見ていると「nginxは/etc/hostsを見てない」というコメントが多数ありました。

ということで調べて見ると本当に見ていないようで、/etc/hostsを見るようにするにはdnsmasqというものを別途立ち上げる必要があるみたいです。

解決

名前解決ができないだけでhost.docker.internalが使えないわけではないので、起動後に/etc/hostsを見て割り当てられるIPを確認して以下のようにハードコードしました。 割り当てるIPはDockerの設定で固定にすることもできるのでこのような実装でも問題ないっぽい。

proxy_pass http://host.docker.internal:8000; # x

proxy_pass http://172.17.0.1:8000; # o

おしまい