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

Golang hashicorp/serf库Docker Compose环境下连接故障排查

Docker Compose环境下Serf服务发现容器内外节点无法互通的问题解决

问题背景

我有一组基于Golang的服务,使用Serf实现服务发现。本地运行时服务间可正常发现并加入集群,但在Docker Compose环境中,容器外的服务无法加入容器内的集群,服务发现失败。


相关代码与配置

初始启动Serf进程代码

func startSD() {
    addr := "127.0.0.1:50055"
    h := &SDHandler{}
    var err error
    mems, err = discovery.New(h, discovery.Config{
        NodeName:       fmt.Sprintf("sd-%s", addr),
        BindAddr:       addr,
        StartJoinAddrs: []string{},
    })
    if err != nil {
        log.Fatalln(err)
    }
}

Serf节点配置代码

func (m *Membership) setupSerf() (err error) {
    addr, err := net.ResolveTCPAddr("tcp", m.BindAddr)
    if err != nil {
        return err
    }

    config := serf.DefaultConfig()
    config.Init()
    config.MemberlistConfig.BindAddr = addr.IP.String()
    config.MemberlistConfig.BindPort = addr.Port

    m.events = make(chan serf.Event)

    config.EventCh = m.events
    config.Tags = m.Tags
    config.NodeName = m.Config.NodeName

    m.serf, err = serf.Create(config)
    if err != nil {
        return err
    }

    go m.eventHandler()

    if m.StartJoinAddrs != nil {
        _, err = m.serf.Join(m.StartJoinAddrs, true)
        if err != nil {
            return err
        }
    }

    return nil
}

Docker Compose配置

version: "3.9"
services:

  media-api:
    build:
      context: .
      dockerfile: Dockerfile
    ports:
      - "50050:50050"
      - "50055:50055"
      - "50055:50055/udp"

初始错误信息

[DEBUG] memberlist: Failed to join 127.0.0.1:50055: EOF


更新后的问题

将BindAddr修改为:50055后,节点加入集群几秒就退出,报错:

2023/05/31 14:54:47 [ERR] memberlist: Failed to send gossip to [::]:50055: write udp 127.0.0.1:50051->[::]:50055: address ::: non-IPv4 address
2023/05/31 14:54:48 [ERR] memberlist: Failed to send UDP ping: write udp 127.0.0.1:50051->[::]:50055: address ::: non-IPv4 address
2023/05/31 14:54:49 [WARN] memberlist: Was able to connect to f34f34g34g34gerg over TCP but UDP probes failed, network may be misconfigured
2023/05/31 14:54:50 [ERR] memberlist: Failed to send UDP ping: write udp 127.0.0.1:50051->[::]:50055: address ::: non-IPv4 address


问题根源与解决方案

问题分析

  1. 初始配置BindAddr: "127.0.0.1:50055"让Serf仅绑定容器内回环地址,容器外服务无法访问该端口,导致连接失败。
  2. 修改为:50055后,Serf默认绑定所有网络接口(含IPv6),但容器内外UDP通信在IPv4环境下出现协议不兼容,节点被集群踢除。

解决步骤

1. 绑定所有IPv4接口

修改启动代码中的BindAddr为0.0.0.0:50055,明确指定绑定所有IPv4接口,避免IPv6干扰:

func startSD() {
    addr := "0.0.0.0:50055"
    h := &SDHandler{}
    var err error
    mems, err = discovery.New(h, discovery.Config{
        NodeName:       fmt.Sprintf("sd-%s", addr),
        BindAddr:       addr,
        StartJoinAddrs: []string{},
    })
    if err != nil {
        log.Fatalln(err)
    }
}

2. 强制Serf使用IPv4协议

在setupSerf函数中添加禁用IPv6的配置,确保UDP通信仅使用IPv4:

func (m *Membership) setupSerf() (err error) {
    addr, err := net.ResolveTCPAddr("tcp", m.BindAddr)
    if err != nil {
        return err
    }

    config := serf.DefaultConfig()
    config.Init()
    config.MemberlistConfig.BindAddr = addr.IP.String()
    config.MemberlistConfig.BindPort = addr.Port
    // 禁用IPv6,强制使用IPv4
    config.MemberlistConfig.DisableIPv6 = true
    // 仅允许IPv4节点加入
    config.MemberlistConfig.AllowAllIPv4 = true

    m.events = make(chan serf.Event)

    config.EventCh = m.events
    config.Tags = m.Tags
    config.NodeName = m.Config.NodeName

    m.serf, err = serf.Create(config)
    if err != nil {
        return err
    }

    go m.eventHandler()

    if m.StartJoinAddrs != nil {
        _, err = m.serf.Join(m.StartJoinAddrs, true)
        if err != nil {
            return err
        }
    }

    return nil
}

3. 容器外节点使用宿主机IP加入集群

容器内Serf通过端口映射暴露后,容器外节点需使用宿主机实际IP(而非127.0.0.1,跨机器时需用宿主机局域网IP)加入集群:

// 容器外服务启动代码示例,替换为实际宿主机IP
StartJoinAddrs: []string{"192.168.1.100:50055"},

验证要点

  • 确认Docker Compose已正确映射TCP和UDP的50055端口(当前配置已满足)。
  • 检查宿主机防火墙是否放行50055端口的TCP和UDP流量。
  • 确保容器内外节点网络互通,容器外节点可ping通宿主机IP。

内容的提问来源于stack exchange,提问作者Alexander Z.

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 15:32:20