Docker化Go客户端无法连接Liftbridge服务求助
Docker化的Go应用使用go-liftbridge客户端,DNS解析正常,也明确传入了解析后的IP和端口,但客户端始终尝试连接[::1]:9292,无法连接Liftbridge服务。
环境信息
- Liftbridge版本: v1.9.0
- Go Liftbridge客户端版本: v2.3.0
- Go版本: 1.22
- 操作系统: Pop!_OS 22.04 LTS x86_64
- Docker版本: v26.0.1
- Docker Compose版本: v2.26.1
复现步骤
- 将使用
go-liftbridge客户端的简单Go应用Docker化。 - 用Docker Compose管理Liftbridge服务和Go应用。
- 尝试通过Docker Compose内的服务主机名解析出的IP连接Liftbridge服务。
即使硬编码IP地址,客户端仍会尝试连接[::1]。
预期行为
客户端应使用指定的IP和端口连接Liftbridge服务。
实际行为
客户端忽略提供的IP和端口,尝试连接[::1]:9292,导致连接拒绝错误。
Docker Compose配置
services: nats: image: nats:latest ports: - "4222:4222" - "6222:6222" - "8222:8222" liftbridge: image: liftbridge/liftbridge:latest command: - "--raft-bootstrap-seed" - "--nats-servers=nats://nats:4222" - "--data-dir=/tmp/liftbridge/" ports: - "9292:9292" depends_on: - nats volumes: - ./liftbridge-data:/tmp/liftbridge go-liftbridge-spark-connector: image: go-liftbridge-spark-connector-img-no-tcp depends_on: - liftbridge command: ["-liftbridgeIP", "liftbridge", "-liftbridgePort", "9292"]
Go应用代码
package main import ( "flag" "log" "net" "time" lift "github.com/liftbridge-io/go-liftbridge/v2" ) type config struct { liftbridgeIP string liftbridgePort string } func main() { var cfg config flag.StringVar(&cfg.liftbridgeIP, "liftbridgeIP", "localhost", "Liftbridge IP address") flag.StringVar(&cfg.liftbridgePort, "liftbridgePort", "9292", "Liftbridge Port") flag.Parse() time.Sleep(5 * time.Second) addrs, err := net.LookupHost(cfg.liftbridgeIP) if err != nil { log.Fatalf("Failed to resolve host: %v", err) } log.Printf("Resolved liftbridge to: %v", addrs) address := addrs[0] + ":" + cfg.liftbridgePort log.Printf("Connecting to Liftbridge server at %s", address) client, err := connectLiftbridgeWithRetry([]string{address}, 10, 2*time.Second) if err != nil { log.Fatalf("Failed to connect to Liftbridge server: %v", err) } defer client.Close() select {} } func connectLiftbridgeWithRetry(addresses []string, maxRetries int, delay time.Duration) (lift.Client, error) { var client lift.Client var err error for i := 0; i < maxRetries; i++ { log.Printf("Attempt %d to connect to Liftbridge at addresses: %v", i+1, addresses) client, err = lift.Connect(addresses) if err == nil { return client, nil } log.Printf("Failed to connect to Liftbridge (%d/%d): %v", i+1, maxRetries, err) time.Sleep(delay) } return nil, err }
观测到的行为
go-liftbridge-spark-connector-1 | 2024/05/14 07:48:24 Resolved liftbridge to: [172.27.0.3] go-liftbridge-spark-connector-1 | 2024/05/14 07:48:24 Connecting to Liftbridge server at liftbridge:9292 go-liftbridge-spark-connector-1 | 2024/05/14 07:48:24 Attempt 1 to connect to Liftbridge at addresses: [liftbridge:9292] go-liftbridge-spark-connector-1 | 2024/05/14 07:48:24 Failed to connect to Liftbridge (1/5): rpc error: code = Unavailable desc = connection error: desc = "transport: Error while dialing dial tcp [::1]:9292: connect: connection refused"
后续尝试均因同一错误失败。
已尝试的操作
- 网络连通性验证: 在Go容器内用
nc确认可解析并连接Liftbridge容器:nc -zv liftbridge 9292 Connection to liftbridge (172.27.0.3) 9292 port [tcp/*] succeeded! - Docker Compose配置检查: 确认所有服务在同一网络,服务名正确。
- 简化Go代码: 将应用简化为仅连接Liftbridge并记录结果。
核心原因
Liftbridge默认会把自身的RPC监听地址设为localhost:9292(即IPv6回环地址[::1]:9292)。客户端发起连接后,Liftbridge会将这个内部监听地址返回给客户端,导致客户端直接尝试连接回环地址,而非容器间可访问的服务地址。
具体修复步骤
修改Liftbridge启动命令,添加
--rpc-advertise参数,指定容器间可访问的服务名或IP:
在Docker Compose的liftbridge服务command中加入:- "--rpc-advertise=liftbridge:9292"修改后的完整
liftbridge服务配置:liftbridge: image: liftbridge/liftbridge:latest command: - "--raft-bootstrap-seed" - "--nats-servers=nats://nats:4222" - "--data-dir=/tmp/liftbridge/" - "--rpc-advertise=liftbridge:9292" ports: - "9292:9292" depends_on: - nats volumes: - ./liftbridge-data:/tmp/liftbridge该参数的作用是让Liftbridge向客户端返回对外暴露的RPC地址,而非内部回环地址。
可选:添加
--rpc-listen参数(确保监听所有接口):
如果需要强制Liftbridge监听所有网络接口,可同时添加:- "--rpc-listen=0.0.0.0:9292"注:默认情况下Liftbridge已监听
0.0.0.0:9292,此参数为兼容性补充。重启服务:
执行docker-compose down后再docker-compose up -d,让配置生效。
验证
修改后,Go客户端连接时会收到Liftbridge返回的liftbridge:9292地址,而非回环地址,即可正常建立连接。
内容的提问来源于stack exchange,提问作者M Umer Masood

