You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Docker环境下Akka HTTP服务间路由调用失败问题排查求助

Docker环境下Akka HTTP服务间调用连接失败问题解决

问题背景

我有两个基于Akka HTTP的服务,均通过Docker运行,使用sbt native package生成镜像,端口分别为8085(projectA)和8083(projectB)。需要在projectA中通过Akka HTTP Client调用projectB的路由,但遇到连接异常。

环境配置

projectA的docker-compose配置

akkahttpservice:
    image: projectA-service:0.0.1
    container_name: projectA-service-container
    ports:
      - "8085:8085"

projectB的docker-compose配置

akkahttpservice:
    image: projectB-service:0.0.1
    container_name: projectB-service-container
    ports:
      - "8083:8083"

当前容器运行状态(docker ps输出)

CONTAINER ID   IMAGE                         COMMAND                  CREATED         STATUS          PORTS                                                                                  NAMES
71a58c080e7c   projectA-service:0.0.1   "/opt/docker/bin/not…"   5 minutes ago   Up 5 minutes    8084/tcp, 0.0.0.0:8085->8085/tcp, :::8085->8085/tcp                                    projectA-service-container
c08f5700ce3d   projectB-service:0.0.1          "/opt/docker/bin/int…"   22 hours ago    Up 28 minutes   0.0.0.0:8083->8083/tcp, :::8083->8083/tcp                                              projectB-service-container

代码实现

projectB的目标路由

def getAdminToken: server.Route =
    path("get-admin-token") {
    post {
  entity(as[JsValue]) {
            json =>
              val userName = json.asJsObject.fields("userName").convertTo[String]
              val userPwd = json.asJsObject.fields("userPwd").convertTo[String]
complete("got the details")
        }
   }
}

projectA中的调用代码

def addUserInKeyCloak: server.Route = {
    path("add-user-in-keycloak") {
      post {
        entity(as[NotaryUser]) {
          notaryUser =>
            val adminUrl = "http://0.0.0.0:8083/get-admin-token"
        val jsonStr =
          s"""|{
             |     "userName":"admin",
             |   "userPwd":"admin"
             |  }""".stripMargin
val request = HttpRequest(HttpMethods.POST, adminUrl, Nil, HttpEntity(ContentTypes.`application/json`, jsonStr.stripMargin.parseJson.toString()))
        val responseFuture = Http(context.system).singleRequest(request)
        complete("result from future")
            
        }
      }
    }
  }

尝试过程及异常

  1. 使用http://0.0.0.0:8083/get-admin-token调用时,抛出连接拒绝异常:
Tcp command [Connect(0.0.0.0:8083,None,List(),Some(10 seconds),true)] failed because of java.net.ConnectException: Connection refused (akka.stream.StreamTcpException: Tcp command [Connect(0.0.0.0:8083,None,List(),Some(10 seconds),true)] failed because of java.net.ConnectException: Connection refused)
  1. 使用容器名称http://projectB-service-container:8083/get-admin-token调用时,抛出未知主机异常:
Tcp command [Connect(docker-interpret-auth-container:8083,None,List(),Some(10 seconds),true)] failed because of java.net.UnknownHostException: projectB-service-container (akka.stream.StreamTcpException: Tcp command [Connect(projectB-service-container:8083,None,List(),Some(10 seconds),true)] failed because of java.net.UnknownHostException: projectB-service-container)

说明:本地未使用Docker时代码运行正常,Postman和Curl也能正常访问Docker中的服务。

解决方法

1. 确保两个服务处于同一Docker网络

Docker默认会为每个docker-compose文件创建独立网络,跨网络的容器无法通过名称互相访问。解决方式:

  • 方案一:合并到同一个docker-compose文件
    将两个服务放在同一个docker-compose.yml中,默认网络下即可通过服务名称访问。建议修改服务名避免冲突,示例:

    version: '3.8'
    services:
      projectA-service:
        image: projectA-service:0.0.1
        container_name: projectA-service-container
        ports:
          - "8085:8085"
      projectB-service:
        image: projectB-service:0.0.1
        container_name: projectB-service-container
        ports:
          - "8083:8083"
    

    此时projectA中可使用http://projectB-service:8083/get-admin-token访问。

  • 方案二:加入自定义共享网络
    为两个服务配置同一个自定义网络:
    首先修改projectA的docker-compose.yml:

    version: '3.8'
    services:
      akkahttpservice:
        image: projectA-service:0.0.1
        container_name: projectA-service-container
        ports:
          - "8085:8085"
        networks:
          - akka-shared-net
    networks:
      akka-shared-net:
        driver: bridge
    

    再修改projectB的docker-compose.yml,加入已创建的网络:

    version: '3.8'
    services:
      akkahttpservice:
        image: projectB-service:0.0.1
        container_name: projectB-service-container
        ports:
          - "8083:8083"
        networks:
          - akka-shared-net
    networks:
      akka-shared-net:
        external: true
    

2. 使用正确的访问地址

  • 不能用0.0.0.0:容器内的0.0.0.0指向自身容器,而非宿主机或其他容器,因此会访问失败。
  • 同一网络下,使用容器名称或服务名称作为主机地址:
    val adminUrl = "http://projectB-service-container:8083/get-admin-token"
    
    若使用同一docker-compose且修改了服务名,也可使用服务名:
    val adminUrl = "http://projectB-service:8083/get-admin-token"
    

内容的提问来源于stack exchange,提问作者sarah w

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 00:50:28