在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網絡進行連接。

    1. 在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的配置文件可以轻松地更改端口号,所以可以视为好的方案。

广告
将在 10 秒后关闭
bannerAds