igozhang

——

    网段172.27 SSH 不通排查

    ENV

    类别 版本/信息
    主机 主机名 igo-node01
    操作系统 CentOS Linux 7 (Core) 内核 3.10.0-1160.el7.x86_64
    运行时间 uptime 38 weeks+
    生产网卡 bond0 10.10.10.53/24
    SSH sshd 端口 5008,监听 0.0.0.0:5008
    容器 Docker 20.10.17
    容器 Docker Compose v2.12.2
    容器 data-root /data/docker
    容器 default-runtime nvidia
    编排 igo-mineru gpu0 项目名 igo-mineru-gpu0,compose 文件 gpu0-compose.yaml
    业务容器 igo-mineru-api-gpu0 镜像 igo-mineru:latest,端口 8004:8004
    K8s 组件 节点存在 kube-proxy / Calico(cali-* 链、tunl0 等)
    GPU 驱动/运行时 nvidia-container-runtime(daemon.json 配置)

    1. 现象

    • 时间:约近 2 天起
    • 表现:172.27 网段用户 SSH 连接 10.10.10.53:5008 失败(超时/无响应)
    • 影响范围:来自 172.27 网段访问本机 SSH;业务容器 igo-mineru-api-gpu0(8004)本身可运行

    2. 原因

    2.1 结论

    根因是 Docker 网络 igo-mineru-gpu0_default 自动占用 172.27.0.0/16,与生产 172.27 网段路由冲突,导致 SSH 回包走错接口。与 iptables DROP 无关。

    2.2 定位推导过程

    ① 排除 iptables 直接拦截 SSH

    iptables-save | grep 5008
    iptables -L cali-from-host-endpoint -n -v --line-numbers
    iptables -L DOCKER-USER -n -v --line-numbers
    

    关键输出:

    • 无 5008 相关规则
    • cali-from-host-endpoint 为空链
    • DOCKER-USER 为空链
    • INPUT 默认策略 ACCEPT

    判断: 非 INPUT 路径 DROP 导致。

    ② 确认 SYN 到达本机但无 SYN-ACK

    timeout 8 tcpdump -i bond0 -n 'tcp port 5008 and src net 172.27.0.0/16' -c 5
    

    关键输出:

    172.27.100.23.xxxxx > 10.10.10.53.5008: Flags [S] ...
    (仅 SYN 重传,无 SYN-ACK)
    

    判断: 包能进本机,问题在本机处理/回包路径,非上游防火墙。

    ③ 定位回程路由错误

    ip route get 172.27.100.23 from 10.10.10.53
    ip route show | grep 172.27
    

    故障时关键输出:

    172.27.100.23 from 10.10.10.53 dev br-igo-old   # 错误:走 Docker 网桥
    172.27.0.0/16 dev br-igo-old proto kernel scope link src 172.27.0.1
    

    判断: Docker 网桥 br-igo-oldigo-mineru-gpu0_default)抢占了 172.27/16 路由,SYN 从 bond0 进,SYN-ACK 却发往 Docker 网桥。

    ④ 确认冲突网络来源

    docker ps --filter network=igo-mineru-gpu0_default --format '{{.Names}}'
    docker network ls | grep igo-mineru
    

    关键输出:

    • 容器:igo-mineru-api-gpu0
    • 网络:igo-mineru-gpu0_default
    • compose 路径:/opt/igo/igo-mineru/gpu0-compose.yaml原无 networks/subnet 配置

    判断: Docker 在本机已有 172.17–172.26 网络后,自动分配下一段 172.27.0.0/16,与生产网段重叠。

    2.3 问题形成原因推测

    运维/开发人员在 igo-node01 上部署 igo-mineru-api-gpu0(gpu0-compose.yaml)时未指定 Docker 网段;Docker 在已有多个 bridge 网络后自动为 igo-mineru-gpu0_default 分配了 172.27.0.0/16,与生产 172.27 网段冲突,导致来自 172.27 客户端的 SSH 回包被错误路由至 Docker 网桥,连接无法建立。


    3. 方案

    3.1 变更前备份

    BACKUP_TIME=$(date +%Y%m%d%H%M)
    cp -a /etc/docker/daemon.json /etc/docker/daemon.json.bak.${BACKUP_TIME}
    cp -a /opt/igo/igo-mineru/gpu0-compose.yaml /opt/igo/igo-mineru/gpu0-compose.yaml.bak.${BACKUP_TIME}
    echo "backup tag: ${BACKUP_TIME}"
    

    示例 backup tag:202601011200

    3.2 Docker 全局:限制自动分配网段(绕开 172.27)

    文件: /etc/docker/daemon.json

    {
        "data-root": "/data/docker",
        "default-address-pools": [
            {"base": "172.28.0.0/16", "size": 24},
            {"base": "172.29.0.0/16", "size": 24},
            {"base": "172.30.0.0/16", "size": 24},
            {"base": "172.31.0.0/16", "size": 24}
        ],
        "default-runtime": "nvidia",
        "log-driver": "json-file",
        "log-opts": {"max-file": "3", "max-size": "100m"},
        "runtimes": {
            "nvidia": {"args": [], "path": "nvidia-container-runtime"}
        }
    }
    
    python3 -m json.tool /etc/docker/daemon.json > /dev/null && systemctl restart docker
    

    注意: 仅改 daemon.json 不会改变已有网络,须配合删除并重建冲突网络。

    3.3 Compose:显式指定 gpu0 网段

    文件: /opt/igo/igo-mineru/gpu0-compose.yaml 末尾追加:

    networks:
      default:
        ipam:
          config:
            - subnet: 172.30.0.0/16
    

    3.4 重建 gpu0 网络与容器

    必须使用原项目名 -p igo-mineru-gpu0

    docker rm -f igo-mineru-api-gpu0
    docker network rm igo-mineru-gpu0_default igo-mineru0618_default 2>/dev/null
    
    cd /opt/igo/igo-mineru
    docker compose -p igo-mineru-gpu0 -f gpu0-compose.yaml --profile api up -d
    

    3.5 验证

    路由与网络:

    ip route show | grep -E '172\.27|172\.30'
    ip route get 172.27.100.23 from 10.10.10.53
    docker network inspect igo-mineru-gpu0_default --format '{{range .IPAM.Config}}{{.Subnet}}{{end}}'
    

    修复后关键输出:

    172.30.0.0/16 dev br-igo-new ...              # 无 172.27 路由
    172.27.100.23 ... via 10.10.10.254 dev bond0  # 回包走 bond0
    172.30.0.0/16
    

    业务与 SSH:

    curl -sf http://localhost:8004/health && echo OK
    timeout 8 tcpdump -i bond0 -n 'tcp port 5008 and host 172.27.100.23' -c 6
    # 172.27 用户:ssh -p 5008 10.10.10.53
    

    3.6 回退(backup tag: 202601011200

    docker rm -f igo-mineru-api-gpu0 2>/dev/null
    docker network rm igo-mineru-gpu0_default 2>/dev/null
    cp -a /etc/docker/daemon.json.bak.202601011200 /etc/docker/daemon.json
    cp -a /opt/igo/igo-mineru/gpu0-compose.yaml.bak.202601011200 /opt/igo/igo-mineru/gpu0-compose.yaml
    systemctl restart docker
    cd /opt/igo/igo-mineru && docker compose -p igo-mineru-gpu0 -f gpu0-compose.yaml --profile api up -d
    

    回退后可能再次分配到 172.27,SSH 问题可能复现。


    4. 后续预防措施

    1. 所有 compose 文件显式配置 networks.subnet,部署前核对不与生产网段(172.27 等)重叠。

    2. Docker daemon 配置 default-address-pools,新建网络自动避开 172.27。

    3. compose 操作统一带项目名:

      docker compose -p igo-mineru-gpu0 -f gpu0-compose.yaml --profile api <command>
      
    4. 上线前检查:

      ip route show | grep 172.27
      ip route get <生产网段样例IP> from $(ip -4 addr show bond0 | awk '/inet /{print $2}' | cut -d/ -f1)
      
    5. 维护本机 Docker 网络清单,新增 stack 前确认下一自动分配段是否会撞生产网段。


    5. 建议配置参数

    参数 当前值(修复前 → 修复后) 建议值 原因/后果
    gpu0-compose.yaml networks.subnet 未配置(自动 172.27/16)→ 172.30.0.0/16 172.30.0.0/16 未配置时 Docker 顺序分配,易与生产 172.27 冲突
    daemon.json default-address-pools 无 → 172.28–172.31/16 配置多个不含 172.27 的 /16 池 防止未来新建网络再次自动分到 172.27
    compose 项目名 -p 曾误用目录名 igo-mineru0618 -p igo-mineru-gpu0 项目名不一致会导致 down/up 无法管理原容器
    SSH 端口 5008 保持 5008 与排查结论无关
    生产 SSH 目标 IP 应使用 10.10.10.53 不使用 172.27.0.1 172.27.0.1 为 Docker 网桥网关,非生产地址

    报告状态: 已修复并验证(路由、8004 health、SSH 回包路径均正常)

    MP3