どうしてもDockerコンテナ間をlocalhost:xxxxで通信したい
結論
リバースプロキシを通しました
経緯
docker composeでwebアプリケーションが2つ起動する環境を構築しました
それぞれApp1, App2とします
App1はlocalhost:8080, App2はlocalhost:8081でアクセスできます
App1からApp2が提供するAPIをリクエストします
また、App1を開いている時にApp2へのリダイレクトが発生します
services:
app1:
ports:
- 8080:80
app2:
ports:
- 8081:80
App1からApp2へのAPI通信
App2のAPIエンドポイント/api/test
をApp1からリクエストするためには
localhost:8081/api/test では出来ません。
同じネットワーク内なのでURIをApp2/api/test
としたり、
ホスト側にポートを公開してるので host.docker.internal:8081/api/test
にリクエストする必要があります
App2へのリダイレクト
ホストマシンからみたApp2はlocalhost:8081です
App2でもhost.docker.internal:8081でも繋がりません
App1がURIを使い分けたらよいけども
できればAPIとwebブラウザからアクセスするURIは同じものに統一したいです
解決策
App1がlocalhost:8081にアクセスしたらhost.docker.internal:8081にポートフォーワーディングできればよさそう
nginxで解決
App1のコンテナ内にwebサーバ(nginx)が同居してる環境であれば、nginxのリバースプロキシを使うことで解決できそうでした
(省略)
server {
listen 8081;
server_name localhost;
location / {
proxy_pass http://host.docker.internal:8081;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
socatで解決
今回扱った環境ではApp1はApp1のnginxとApp1のアプリケーション(PHP)にコンテナが分かれていたため、nginxのリバースプロキシは使えませんでした。
そこでsocatをインストールすることにしました
alpine linuxなのでapkコマンドでインストール(ubuntuならapt install socat
ですね)
apk add socat
以下をコンテナ起動時に実行
socat TCP-LISTEN:8081,fork TCP:host.docker.internal:8081
これでlocalhostによる通信が出来ました
脚注
通常、こんなことが必要なケースは滅多にないかと思います
このケースでは、独自のOAuthサーバ、クライアントを開発する環境を作ることになり、
OAuthライブラリは改造せずに使いたいという理由があったので発生しました
(OAuthサーバにlocalhostを設定すると、ログイン時のリダイレクトもアクセストークン取得APIもlocalhostが使われてしまい分けることが出来なかった)
Discussion