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") } } } }
尝试过程及异常
- 使用
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)
- 使用容器名称
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指向自身容器,而非宿主机或其他容器,因此会访问失败。 - 同一网络下,使用容器名称或服务名称作为主机地址:
若使用同一docker-compose且修改了服务名,也可使用服务名:val adminUrl = "http://projectB-service-container:8083/get-admin-token"val adminUrl = "http://projectB-service:8083/get-admin-token"
内容的提问来源于stack exchange,提问作者sarah w
相关产品推荐
相关产品推荐

