Docker/Symfony/Reactjs/Keycloak:如何使用分离的 docker-compose 文件从一个容器向另一个容器发出 HTTP 请求?

Posted

技术标签:

【中文标题】Docker/Symfony/Reactjs/Keycloak:如何使用分离的 docker-compose 文件从一个容器向另一个容器发出 HTTP 请求?【英文标题】:Docker/Symfony/Reactjs/Keycloak : How to make an HTTP request from a container to another with separated docker-compose files? 【发布时间】:2021-09-21 04:22:23 【问题描述】:

我有 3 个服务:我在 Symfony 中的后端(Backoffice 和 Api)、我在 Reactjs 中的前端应用程序以及用于 SSO 身份验证的 Keycloak 服务。

我想为我的后台和前端应用使用 Keycloak 身份验证。

我有 3 个单独的 docker-compose 文件:

我的后端 docker-compose 文件:

version: "3.3"
services:
  web:
    container_name: web_app
    build:
      context: ./.docker/web
    ports:
      - 8000:80
    volumes:
      - .:/var/www/backend
    working_dir: /var/www/backend
    depends_on:
      - mysql

  mysql:
    container_name: mysql_app
    image: mysql:5.7
    command: mysqld --sql_mode=NO_ENGINE_SUBSTITUTION --character-set-server=utf8 --collation-server=utf8_general_ci --skip-character-set-client-handshake
    restart: on-failure
    ports:
      - 3307:3306
    volumes:
      - mysql_data:/var/lib/mysql
    environment:
      MYSQL_ROOT_PASSWORD: root
      MYSQL_DATABASE: app

  phpmyadmin:
    container_name: phpmyadmin_app
    image: phpmyadmin/phpmyadmin
    ports:
      - 8001:80
    environment:
      PMA_HOST: mysql
      PMA_USER: root
      PMA_PASSWORD: root
    depends_on:
      - mysql

volumes:
  mysql_data:
    driver: local

networks:
  default:
    external:
      name: app-network

我的前端 docker-compose 文件:

version: "3.3"
services:
  nodejs:
    container_name: nodejs_app
    image: "node:10"
    ports:
      - 3001:3000
    user: "node"
    environment:
      - NODE_ENV=development
    volumes:
      - .:/usr/src/frontend
    working_dir: /usr/src/frontend
    command: >
      sh -c "npm install && npm start"

networks:
  default:
    external:
      name: app-network

我的 Keycloak docker-compose 文件:

version: "3.3"
services:
  keycloak_mysql:
    image: mysql:5.7
    volumes:
      - keycloak_data:/var/lib/mysql
    ports:
      - 3308:3306
    environment:
      MYSQL_ROOT_PASSWORD: root
      MYSQL_DATABASE: keycloak
  keycloak:
    image: quay.io/keycloak/keycloak:latest
    environment:
      DB_VENDOR: MYSQL
      DB_ADDR: keycloak_mysql
      DB_DATABASE: keycloak
      DB_USER: root
      DB_PASSWORD: root
      KEYCLOAK_USER: admin
      KEYCLOAK_PASSWORD: admin
    ports:
      - 8080:8080
    depends_on:
      - keycloak_mysql

volumes:
  keycloak_data:
    driver: local

networks:
  default:
    external:
      name: app-network

我的后端 .env 文件:

OAUTH_KEYCLOAK_SERVER_URL=http://localhost:8080/auth
OAUTH_KEYCLOAK_CLIENT_ID=app
OAUTH_KEYCLOAK_CLIENT_SECRET=
OAUTH_KEYCLOAK_REALMS=app

然后使用以下命令创建一个网络:docker network create app-network

首先,当我尝试在后台进行身份验证时,我被重定向到 Keycloak 登录页面。 然后,在输入我的凭据后,我被重定向回我的后台,并出现以下错误:

cURL error 7: Failed to connect to localhost port 8080: Connection refused (see https://curl.haxx.se/libcurl/c/libcurl-errors.html) for http://localhost:8080/auth/realms/app/protocol/openid-connect/token

我对 docker 和网络不是很熟悉。

我该如何解决这个问题?


更新 1:

现在我已经在我的网络中添加了一个子网:docker network create --subnet 172.23.0.0/24 app-network

并向我的容器添加静态 IP:

services:
  # Backend docker-compose file
  web:
    networks:
      default:
        ipv4_address: 172.23.0.11
    ...
    ...
  mysql:
    networks:
      default:
        ipv4_address: 172.23.0.15
    ...
    ...
  phpmyadmin:
    networks:
      default:
        ipv4_address: 172.23.0.14

  # Frontend docker-compose file
  nodejs:
    networks:
      default:
        ipv4_address: 172.23.0.12

  # Keycloak docker-compose file
  keycloak_mysql:
    networks:
      default:
        ipv4_address: 172.23.0.16
    ...
    ...
  keycloak:
    networks:
      default:
        ipv4_address: 172.23.0.13

下面的命令:docker network inspect app-network 给了我:

[
    
        "Name": "app-network",
        "Id": "31984c890cfbf8206dacf18dd3e831c45cb133ab5391b45edf609cd2232eaffa",
        "Created": "2021-07-14T12:19:07.6486215Z",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": 
            "Driver": "default",
            "Options": ,
            "Config": [
                
                    "Subnet": "172.23.0.0/24"
                
            ]
        ,
        "Internal": false,
        "Attachable": false,
        "Ingress": false,
        "ConfigFrom": 
            "Network": ""
        ,
        "ConfigOnly": false,
        "Containers": 
            "14ab20cf0c5517d9ec9b9d136d65bc07e847d154364ab831a7825c913943a768": 
                "Name": "phpmyadmin",
                "EndpointID": "81d31a65c37e121dbb4948e933e8edf37213612e9b3f6eb4ac66e4a0443a0117",
                "MacAddress": "02:42:ac:17:00:0e",
                "IPv4Address": "172.23.0.14/24",
                "IPv6Address": ""
            ,
            "1cec44b30b8f942803d1bc3525ba5875d73f7253fbac021c67bf76ebf4488f7c": 
                "Name": "web",
                "EndpointID": "9a58e55dd679585af744af01b69d21eb94995a54ead0d24a5fe64e306c599452",
                "MacAddress": "02:42:ac:17:00:0b",
                "IPv4Address": "172.23.0.11/24",
                "IPv6Address": ""
            ,
            "21f54bb4a453e701f1628b4c5e122d3a1e32411608603d193bd5787e2ff1ac38": 
                "Name": "nodejs",
                "EndpointID": "3272a80565ea0ff627c947635c04f5ad8fa47d1822db62e3e0d5f9052270d062",
                "MacAddress": "02:42:ac:17:00:0c",
                "IPv4Address": "172.23.0.12/24",
                "IPv6Address": ""
            ,
            "7d0a8dec8ff6baac31e208c5ccea6fca6954d088a87b884ddd96c95d1c6a2930": 
                "Name": "keycloak_mysql_1",
                "EndpointID": "2517e766e4af674185c4d8612c5e169e6e12ab4658497dfe95cd08ba3d3f6153",
                "MacAddress": "02:42:ac:17:00:10",
                "IPv4Address": "172.23.0.16/24",
                "IPv6Address": ""
            ,
            "822abcc2e5b7e2231f08534050618bc4842405a0f7a287274b9240c291ce87e3": 
                "Name": "mysql",
                "EndpointID": "5b3f47483495e48d0026c84dffe86d4cecd529b9f87ca0d40902280cca01be86",
                "MacAddress": "02:42:ac:17:00:0f",
                "IPv4Address": "172.23.0.15/24",
                "IPv6Address": ""
            ,
            "998210a92b66d1342c9df35b30e341f7631c62604f6b7d0d0d3ac128d2c78420": 
                "Name": "keycloak_1",
                "EndpointID": "3e7e346a159593e4863abd7bc20d2b7f398a6fd2763981b2584ecc02d325c92e",
                "MacAddress": "02:42:ac:17:00:0d",
                "IPv4Address": "172.23.0.13/24",
                "IPv6Address": ""
            
        ,
        "Options": ,
        "Labels": 
    
]

我可以通过以下方式访问我的web 容器中的keycloak 容器: curl http://keycloak:8080curl http://172.23.0.13:8080

所以我已将我的后端 .env 文件更新为:OAUTH_KEYCLOAK_SERVER_URL=http://keycloak:8080/auth

但是当重定向发生时,我的浏览器无法识别http://keycloak:8080 url。

在我的浏览器上,我只能访问:

My backend: http://localhost:8000
My frontend: http://localhost:3001
My keycloak: http://localhost:8080

是否也可以通过 Ips 从主机访问我的容器?


解决方案:

我编辑了我的/etc/hosts 并添加了:

127.0.0.1 keycloak
127.0.0.1 web
127.0.0.1 nodejs

现在一切正常

【问题讨论】:

你试过没有在每个 docker-compose.yml 文件的全局网络语句中使用 'default' 关键字吗? 我有同样的错误。 【参考方案1】:

默认情况下,docker-compose 创建的容器都有自己的网络命名空间 - 即他们自己的(虚拟)网络接口和他们自己的 IP 地址 - 因此尝试从应用容器连接到 http://localhost:8080/ 将无法连接到Keycloak 容器,但应用程序容器本身。

要连接到 Keycloak 容器,您需要使用映射 / 被转发到 Keycloak 容器的主机名/IP。由于所有容器都连接到app-network,因此您可以使用容器名称:

OAUTH_KEYCLOAK_SERVER_URL=http://keycloak:8080/auth

请参阅docker-compose networking docs 了解更多信息。 (简短的说明:您无需在主机上公开 mysql 容器的端口,以便应用容器能够连接)

如果使用相同的基本 url 来重定向您的浏览器,请确保使用可以从运行浏览器的主机解析的主机/IP,例如然后将相应端口转发到正确容器的主机本身的主机名。

【讨论】:

感谢您的回答。我已经更新了我的帖子。【参考方案2】:

从您的后端的角度来看(或从这个上下文中的所有其他容器)localhost 是容器本身。因此,如果您想在主机上使用端口转发,则必须使用网桥 IP 地址。

应该类似于172.17.0.1

因此您的配置将显示为:OAUTH_KEYCLOAK_SERVER_URL=http://172.17.0.1:8080/auth

【讨论】:

感谢您的回答。我已经更新了我的帖子。

以上是关于Docker/Symfony/Reactjs/Keycloak:如何使用分离的 docker-compose 文件从一个容器向另一个容器发出 HTTP 请求?的主要内容,如果未能解决你的问题,请参考以下文章