在Docker容器内无法通过主机访问其他容器
在这个世界上,有太多需要记住才能成功的事情。因此,我喜欢先尝试然后再深入探索的方法,而不是等到记住所有东西之后才开始。我认为马多卡妈妈的”学会优雅地摔倒”是至理名言。
所以,我正在使用Keycloak开发一个进行身份验证的Web应用程序,经过验证后,当我尝试在验证环境中运行时,Web应用程序启动失败了。
-
- Keycloakサーバは、検証環境でdocker-composeを使って構築。
Webアプリは、バックエンドをSpring Boot、フロントエンドをAngularで開発。
Angularアプリではkeycloak-angularを使用。
Spring Bootアプリはリソースサーバとして動作するのでspring-boot-starter-oauth2-resource-serverを使い、Angularアプリから送られてきたトークンを検証。
開発中は、検証環境のKeycloakサーバに接続して動作を確認。
Webアプリをコンテナにして、検証環境のKeycloakサーバと同じホストのDocker上で起動すると、Spring BootアプリからKeycloakサーバへの経路がない(no route to host)とのエラーで終了していた。
首先尝试的事情
因此,我將Keycloak容器和Web應用程式容器加入到同一個Docker網絡中,並嘗試通過Spring Boot應用程式通過Docker網絡進行連接。
-
- 在docker中创建一个名为${网络名称}的网络。
- 在Keycloak和Web应用程序的docker-compose.yml文件中,将它们设置为加入上述网络。
version: '3'
services:
app:
build:
context: .
container_name: app
ports:
- 50010:8080
networks:
- ${ネットワーク名}
networks:
${ネットワーク名}:
external: true
spring:
security:
oauth2:
resourceserver:
jwt:
issuer-uri: http://${keycloakコンテナ名}.${ネットワーク名}:8080/auth/realms/${レルム名}
现在,Spring Boot应用可以成功与Keycloak服务器进行通信,并正常启动。然而,当在Angular应用中进行登录时,尽管登录到Keycloak服务器成功,但之后在Angular应用中通过Ajax与Spring Boot应用进行通信时,出现了401 Unauthorized的错误。
当在浏览器中查看响应时,可以看到以下信息在头部。
WWW-Authenticate: Bearer error="invalid_token",
error_description="This iss claim is not equal to the configured issuer",
error_uri="https://tools.ietf.org/html/rfc6750#section-3.1"
据说Angular应用程序和Spring Boot应用程序访问Keycloak服务器的URL不匹配。
因此,我们确实需要通过外部网络从Docker容器内部进行访问。
根本原因
所以我从网络上搜集信息,发现Docker进行了iptables的配置,这样通信可能会受到限制。
我参考了这篇文章,学习了iptables的使用方法。
虽然还没有完全理解,但当我尝试追踪从本地主机发送数据包的链路时,发现…
# iptables -t nat -nvL POSTROUTING
Chain POSTROUTING (policy ACCEPT 12 packets, 853 bytes)
pkts bytes target prot opt in out source destination
0 0 MASQUERADE all -- * !docker0 172.17.0.0/16 0.0.0.0/0
※あとは割愛
我认为默认情况下,无法将来自Docker容器分配的172.17.0.0/16地址的通信返回到docker0桥接上。
避免策略
由于对iptables的理解有限,所以决定让Web应用的Docker容器使用host驱动程序而不是默认的bridge驱动程序。
version: '3'
services:
app:
build:
context: .
container_name: app
network_mode: host # 追加
# ポートマッピングは使えなくなるので削除
# ports:
# - 50010:8080
由于这样做,容器内部使用的端口会直接被主机使用,但是由于Spring Boot的配置文件可以轻松地更改端口号,所以可以视为好的方案。