欢迎光临
我们一直在努力

Docker - 容器的跨主机通信实现方案详解

在这里插入图片描述

👋 大家好,欢迎来到我的技术博客! 📚 在这里,我会分享学习笔记、实战经验与技术思考,力求用简单的方式讲清楚复杂的问题。 🎯 本文将围绕Docker这个话题展开,希望能为你带来一些启发或实用的参考。 🌱 无论你是刚入门的新手,还是正在进阶的开发者,希望你都能有所收获!


文章目录

  • Docker 容器的跨主机通信实现方案详解 🌐
    • 🔍 为什么跨主机通信如此复杂?—— 网络本质再思考
    • 🧱 方案一:Docker Swarm 内置 Overlay 网络(零依赖、开箱即用)
      • 📐 网络模型与数据流
      • ⚙️ 实践:三步搭建可通信集群
        • 步骤 1:初始化 Swarm Manager(Host-A)
        • 步骤 2:Worker 节点加入(Host-B)
        • 步骤 3:创建 Overlay 网络并部署服务
      • 💻 Java 示例:Spring Boot 服务调用(容器名直连)
        • `inventory-service`(提供库存接口)
        • `order-service`(调用库存服务)
        • Docker Compose 部署(Swarm 模式下生效)
    • 🌐 方案二:Flannel —— Kubernetes 生态最轻量的 CNI 插件
      • 📐 网络模型(Host-GW 模式,极致性能)
      • ⚙️ 实践:Kubernetes 集群中启用 Flannel
        • 步骤 1:安装 Flannel(官方 manifest)
        • 步骤 2:验证网络就绪
      • 💻 Java 示例:Kubernetes Service 调用(DNS + ClusterIP)
        • `inventory-service` Deployment + Service
        • `order-service` 中调用逻辑(Java)
        • 启动参数注入(Deployment 中)
    • 🛡️ 方案三:Calico —— 企业级策略驱动网络(BGP + eBPF)
      • 📐 网络模型(BGP 模式)
      • ⚙️ 实践:在 kubeadm 集群部署 Calico
        • 步骤 1:安装 Calico(Tigera 官方推荐)
        • 步骤 2:验证 BGP 连接
      • 💻 Java 示例:NetworkPolicy 控制下的安全调用
        • `network-policy.yaml`
        • Java 代码无需修改,策略由 Calico 透明执行:
    • 🧩 方案四:Weave Net —— 自动加密、DNS 驱动的开发者友好网络
      • 📐 网络模型(FastDP 模式)
      • ⚙️ 实践:Weave on Docker Standalone(非 Kubernetes)
        • 步骤 1:在 Host-A 启动 Weave
        • 步骤 2:在 Host-B 加入
        • 步骤 3:运行容器并验证 DNS
      • 💻 Java 示例:Weave DNS 直连(无 Kubernetes 依赖)
    • 🧭 方案五:自建 VXLAN 隧道(Linux 原生命令,教学价值高)
      • 📐 网络模型(手动 VXLAN)
      • ⚙️ 实践:手敲命令搭建(Host-A & Host-B)
        • Host-A 执行:
        • Host-B 执行(类似,注意 IP 和 VNI 一致):
        • 测试连通性:
    • 🌐 方案六:Service Mesh 间接通信(Istio / Linkerd)
      • 📐 模型示意(Istio)
      • 💻 Java 示例:零代码改造
    • 🧪 方案对比与选型决策树
      • 🧭 决策树(简化版):
    • 🚀 最佳实践与避坑指南
      • ✅ 必做事项
      • ❌ 经典陷阱
      • 🔍 调试黄金命令
    • 🌟 结语:通信只是开始,治理才是未来

Docker 容器的跨主机通信实现方案详解 🌐

在现代云原生架构中,Docker 已成为容器化部署的事实标准。然而,单机 Docker(docker run 启动的默认 bridge 网络)天然隔离于宿主机网络,更无法直接与其他物理机或虚拟机上的容器通信。当业务规模扩大、服务需水平扩展、或混合部署(如部分服务在 IDC,部分在公有云)时,“容器如何跨主机互通”便成为绕不开的核心命题 🚧。

本文将系统性地剖析 Docker 跨主机通信的主流实现方案:从底层原理到工程落地,涵盖 Overlay 网络(Docker Swarm 原生)、Flannel、Calico、Weave、自建 VXLAN 隧道、以及基于 Service Mesh 的间接通信路径;每种方案均配以清晰的网络拓扑图(Mermaid 渲染)、可验证的配置步骤、真实可用的 Java 服务代码示例(含 Spring Boot REST API + 容器间 HTTP 调用逻辑),并指出适用场景与关键取舍。所有技术细节均基于当前稳定生态(Docker 24.x / Kubernetes 1.28+ / Spring Boot 3.2+),无过时假设,所有外链均为权威、公开、无需登录即可访问的文档站点 ✅。


🔍 为什么跨主机通信如此复杂?—— 网络本质再思考

Docker 默认使用 bridge 驱动创建 docker0 网桥,为每个容器分配 172.17.0.0/16 内网 IP,并通过 iptables NAT 实现与外部通信。该设计带来两个根本限制:

  • IP 地址不可路由:172.17.0.x 是私有地址段,宿主机之间未建立路由规则,A 主机的 172.17.0.2 对 B 主机完全不可见;
  • 二层隔离:Docker bridge 是 Linux kernel 的虚拟网桥,仅在同一宿主机内有效,无法跨越物理网络边界。
  • 要让 Host-A 上的 container-A(IP: 10.0.1.5)直接 ping 或 HTTP GET Host-B 上的 container-B(IP: 10.0.2.8),必须在三层(IP 层)之上构建一个逻辑覆盖网络(Overlay Network) —— 即在现有物理网络(underlay)之上,封装一层可跨主机寻址与转发的虚拟网络平面 🌐。

    💡 关键共识:跨主机通信 ≠ 端口映射(-p 8080:8080)。后者仅暴露服务端口到宿主机,仍需客户端主动访问宿主机 IP,且无法实现容器 IP 直通、服务发现、策略控制等高级能力。


    🧱 方案一:Docker Swarm 内置 Overlay 网络(零依赖、开箱即用)

    Docker Engine 自带集群编排能力(Swarm mode),其 overlay 网络驱动基于 VXLAN 封装 + 内置 KV 存储(Gossip 协议),无需额外组件,适合中小规模、对 Kubernetes 无强需求的团队。

    📐 网络模型与数据流

    #mermaid-svg-y9vsTG4E5Df57dvm{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-y9vsTG4E5Df57dvm .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-y9vsTG4E5Df57dvm .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-y9vsTG4E5Df57dvm .error-icon{fill:#552222;}#mermaid-svg-y9vsTG4E5Df57dvm .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-y9vsTG4E5Df57dvm .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-y9vsTG4E5Df57dvm .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-y9vsTG4E5Df57dvm .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-y9vsTG4E5Df57dvm .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-y9vsTG4E5Df57dvm .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-y9vsTG4E5Df57dvm .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-y9vsTG4E5Df57dvm .marker{fill:#333333;stroke:#333333;}#mermaid-svg-y9vsTG4E5Df57dvm .marker.cross{stroke:#333333;}#mermaid-svg-y9vsTG4E5Df57dvm svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-y9vsTG4E5Df57dvm p{margin:0;}#mermaid-svg-y9vsTG4E5Df57dvm .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-y9vsTG4E5Df57dvm .cluster-label text{fill:#333;}#mermaid-svg-y9vsTG4E5Df57dvm .cluster-label span{color:#333;}#mermaid-svg-y9vsTG4E5Df57dvm .cluster-label span p{background-color:transparent;}#mermaid-svg-y9vsTG4E5Df57dvm .label text,#mermaid-svg-y9vsTG4E5Df57dvm span{fill:#333;color:#333;}#mermaid-svg-y9vsTG4E5Df57dvm .node rect,#mermaid-svg-y9vsTG4E5Df57dvm .node circle,#mermaid-svg-y9vsTG4E5Df57dvm .node ellipse,#mermaid-svg-y9vsTG4E5Df57dvm .node polygon,#mermaid-svg-y9vsTG4E5Df57dvm .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-y9vsTG4E5Df57dvm .rough-node .label text,#mermaid-svg-y9vsTG4E5Df57dvm .node .label text,#mermaid-svg-y9vsTG4E5Df57dvm .image-shape .label,#mermaid-svg-y9vsTG4E5Df57dvm .icon-shape .label{text-anchor:middle;}#mermaid-svg-y9vsTG4E5Df57dvm .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-y9vsTG4E5Df57dvm .rough-node .label,#mermaid-svg-y9vsTG4E5Df57dvm .node .label,#mermaid-svg-y9vsTG4E5Df57dvm .image-shape .label,#mermaid-svg-y9vsTG4E5Df57dvm .icon-shape .label{text-align:center;}#mermaid-svg-y9vsTG4E5Df57dvm .node.clickable{cursor:pointer;}#mermaid-svg-y9vsTG4E5Df57dvm .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-y9vsTG4E5Df57dvm .arrowheadPath{fill:#333333;}#mermaid-svg-y9vsTG4E5Df57dvm .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-y9vsTG4E5Df57dvm .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-y9vsTG4E5Df57dvm .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-y9vsTG4E5Df57dvm .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-y9vsTG4E5Df57dvm .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-y9vsTG4E5Df57dvm .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-y9vsTG4E5Df57dvm .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-y9vsTG4E5Df57dvm .cluster text{fill:#333;}#mermaid-svg-y9vsTG4E5Df57dvm .cluster span{color:#333;}#mermaid-svg-y9vsTG4E5Df57dvm div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-y9vsTG4E5Df57dvm .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-y9vsTG4E5Df57dvm rect.text{fill:none;stroke-width:0;}#mermaid-svg-y9vsTG4E5Df57dvm .icon-shape,#mermaid-svg-y9vsTG4E5Df57dvm .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-y9vsTG4E5Df57dvm .icon-shape p,#mermaid-svg-y9vsTG4E5Df57dvm .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-y9vsTG4E5Df57dvm .icon-shape .label rect,#mermaid-svg-y9vsTG4E5Df57dvm .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-y9vsTG4E5Df57dvm .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-y9vsTG4E5Df57dvm .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-y9vsTG4E5Df57dvm :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}

    Host B

    Host A

    eth0

    UDP 8472

    IP PacketDst: Host-B IP

    eth0

    Container-A10.0.1.5

    swarm-overlayVXLAN dev: vxlan0

    Host-A KernelVXLAN Encap

    Physical Network

    Host-B KernelVXLAN Decap

    swarm-overlayVXLAN dev: vxlan0

    Container-B10.0.2.8

    • 所有容器接入同一 overlay 网络后,获得 10.0.0.0/16 内连续 IP(由 Swarm 内置分配器管理);
    • 数据包经 vxlan0 设备封装为 UDP 报文(目的端口 8472),通过物理网络送达目标主机;
    • 目标主机内核解封后,交付至本地容器 —— 对应用完全透明,如同运行在同一台机器上。

    ⚙️ 实践:三步搭建可通信集群

    步骤 1:初始化 Swarm Manager(Host-A)

    # 初始化 Swarm,指定 advertise-addr 为 Host-A 可被 Host-B 访问的 IP(如 192.168.1.10)
    docker swarm init –advertise-addr 192.168.1.10
    # 输出加入命令,类似:
    # docker swarm join –token SWMTKN-1-abc… 192.168.1.10:2377

    步骤 2:Worker 节点加入(Host-B)

    # 在 Host-B 执行上一步输出的 join 命令
    docker swarm join –token SWMTKN-1-abc... 192.168.1.10:2377

    步骤 3:创建 Overlay 网络并部署服务

    # 在 Manager 节点创建 overlay 网络(–attachable 允许独立容器接入)
    docker network create -d overlay –attachable my-overlay

    # 启动服务 A(自动调度到某节点)
    docker service create \\
    –name service-a \\
    –network my-overlay \\
    –publish published=8080,target=8080 \\
    nginx:alpine

    # 启动服务 B(同网络)
    docker service create \\
    –name service-b \\
    –network my-overlay \\
    –publish published=8081,target=8080 \\
    nginx:alpine

    此时,service-a 容器内可直接 curl http://service-b:8080 —— Swarm 内置 DNS 会解析 service-b 为该服务所有任务(tasks)的 VIP(Virtual IP),流量经 overlay 网络负载均衡 🌟。

    💻 Java 示例:Spring Boot 服务调用(容器名直连)

    我们编写两个 Spring Boot 应用:order-service(下单)与 inventory-service(库存查询),通过 inventory-service 容器名调用其 /api/stock/{sku} 接口。

    inventory-service(提供库存接口)

    // InventoryController.java
    @RestController
    @RequestMapping("/api")
    public class InventoryController {

    @GetMapping("/stock/{sku}")
    public ResponseEntity<Map<String, Object>> getStock(@PathVariable String sku) {
    Map<String, Object> response = new HashMap<>();
    response.put("sku", sku);
    response.put("available", true);
    response.put("quantity", 99);
    response.put("host", InetAddress.getLoopbackAddress().getHostName()); // 返回容器主机名,用于验证来源
    return ResponseEntity.ok(response);
    }
    }

    order-service(调用库存服务)

    // OrderService.java
    @Service
    public class OrderService {

    private final RestTemplate restTemplate;

    public OrderService(RestTemplate restTemplate) {
    this.restTemplate = restTemplate;
    }

    public Map<String, Object> placeOrder(String sku) {
    try {
    // ⚠️ 关键:直接使用容器名 inventory-service 作为 hostname!
    String url = "http://inventory-service:8080/api/stock/" + sku;
    ResponseEntity<Map> response = restTemplate.getForEntity(url, Map.class);
    System.out.println("✅ Inventory response from: " + response.getBody().get("host"));
    return response.getBody();
    } catch (Exception e) {
    System.err.println("❌ Failed to call inventory-service: " + e.getMessage());
    throw new RuntimeException("Inventory check failed", e);
    }
    }
    }

    // OrderController.java(暴露下单 API)
    @RestController
    @RequestMapping("/api")
    public class OrderController {

    private final OrderService orderService;

    public OrderController(OrderService orderService) {
    this.orderService = orderService;
    }

    @PostMapping("/orders")
    public Map<String, Object> createOrder(@RequestBody Map<String, String> request) {
    String sku = request.get("sku");
    return orderService.placeOrder(sku);
    }
    }

    Docker Compose 部署(Swarm 模式下生效)

    # docker-compose.yml
    version: '3.8'
    services:
    inventory-service:
    image: spring–inventory:1.0
    networks:
    – my–overlay
    ports:
    – "8080:8080"
    deploy:
    replicas: 1

    order-service:
    image: spring–order:1.0
    networks:
    – my–overlay
    ports:
    – "8081:8081"
    depends_on:
    – inventory–service
    deploy:
    replicas: 1

    networks:
    my-overlay:
    driver: overlay
    attachable: true

    构建镜像并部署:

    docker build -t spring-inventory:1.0 -f Dockerfile.inventory .
    docker build -t spring-order:1.0 -f Dockerfile.order .
    docker stack deploy -c docker-compose.yml shop-stack

    验证通信:

    # 进入 order-service 容器
    docker exec -it $(docker ps –filter "name=order-service" -q) sh

    # 在容器内执行(无需 IP,直接容器名)
    curl -s http://inventory-service:8080/api/stock/IPHONE15 | jq
    # 输出示例:
    # {
    # "sku": "IPHONE15",
    # "available": true,
    # "quantity": 99,
    # "host": "inventory-service.1.xxx" ← 来自 Swarm DNS 解析
    # }

    ✅ 优势:零外部依赖、内置 DNS、服务发现、滚动更新、健康检查; ⚠️ 局限:集群规模建议 < 100 节点;不支持 NetworkPolicy(需升级到 UCP 或切换 Calico);调试工具链较弱。

    📘 深入阅读:Docker 官方 Overlay 网络文档 → https://docs.docker.com/network/overlay/


    🌐 方案二:Flannel —— Kubernetes 生态最轻量的 CNI 插件

    Flannel 由 CoreOS 开发,是 Kubernetes 早期事实标准网络插件。它不操作 Docker daemon,而是为每个 Node 分配唯一子网(如 10.244.1.0/24),容器 IP 直接路由可达,无隧道封装开销(可选 VXLAN/Host-GW 模式)。

    📐 网络模型(Host-GW 模式,极致性能)

    #mermaid-svg-hGShKYnOWazAQlOS{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-hGShKYnOWazAQlOS .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-hGShKYnOWazAQlOS .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-hGShKYnOWazAQlOS .error-icon{fill:#552222;}#mermaid-svg-hGShKYnOWazAQlOS .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-hGShKYnOWazAQlOS .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-hGShKYnOWazAQlOS .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-hGShKYnOWazAQlOS .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-hGShKYnOWazAQlOS .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-hGShKYnOWazAQlOS .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-hGShKYnOWazAQlOS .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-hGShKYnOWazAQlOS .marker{fill:#333333;stroke:#333333;}#mermaid-svg-hGShKYnOWazAQlOS .marker.cross{stroke:#333333;}#mermaid-svg-hGShKYnOWazAQlOS svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-hGShKYnOWazAQlOS p{margin:0;}#mermaid-svg-hGShKYnOWazAQlOS .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-hGShKYnOWazAQlOS .cluster-label text{fill:#333;}#mermaid-svg-hGShKYnOWazAQlOS .cluster-label span{color:#333;}#mermaid-svg-hGShKYnOWazAQlOS .cluster-label span p{background-color:transparent;}#mermaid-svg-hGShKYnOWazAQlOS .label text,#mermaid-svg-hGShKYnOWazAQlOS span{fill:#333;color:#333;}#mermaid-svg-hGShKYnOWazAQlOS .node rect,#mermaid-svg-hGShKYnOWazAQlOS .node circle,#mermaid-svg-hGShKYnOWazAQlOS .node ellipse,#mermaid-svg-hGShKYnOWazAQlOS .node polygon,#mermaid-svg-hGShKYnOWazAQlOS .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-hGShKYnOWazAQlOS .rough-node .label text,#mermaid-svg-hGShKYnOWazAQlOS .node .label text,#mermaid-svg-hGShKYnOWazAQlOS .image-shape .label,#mermaid-svg-hGShKYnOWazAQlOS .icon-shape .label{text-anchor:middle;}#mermaid-svg-hGShKYnOWazAQlOS .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-hGShKYnOWazAQlOS .rough-node .label,#mermaid-svg-hGShKYnOWazAQlOS .node .label,#mermaid-svg-hGShKYnOWazAQlOS .image-shape .label,#mermaid-svg-hGShKYnOWazAQlOS .icon-shape .label{text-align:center;}#mermaid-svg-hGShKYnOWazAQlOS .node.clickable{cursor:pointer;}#mermaid-svg-hGShKYnOWazAQlOS .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-hGShKYnOWazAQlOS .arrowheadPath{fill:#333333;}#mermaid-svg-hGShKYnOWazAQlOS .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-hGShKYnOWazAQlOS .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-hGShKYnOWazAQlOS .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-hGShKYnOWazAQlOS .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-hGShKYnOWazAQlOS .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-hGShKYnOWazAQlOS .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-hGShKYnOWazAQlOS .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-hGShKYnOWazAQlOS .cluster text{fill:#333;}#mermaid-svg-hGShKYnOWazAQlOS .cluster span{color:#333;}#mermaid-svg-hGShKYnOWazAQlOS div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-hGShKYnOWazAQlOS .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-hGShKYnOWazAQlOS rect.text{fill:none;stroke-width:0;}#mermaid-svg-hGShKYnOWazAQlOS .icon-shape,#mermaid-svg-hGShKYnOWazAQlOS .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-hGShKYnOWazAQlOS .icon-shape p,#mermaid-svg-hGShKYnOWazAQlOS .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-hGShKYnOWazAQlOS .icon-shape .label rect,#mermaid-svg-hGShKYnOWazAQlOS .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-hGShKYnOWazAQlOS .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-hGShKYnOWazAQlOS .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-hGShKYnOWazAQlOS :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}

    Host B192.168.1.11

    Host A192.168.1.10

    eth0

    Kernel Route

    Kernel Route

    eth0

    Container-A10.244.1.5

    flannel.110.244.1.0/24

    Route: 10.244.2.0/24 via 192.168.1.11

    Physical NIC

    Physical NIC

    flannel.110.244.2.0/24

    Container-B10.244.2.8

    • Flannel DaemonSet 在每节点启动 flanneld,从 etcd 获取本机子网(如 10.244.1.0/24);
    • flanneld 配置 Linux kernel 路由表:ip route add 10.244.2.0/24 via 192.168.1.11;
    • 容器发出的数据包,经 kernel 路由直接发往目标宿主机物理 IP,由目标宿主机 flannel.1 网桥接收并转发给容器 —— 纯三层路由,零封装,延迟最低。

    ⚙️ 实践:Kubernetes 集群中启用 Flannel

    注意:此方案需先有 Kubernetes 集群(kubeadm 或托管 K8s)。Flannel 作为 CNI 插件工作于 kubelet 与容器运行时之间。

    步骤 1:安装 Flannel(官方 manifest)

    kubectl apply -f https://github.com/flannel-io/flannel/releases/download/v0.24.2/kube-flannel.yml

    该 YAML 会:

    • 创建 kube-flannel Namespace;
    • 部署 flanneld DaemonSet(自动注入 –iface=eth0 参数);
    • 创建 kube-flannel-cfg ConfigMap,定义网络配置(默认 10.244.0.0/16);
    • 设置 RBAC 权限。
    步骤 2:验证网络就绪

    # 查看 flannel Pod 状态
    kubectl get pods -n kube-flannel

    # 查看节点路由(在 Host-A 执行)
    ip route | grep 10.244
    # 输出应包含:10.244.2.0/24 via 192.168.1.11 dev eth0

    # 查看容器 IP(任意 Pod)
    kubectl get pods -o wide
    # NAME READY STATUS IP NODE
    # nginx-abc12 1/1 Running 10.244.1.5 host-a
    # redis-def34 1/1 Running 10.244.2.8 host-b ← 跨主机!

    💻 Java 示例:Kubernetes Service 调用(DNS + ClusterIP)

    在 Kubernetes 中,我们不再直接使用容器名,而是通过 Service 对象抽象后端 Pod 集合,并利用集群 DNS(CoreDNS)解析 service-name.namespace.svc.cluster.local。

    inventory-service Deployment + Service

    # inventory-deploy.yaml
    apiVersion: apps/v1
    kind: Deployment
    metadata:
    name: inventory–deployment
    spec:
    replicas: 2
    selector:
    matchLabels:
    app: inventory
    template:
    metadata:
    labels:
    app: inventory
    spec:
    containers:
    – name: inventory
    image: spring–inventory:1.0
    ports:
    – containerPort: 8080
    —
    # inventory-service.yaml
    apiVersion: v1
    kind: Service
    metadata:
    name: inventory–service
    spec:
    selector:
    app: inventory
    ports:
    – protocol: TCP
    port: 8080
    targetPort: 8080
    type: ClusterIP # 内部服务,仅集群内可访问

    order-service 中调用逻辑(Java)

    @Service
    public class InventoryClient {

    private final RestTemplate restTemplate;
    private final String inventoryUrl; // 从环境变量注入

    public InventoryClient(RestTemplate restTemplate,
    @Value("${inventory.service.url:http://inventory-service:8080}") String url) {
    this.restTemplate = restTemplate;
    this.inventoryUrl = url;
    }

    public Map<String, Object> checkStock(String sku) {
    // 使用 Service DNS 名称(Kubernetes 自动解析)
    String url = inventoryUrl + "/api/stock/" + sku;
    return restTemplate.getForObject(url, Map.class);
    }
    }

    启动参数注入(Deployment 中)

    # order-deploy.yaml
    env:
    – name: INVENTORY_SERVICE_URL
    value: "http://inventory-service.default.svc.cluster.local:8080"
    # 或简写(default namespace 可省略)
    # value: "http://inventory-service:8080"

    ✅ 优势:极致性能(Host-GW)、轻量(仅需 etcd + flanneld)、K8s 生态兼容性最佳; ⚠️ 局限:不支持 NetworkPolicy(需配合 Calico);大规模集群下 etcd 成为瓶颈;VXLAN 模式有封装开销。

    📘 深入阅读:Flannel 官方架构说明 → https://github.com/flannel-io/flannel#architecture


    🛡️ 方案三:Calico —— 企业级策略驱动网络(BGP + eBPF)

    Calico 是 CNCF 毕业项目,定位为“云原生网络与安全平台”。它摒弃隧道,原生集成 Linux BGP 协议,让每个节点成为 BGP Speaker,动态宣告自身容器子网,实现全网可达;同时提供细粒度 NetworkPolicy(Kubernetes 原生策略)、eBPF 加速、服务网格集成。

    📐 网络模型(BGP 模式)

    #mermaid-svg-Lskk8rH97I0G5IqJ{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-Lskk8rH97I0G5IqJ .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-Lskk8rH97I0G5IqJ .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-Lskk8rH97I0G5IqJ .error-icon{fill:#552222;}#mermaid-svg-Lskk8rH97I0G5IqJ .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-Lskk8rH97I0G5IqJ .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-Lskk8rH97I0G5IqJ .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-Lskk8rH97I0G5IqJ .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-Lskk8rH97I0G5IqJ .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-Lskk8rH97I0G5IqJ .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-Lskk8rH97I0G5IqJ .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-Lskk8rH97I0G5IqJ .marker{fill:#333333;stroke:#333333;}#mermaid-svg-Lskk8rH97I0G5IqJ .marker.cross{stroke:#333333;}#mermaid-svg-Lskk8rH97I0G5IqJ svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-Lskk8rH97I0G5IqJ p{margin:0;}#mermaid-svg-Lskk8rH97I0G5IqJ .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-Lskk8rH97I0G5IqJ .cluster-label text{fill:#333;}#mermaid-svg-Lskk8rH97I0G5IqJ .cluster-label span{color:#333;}#mermaid-svg-Lskk8rH97I0G5IqJ .cluster-label span p{background-color:transparent;}#mermaid-svg-Lskk8rH97I0G5IqJ .label text,#mermaid-svg-Lskk8rH97I0G5IqJ span{fill:#333;color:#333;}#mermaid-svg-Lskk8rH97I0G5IqJ .node rect,#mermaid-svg-Lskk8rH97I0G5IqJ .node circle,#mermaid-svg-Lskk8rH97I0G5IqJ .node ellipse,#mermaid-svg-Lskk8rH97I0G5IqJ .node polygon,#mermaid-svg-Lskk8rH97I0G5IqJ .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-Lskk8rH97I0G5IqJ .rough-node .label text,#mermaid-svg-Lskk8rH97I0G5IqJ .node .label text,#mermaid-svg-Lskk8rH97I0G5IqJ .image-shape .label,#mermaid-svg-Lskk8rH97I0G5IqJ .icon-shape .label{text-anchor:middle;}#mermaid-svg-Lskk8rH97I0G5IqJ .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-Lskk8rH97I0G5IqJ .rough-node .label,#mermaid-svg-Lskk8rH97I0G5IqJ .node .label,#mermaid-svg-Lskk8rH97I0G5IqJ .image-shape .label,#mermaid-svg-Lskk8rH97I0G5IqJ .icon-shape .label{text-align:center;}#mermaid-svg-Lskk8rH97I0G5IqJ .node.clickable{cursor:pointer;}#mermaid-svg-Lskk8rH97I0G5IqJ .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-Lskk8rH97I0G5IqJ .arrowheadPath{fill:#333333;}#mermaid-svg-Lskk8rH97I0G5IqJ .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-Lskk8rH97I0G5IqJ .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-Lskk8rH97I0G5IqJ .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Lskk8rH97I0G5IqJ .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-Lskk8rH97I0G5IqJ .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Lskk8rH97I0G5IqJ .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-Lskk8rH97I0G5IqJ .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-Lskk8rH97I0G5IqJ .cluster text{fill:#333;}#mermaid-svg-Lskk8rH97I0G5IqJ .cluster span{color:#333;}#mermaid-svg-Lskk8rH97I0G5IqJ div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-Lskk8rH97I0G5IqJ .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-Lskk8rH97I0G5IqJ rect.text{fill:none;stroke-width:0;}#mermaid-svg-Lskk8rH97I0G5IqJ .icon-shape,#mermaid-svg-Lskk8rH97I0G5IqJ .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Lskk8rH97I0G5IqJ .icon-shape p,#mermaid-svg-Lskk8rH97I0G5IqJ .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-Lskk8rH97I0G5IqJ .icon-shape .label rect,#mermaid-svg-Lskk8rH97I0G5IqJ .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Lskk8rH97I0G5IqJ .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-Lskk8rH97I0G5IqJ .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-Lskk8rH97I0G5IqJ :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}

    Host B

    Host A

    BGP Session

    BGP Update

    BGP Session

    BGP Update

    BGP over TCP 179

    Container-A10.244.1.5

    cni0 bridge

    caliXXX interface

    Host-B

    Route: 10.244.2.0/24

    caliYYY interface

    cni0 bridge

    Container-B10.244.2.8

    Host-A

    Route: 10.244.1.0/24

    • Calico 为每个节点分配 10.244.0.0/16 下的 /26 子网(如 10.244.1.0/26);
    • calico-node DaemonSet 启动 bird(BGP 守护进程),与集群内其他节点建立 Full Mesh BGP 连接;
    • 节点学习到所有子网路由后,容器流量直接路由,无隧道、无 NAT、无额外封装;
    • felix 组件实时同步 Kubernetes NetworkPolicy 到 iptables/eBPF,实现微隔离。

    ⚙️ 实践:在 kubeadm 集群部署 Calico

    步骤 1:安装 Calico(Tigera 官方推荐)

    # 下载并应用 Calico manifest(自动适配 kubeadm CIDR)
    kubectl create -f https://raw.githubusercontent.com/projectcalico/calico/v3.27.2/manifests/tigera-operator.yaml
    kubectl create -f https://raw.githubusercontent.com/projectcalico/calico/v3.27.2/manifests/custom-resources.yaml

    ✅ 此方式使用 Tigera Operator,比传统 calico.yaml 更健壮,支持升级、监控、多租户。

    步骤 2:验证 BGP 连接

    # 查看 calico-node Pod
    kubectl get pods -n tigera-operator

    # 进入 calico-node 容器查看 BGP 状态
    kubectl exec -n calico-system deploy/calico-node — birdcl status
    # 输出应显示:BGP state = Established,Peer address = 192.168.1.11

    # 查看路由表
    kubectl exec -n calico-system deploy/calico-node — ip route | grep 10.244
    # 10.244.2.0/26 via 192.168.1.11 dev eth0

    💻 Java 示例:NetworkPolicy 控制下的安全调用

    我们定义一条策略:仅允许 order-service Pod 访问 inventory-service 的 8080 端口。

    network-policy.yaml

    apiVersion: networking.k8s.io/v1
    kind: NetworkPolicy
    metadata:
    name: allow–order–to–inventory
    namespace: default
    spec:
    podSelector:
    matchLabels:
    app: inventory
    policyTypes:
    – Ingress
    ingress:
    – from:
    – podSelector:
    matchLabels:
    app: order
    ports:
    – protocol: TCP
    port: 8080

    应用后,order-service 可正常调用 inventory-service,但其他 Pod(如 debug-pod)将被拒绝。

    Java 代码无需修改,策略由 Calico 透明执行:

    // InventoryClient.java(同前)
    public Map<String, Object> checkStock(String sku) {
    // 仍使用 Service DNS,策略在底层生效
    String url = "http://inventory-service:8080/api/stock/" + sku;
    return restTemplate.getForObject(url, Map.class);
    }

    ✅ 优势:企业级策略、BGP 原生路由、eBPF 加速(可选)、可观测性(Flow Logs)、服务网格集成; ⚠️ 局限:学习曲线陡峭;BGP 需要网络设备支持(或使用 internal BGP);资源占用略高。

    📘 深入阅读:Calico 官方 NetworkPolicy 教程 → https://projectcalico.docs.tigera.io/security/calico-network-policy


    🧩 方案四:Weave Net —— 自动加密、DNS 驱动的开发者友好网络

    Weave Net 由 Weaveworks 开发,主打“开箱即用、自动发现、默认加密”。它使用 weave 虚拟网桥 + weaver 路由守护进程,支持 VXLAN 和 fastdp(数据面加速)模式,并内置 DNS 服务,容器可通过 service.namespace.weave.local 直连。

    📐 网络模型(FastDP 模式)

    #mermaid-svg-vxeDHJmz7w0vo7rM{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-vxeDHJmz7w0vo7rM .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-vxeDHJmz7w0vo7rM .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-vxeDHJmz7w0vo7rM .error-icon{fill:#552222;}#mermaid-svg-vxeDHJmz7w0vo7rM .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-vxeDHJmz7w0vo7rM .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-vxeDHJmz7w0vo7rM .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-vxeDHJmz7w0vo7rM .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-vxeDHJmz7w0vo7rM .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-vxeDHJmz7w0vo7rM .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-vxeDHJmz7w0vo7rM .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-vxeDHJmz7w0vo7rM .marker{fill:#333333;stroke:#333333;}#mermaid-svg-vxeDHJmz7w0vo7rM .marker.cross{stroke:#333333;}#mermaid-svg-vxeDHJmz7w0vo7rM svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-vxeDHJmz7w0vo7rM p{margin:0;}#mermaid-svg-vxeDHJmz7w0vo7rM .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-vxeDHJmz7w0vo7rM .cluster-label text{fill:#333;}#mermaid-svg-vxeDHJmz7w0vo7rM .cluster-label span{color:#333;}#mermaid-svg-vxeDHJmz7w0vo7rM .cluster-label span p{background-color:transparent;}#mermaid-svg-vxeDHJmz7w0vo7rM .label text,#mermaid-svg-vxeDHJmz7w0vo7rM span{fill:#333;color:#333;}#mermaid-svg-vxeDHJmz7w0vo7rM .node rect,#mermaid-svg-vxeDHJmz7w0vo7rM .node circle,#mermaid-svg-vxeDHJmz7w0vo7rM .node ellipse,#mermaid-svg-vxeDHJmz7w0vo7rM .node polygon,#mermaid-svg-vxeDHJmz7w0vo7rM .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-vxeDHJmz7w0vo7rM .rough-node .label text,#mermaid-svg-vxeDHJmz7w0vo7rM .node .label text,#mermaid-svg-vxeDHJmz7w0vo7rM .image-shape .label,#mermaid-svg-vxeDHJmz7w0vo7rM .icon-shape .label{text-anchor:middle;}#mermaid-svg-vxeDHJmz7w0vo7rM .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-vxeDHJmz7w0vo7rM .rough-node .label,#mermaid-svg-vxeDHJmz7w0vo7rM .node .label,#mermaid-svg-vxeDHJmz7w0vo7rM .image-shape .label,#mermaid-svg-vxeDHJmz7w0vo7rM .icon-shape .label{text-align:center;}#mermaid-svg-vxeDHJmz7w0vo7rM .node.clickable{cursor:pointer;}#mermaid-svg-vxeDHJmz7w0vo7rM .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-vxeDHJmz7w0vo7rM .arrowheadPath{fill:#333333;}#mermaid-svg-vxeDHJmz7w0vo7rM .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-vxeDHJmz7w0vo7rM .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-vxeDHJmz7w0vo7rM .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-vxeDHJmz7w0vo7rM .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-vxeDHJmz7w0vo7rM .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-vxeDHJmz7w0vo7rM .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-vxeDHJmz7w0vo7rM .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-vxeDHJmz7w0vo7rM .cluster text{fill:#333;}#mermaid-svg-vxeDHJmz7w0vo7rM .cluster span{color:#333;}#mermaid-svg-vxeDHJmz7w0vo7rM div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-vxeDHJmz7w0vo7rM .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-vxeDHJmz7w0vo7rM rect.text{fill:none;stroke-width:0;}#mermaid-svg-vxeDHJmz7w0vo7rM .icon-shape,#mermaid-svg-vxeDHJmz7w0vo7rM .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-vxeDHJmz7w0vo7rM .icon-shape p,#mermaid-svg-vxeDHJmz7w0vo7rM .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-vxeDHJmz7w0vo7rM .icon-shape .label rect,#mermaid-svg-vxeDHJmz7w0vo7rM .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-vxeDHJmz7w0vo7rM .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-vxeDHJmz7w0vo7rM .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-vxeDHJmz7w0vo7rM :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}

    Host B

    Host A

    Encrypted UDP

    Container-A10.32.0.5

    weave bridge

    weaver process

    Host-B

    weaver process

    weave bridge

    Container-B10.32.1.8

    • weave launch 命令自动发现集群(支持 token 或 IP 列表);
    • 所有容器接入 weave 网络后,获得 10.32.0.0/12 内 IP;
    • weaver 进程建立加密 UDP 连接(AES-CTR),封装容器数据包;
    • 内置 weaveDNS 为每个容器注册 <name>.<namespace>.weave.local DNS 记录。

    ⚙️ 实践:Weave on Docker Standalone(非 Kubernetes)

    Weave 可独立于 Kubernetes 运行,适合 Docker Compose 或裸机集群。

    步骤 1:在 Host-A 启动 Weave

    # 启动 weave 并指定 peer(Host-B IP)
    weave launch –ipalloc-range 10.32.0.0/12 192.168.1.11
    # 输出:weave is ready

    步骤 2:在 Host-B 加入

    weave launch –ipalloc-range 10.32.0.0/12 192.168.1.10

    步骤 3:运行容器并验证 DNS

    # Host-A 运行 inventory
    weave run –name inventory -p 8080:8080 spring-inventory:1.0

    # Host-B 运行 order
    weave run –name order -p 8081:8081 spring-order:1.0

    # 在 order 容器内解析 inventory
    docker exec order nslookup inventory.weave.local
    # Server: 127.0.0.11
    # Address 1: 10.32.1.5 inventory.weave.local

    # 调用成功!
    docker exec order curl -s http://inventory.weave.local:8080/api/stock/IPHONE15

    💻 Java 示例:Weave DNS 直连(无 Kubernetes 依赖)

    @Service
    public class InventoryClient {

    private final RestTemplate restTemplate;

    public InventoryClient(RestTemplate restTemplate) {
    this.restTemplate = restTemplate;
    }

    public Map<String, Object> checkStock(String sku) {
    // 使用 Weave DNS 名称(自动注册)
    String url = "http://inventory.weave.local:8080/api/stock/" + sku;
    return restTemplate.getForObject(url, Map.class);
    }
    }

    ✅ 优势:零配置发现、默认加密、内置 DNS、支持 Docker/K8s/standalone; ⚠️ 局限:性能略低于 Flannel/Calico(加密开销);社区活跃度低于 Calico;企业功能需付费版。

    📘 深入阅读:Weave Net 官方快速入门 → https://www.weave.works/docs/net/latest/quickstart/


    🧭 方案五:自建 VXLAN 隧道(Linux 原生命令,教学价值高)

    理解底层原理的最佳方式,是亲手搭建一个 VXLAN 网络。这无需任何第三方软件,仅用 ip、brctl、ethtool 等 Linux 标准工具。

    📐 网络模型(手动 VXLAN)

    #mermaid-svg-ygly9nQ5YJYqlOfb{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-ygly9nQ5YJYqlOfb .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-ygly9nQ5YJYqlOfb .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-ygly9nQ5YJYqlOfb .error-icon{fill:#552222;}#mermaid-svg-ygly9nQ5YJYqlOfb .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-ygly9nQ5YJYqlOfb .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-ygly9nQ5YJYqlOfb .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-ygly9nQ5YJYqlOfb .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-ygly9nQ5YJYqlOfb .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-ygly9nQ5YJYqlOfb .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-ygly9nQ5YJYqlOfb .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-ygly9nQ5YJYqlOfb .marker{fill:#333333;stroke:#333333;}#mermaid-svg-ygly9nQ5YJYqlOfb .marker.cross{stroke:#333333;}#mermaid-svg-ygly9nQ5YJYqlOfb svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-ygly9nQ5YJYqlOfb p{margin:0;}#mermaid-svg-ygly9nQ5YJYqlOfb .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-ygly9nQ5YJYqlOfb .cluster-label text{fill:#333;}#mermaid-svg-ygly9nQ5YJYqlOfb .cluster-label span{color:#333;}#mermaid-svg-ygly9nQ5YJYqlOfb .cluster-label span p{background-color:transparent;}#mermaid-svg-ygly9nQ5YJYqlOfb .label text,#mermaid-svg-ygly9nQ5YJYqlOfb span{fill:#333;color:#333;}#mermaid-svg-ygly9nQ5YJYqlOfb .node rect,#mermaid-svg-ygly9nQ5YJYqlOfb .node circle,#mermaid-svg-ygly9nQ5YJYqlOfb .node ellipse,#mermaid-svg-ygly9nQ5YJYqlOfb .node polygon,#mermaid-svg-ygly9nQ5YJYqlOfb .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-ygly9nQ5YJYqlOfb .rough-node .label text,#mermaid-svg-ygly9nQ5YJYqlOfb .node .label text,#mermaid-svg-ygly9nQ5YJYqlOfb .image-shape .label,#mermaid-svg-ygly9nQ5YJYqlOfb .icon-shape .label{text-anchor:middle;}#mermaid-svg-ygly9nQ5YJYqlOfb .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-ygly9nQ5YJYqlOfb .rough-node .label,#mermaid-svg-ygly9nQ5YJYqlOfb .node .label,#mermaid-svg-ygly9nQ5YJYqlOfb .image-shape .label,#mermaid-svg-ygly9nQ5YJYqlOfb .icon-shape .label{text-align:center;}#mermaid-svg-ygly9nQ5YJYqlOfb .node.clickable{cursor:pointer;}#mermaid-svg-ygly9nQ5YJYqlOfb .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-ygly9nQ5YJYqlOfb .arrowheadPath{fill:#333333;}#mermaid-svg-ygly9nQ5YJYqlOfb .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-ygly9nQ5YJYqlOfb .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-ygly9nQ5YJYqlOfb .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-ygly9nQ5YJYqlOfb .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-ygly9nQ5YJYqlOfb .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-ygly9nQ5YJYqlOfb .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-ygly9nQ5YJYqlOfb .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-ygly9nQ5YJYqlOfb .cluster text{fill:#333;}#mermaid-svg-ygly9nQ5YJYqlOfb .cluster span{color:#333;}#mermaid-svg-ygly9nQ5YJYqlOfb div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-ygly9nQ5YJYqlOfb .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-ygly9nQ5YJYqlOfb rect.text{fill:none;stroke-width:0;}#mermaid-svg-ygly9nQ5YJYqlOfb .icon-shape,#mermaid-svg-ygly9nQ5YJYqlOfb .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-ygly9nQ5YJYqlOfb .icon-shape p,#mermaid-svg-ygly9nQ5YJYqlOfb .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-ygly9nQ5YJYqlOfb .icon-shape .label rect,#mermaid-svg-ygly9nQ5YJYqlOfb .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-ygly9nQ5YJYqlOfb .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-ygly9nQ5YJYqlOfb .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-ygly9nQ5YJYqlOfb :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}

    Host B192.168.1.11

    Host A192.168.1.10

    UDP 8472

    Container-A10.10.1.5

    veth-a

    br-vxlan

    vxlan0VNI: 100

    192.168.1.11

    vxlan0VNI: 100

    br-vxlan

    veth-b

    Container-B10.10.2.8

    ⚙️ 实践:手敲命令搭建(Host-A & Host-B)

    Host-A 执行:

    # 1. 创建 bridge 和 vxlan
    sudo ip link add br-vxlan type bridge
    sudo ip link add vxlan0 type vxlan id 100 dev eth0 dstport 8472
    sudo ip link set vxlan0 master br-vxlan
    sudo ip link set br-vxlan up
    sudo ip link set vxlan0 up

    # 2. 分配子网 IP(供容器使用)
    sudo ip addr add 10.10.1.1/24 dev br-vxlan

    # 3. 启动容器并连接到 br-vxlan
    docker run -d –name container-a –net none ubuntu:22.04 sleep infinity
    PID=$(docker inspect –format '{{.State.Pid}}' container-a)
    sudo mkdir -p /var/run/netns
    sudo ln -s /proc/$PID/ns/net /var/run/netns/container-a

    # 创建 veth pair
    sudo ip link add veth-a type veth peer name veth-a-br
    sudo ip link set veth-a netns container-a
    sudo ip link set veth-a-br master br-vxlan
    sudo ip link set veth-a-br up

    # 配置容器内网络
    sudo ip netns exec container-a ip link set veth-a up
    sudo ip netns exec container-a ip addr add 10.10.1.5/24 dev veth-a
    sudo ip netns exec container-a ip route add default via 10.10.1.1

    Host-B 执行(类似,注意 IP 和 VNI 一致):

    sudo ip link add br-vxlan type bridge
    sudo ip link add vxlan0 type vxlan id 100 dev eth0 dstport 8472
    sudo ip link set vxlan0 master br-vxlan
    sudo ip link set br-vxlan up
    sudo ip link set vxlan0 up
    sudo ip addr add 10.10.2.1/24 dev br-vxlan

    # 启动 container-b…

    测试连通性:

    # Host-A 中
    sudo ip netns exec container-a ping -c 3 10.10.2.5 # 应成功!

    # Host-B 中
    sudo ip netns exec container-b curl http://10.10.1.5:8080/api/stock/IPHONE15

    ✅ 优势:彻底掌握 VXLAN 原理、无黑盒、最小依赖; ⚠️ 局限:运维成本极高、无服务发现、无健康检查、无法规模化。


    🌐 方案六:Service Mesh 间接通信(Istio / Linkerd)

    当直接容器 IP 通信不满足需求(如需要 mTLS、重试、熔断、分布式追踪),Service Mesh 提供了更高维度的解决方案:通信仍走底层网络(如 Calico),但所有流量被 Sidecar 代理劫持,由控制平面统一治理。

    📐 模型示意(Istio)

    #mermaid-svg-WiBYAJwb8WTVJ3kM{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-WiBYAJwb8WTVJ3kM .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-WiBYAJwb8WTVJ3kM .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-WiBYAJwb8WTVJ3kM .error-icon{fill:#552222;}#mermaid-svg-WiBYAJwb8WTVJ3kM .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-WiBYAJwb8WTVJ3kM .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-WiBYAJwb8WTVJ3kM .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-WiBYAJwb8WTVJ3kM .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-WiBYAJwb8WTVJ3kM .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-WiBYAJwb8WTVJ3kM .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-WiBYAJwb8WTVJ3kM .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-WiBYAJwb8WTVJ3kM .marker{fill:#333333;stroke:#333333;}#mermaid-svg-WiBYAJwb8WTVJ3kM .marker.cross{stroke:#333333;}#mermaid-svg-WiBYAJwb8WTVJ3kM svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-WiBYAJwb8WTVJ3kM p{margin:0;}#mermaid-svg-WiBYAJwb8WTVJ3kM .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-WiBYAJwb8WTVJ3kM .cluster-label text{fill:#333;}#mermaid-svg-WiBYAJwb8WTVJ3kM .cluster-label span{color:#333;}#mermaid-svg-WiBYAJwb8WTVJ3kM .cluster-label span p{background-color:transparent;}#mermaid-svg-WiBYAJwb8WTVJ3kM .label text,#mermaid-svg-WiBYAJwb8WTVJ3kM span{fill:#333;color:#333;}#mermaid-svg-WiBYAJwb8WTVJ3kM .node rect,#mermaid-svg-WiBYAJwb8WTVJ3kM .node circle,#mermaid-svg-WiBYAJwb8WTVJ3kM .node ellipse,#mermaid-svg-WiBYAJwb8WTVJ3kM .node polygon,#mermaid-svg-WiBYAJwb8WTVJ3kM .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-WiBYAJwb8WTVJ3kM .rough-node .label text,#mermaid-svg-WiBYAJwb8WTVJ3kM .node .label text,#mermaid-svg-WiBYAJwb8WTVJ3kM .image-shape .label,#mermaid-svg-WiBYAJwb8WTVJ3kM .icon-shape .label{text-anchor:middle;}#mermaid-svg-WiBYAJwb8WTVJ3kM .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-WiBYAJwb8WTVJ3kM .rough-node .label,#mermaid-svg-WiBYAJwb8WTVJ3kM .node .label,#mermaid-svg-WiBYAJwb8WTVJ3kM .image-shape .label,#mermaid-svg-WiBYAJwb8WTVJ3kM .icon-shape .label{text-align:center;}#mermaid-svg-WiBYAJwb8WTVJ3kM .node.clickable{cursor:pointer;}#mermaid-svg-WiBYAJwb8WTVJ3kM .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-WiBYAJwb8WTVJ3kM .arrowheadPath{fill:#333333;}#mermaid-svg-WiBYAJwb8WTVJ3kM .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-WiBYAJwb8WTVJ3kM .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-WiBYAJwb8WTVJ3kM .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-WiBYAJwb8WTVJ3kM .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-WiBYAJwb8WTVJ3kM .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-WiBYAJwb8WTVJ3kM .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-WiBYAJwb8WTVJ3kM .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-WiBYAJwb8WTVJ3kM .cluster text{fill:#333;}#mermaid-svg-WiBYAJwb8WTVJ3kM .cluster span{color:#333;}#mermaid-svg-WiBYAJwb8WTVJ3kM div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-WiBYAJwb8WTVJ3kM .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-WiBYAJwb8WTVJ3kM rect.text{fill:none;stroke-width:0;}#mermaid-svg-WiBYAJwb8WTVJ3kM .icon-shape,#mermaid-svg-WiBYAJwb8WTVJ3kM .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-WiBYAJwb8WTVJ3kM .icon-shape p,#mermaid-svg-WiBYAJwb8WTVJ3kM .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-WiBYAJwb8WTVJ3kM .icon-shape .label rect,#mermaid-svg-WiBYAJwb8WTVJ3kM .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-WiBYAJwb8WTVJ3kM .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-WiBYAJwb8WTVJ3kM .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-WiBYAJwb8WTVJ3kM :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}

    Host B

    Host A

    HTTP/1.1

    Routing

    Order App

    istio-proxyEnvoy

    ClusterIP Service

    Host-B

    istio-proxyEnvoy

    Inventory App

    • Sidecar(Envoy)与业务容器共享 Network Namespace,拦截 outbound 和 inbound 流量;
    • 流量经 ClusterIP Service 路由,由 Istio Pilot 生成 xDS 配置下发给 Envoy;
    • 应用代码完全无感知,Java 仍调用 http://inventory-service:8080,但实际经过 mTLS 加密、重试 3 次、超时 5s。

    💻 Java 示例:零代码改造

    // OrderService.java(完全不变!)
    public Map<String, Object> placeOrder(String sku) {
    // 依然直连 Service 名称
    String url = "http://inventory-service:8080/api/stock/" + sku;
    return restTemplate.getForObject(url, Map.class);
    }

    Istio 注入后,该请求流程为:

    Order App → localhost:15001 (Envoy inbound)
    → DNS resolve inventory-service → ClusterIP
    → Envoy outbound → mTLS to inventory's Envoy → inventory-app

    ✅ 优势:业务无侵入、全链路可观测、零信任安全、渐进式灰度; ⚠️ 局限:资源开销(CPU/Mem)、调试复杂度高、学习曲线陡峭。

    📘 深入阅读:Istio 官方流量管理指南 → https://istio.io/latest/docs/tasks/traffic-management/


    🧪 方案对比与选型决策树

    方案部署复杂度性能加密策略控制服务发现适用场景
    Docker Swarm Overlay ⭐☆☆☆☆(极简) 中 ❌ ❌ ✅(内置) 小型 Docker 集群,无 K8s 需求
    Flannel ⭐⭐☆☆☆ ⭐⭐⭐⭐⭐(Host-GW) ❌ ❌ ✅(K8s DNS) K8s 初创集群,追求极致性能
    Calico ⭐⭐⭐☆☆ ⭐⭐⭐⭐☆(BGP) ✅(可选) ✅(NetworkPolicy) ✅(K8s DNS) 企业生产环境,需合规与安全
    Weave Net ⭐⭐☆☆☆ ⭐⭐⭐☆☆(加密开销) ✅(默认) ❌ ✅(WeaveDNS) 开发测试、混合环境快速验证
    自建 VXLAN ⭐⭐⭐⭐⭐(手动) ⭐⭐⭐⭐☆ ❌ ❌ ❌ 教学、原理研究、特殊定制
    Service Mesh ⭐⭐⭐⭐☆ ⭐⭐☆☆☆(Sidecar 开销) ✅(mTLS) ✅(细粒度) ✅(K8s DNS + Istio) 微服务治理成熟期,需韧性保障

    🧭 决策树(简化版):

    #mermaid-svg-e5RSQk5gR6YKEbqO{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-e5RSQk5gR6YKEbqO .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-e5RSQk5gR6YKEbqO .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-e5RSQk5gR6YKEbqO .error-icon{fill:#552222;}#mermaid-svg-e5RSQk5gR6YKEbqO .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-e5RSQk5gR6YKEbqO .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-e5RSQk5gR6YKEbqO .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-e5RSQk5gR6YKEbqO .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-e5RSQk5gR6YKEbqO .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-e5RSQk5gR6YKEbqO .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-e5RSQk5gR6YKEbqO .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-e5RSQk5gR6YKEbqO .marker{fill:#333333;stroke:#333333;}#mermaid-svg-e5RSQk5gR6YKEbqO .marker.cross{stroke:#333333;}#mermaid-svg-e5RSQk5gR6YKEbqO svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-e5RSQk5gR6YKEbqO p{margin:0;}#mermaid-svg-e5RSQk5gR6YKEbqO .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-e5RSQk5gR6YKEbqO .cluster-label text{fill:#333;}#mermaid-svg-e5RSQk5gR6YKEbqO .cluster-label span{color:#333;}#mermaid-svg-e5RSQk5gR6YKEbqO .cluster-label span p{background-color:transparent;}#mermaid-svg-e5RSQk5gR6YKEbqO .label text,#mermaid-svg-e5RSQk5gR6YKEbqO span{fill:#333;color:#333;}#mermaid-svg-e5RSQk5gR6YKEbqO .node rect,#mermaid-svg-e5RSQk5gR6YKEbqO .node circle,#mermaid-svg-e5RSQk5gR6YKEbqO .node ellipse,#mermaid-svg-e5RSQk5gR6YKEbqO .node polygon,#mermaid-svg-e5RSQk5gR6YKEbqO .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-e5RSQk5gR6YKEbqO .rough-node .label text,#mermaid-svg-e5RSQk5gR6YKEbqO .node .label text,#mermaid-svg-e5RSQk5gR6YKEbqO .image-shape .label,#mermaid-svg-e5RSQk5gR6YKEbqO .icon-shape .label{text-anchor:middle;}#mermaid-svg-e5RSQk5gR6YKEbqO .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-e5RSQk5gR6YKEbqO .rough-node .label,#mermaid-svg-e5RSQk5gR6YKEbqO .node .label,#mermaid-svg-e5RSQk5gR6YKEbqO .image-shape .label,#mermaid-svg-e5RSQk5gR6YKEbqO .icon-shape .label{text-align:center;}#mermaid-svg-e5RSQk5gR6YKEbqO .node.clickable{cursor:pointer;}#mermaid-svg-e5RSQk5gR6YKEbqO .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-e5RSQk5gR6YKEbqO .arrowheadPath{fill:#333333;}#mermaid-svg-e5RSQk5gR6YKEbqO .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-e5RSQk5gR6YKEbqO .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-e5RSQk5gR6YKEbqO .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-e5RSQk5gR6YKEbqO .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-e5RSQk5gR6YKEbqO .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-e5RSQk5gR6YKEbqO .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-e5RSQk5gR6YKEbqO .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-e5RSQk5gR6YKEbqO .cluster text{fill:#333;}#mermaid-svg-e5RSQk5gR6YKEbqO .cluster span{color:#333;}#mermaid-svg-e5RSQk5gR6YKEbqO div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-e5RSQk5gR6YKEbqO .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-e5RSQk5gR6YKEbqO rect.text{fill:none;stroke-width:0;}#mermaid-svg-e5RSQk5gR6YKEbqO .icon-shape,#mermaid-svg-e5RSQk5gR6YKEbqO .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-e5RSQk5gR6YKEbqO .icon-shape p,#mermaid-svg-e5RSQk5gR6YKEbqO .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-e5RSQk5gR6YKEbqO .icon-shape .label rect,#mermaid-svg-e5RSQk5gR6YKEbqO .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-e5RSQk5gR6YKEbqO .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-e5RSQk5gR6YKEbqO .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-e5RSQk5gR6YKEbqO :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}

    是

    否

    是

    否

    是

    否

    你用 Kubernetes 吗?

    需要 NetworkPolicy 吗?

    用 Docker Swarm 吗?

    选 Calico

    Flannel or Weave

    选 Swarm Overlay

    自建 VXLAN 或 Weave

    部署 Calico

    Flannel for perfWeave for simplicity

    Swarm init + overlay

    Weave launchor manual VXLAN


    🚀 最佳实践与避坑指南

    ✅ 必做事项

    • 始终使用 –mtu 显式设置:VXLAN 封装会减少 MTU,建议在 docker network create 或 Calico ConfigMap 中设为 1450;
    • 关闭宿主机防火墙或放行关键端口:Swarm(2377, 7946, 8472)、Calico(179/BGP)、Weave(6783);
    • 为容器指定 –ip 时,确保在子网范围内:docker run –ip 10.0.1.100 –network my-overlay …;
    • Java 应用禁用 IPv6 回退:添加 JVM 参数 -Djava.net.preferIPv4Stack=true,避免 DNS 解析卡顿。

    ❌ 经典陷阱

    • 混用网络驱动:不要在同一个 docker-compose.yml 中同时声明 bridge 和 overlay 网络,会导致容器无法解析 DNS;
    • 忽略 –advertise-addr:Swarm 初始化时若未指定,可能绑定 127.0.0.1,导致 Worker 无法加入;
    • K8s 中未清理旧 CNI:安装 Flannel 前,务必删除 /etc/cni/net.d/ 下其他插件配置(如 10-calico.conflist),否则 kubelet 启动失败;
    • Java RestTemplate 连接池未复用:高频调用跨主机服务时,务必配置 PoolingHttpClientConnectionManager,否则新建连接耗尽 socket。

    🔍 调试黄金命令

    # 查看容器网络命名空间路由
    docker exec container-name ip route

    # 查看宿主机 VXLAN 设备状态
    ip -d link show vxlan0

    # 抓包分析(在宿主机)
    sudo tcpdump -i eth0 -n port 8472 # VXLAN 流量
    sudo tcpdump -i docker0 -n port 8080 # 容器间 HTTP

    # 检查 DNS 解析(容器内)
    docker exec container-name nslookup inventory-service


    🌟 结语:通信只是开始,治理才是未来

    Docker 跨主机通信,表面是 IP 如何可达的技术问题,深层却是分布式系统可靠性的基石。从 Swarm 的简洁优雅,到 Calico 的企业严谨,再到 Istio 的智能治理,每一种方案都在回答同一个问题:“当我的服务散落于全球数据中心,我该如何信任它们之间的每一次对话?”

    而 Java 开发者幸运的是,无论底层网络如何演进,RestTemplate、WebClient、甚至 FeignClient,都只需关注业务逻辑 —— 网络的复杂性,正被越来越成熟的开源项目悄然封装。

    🌈 下一站,是服务网格的深度集成,是 eBPF 带来的内核级加速,是 WASM 边缘网络的轻量化革命。而此刻,理解这些方案的本质,便是你驾驭云原生浪潮最坚实的船桨 🚣‍♂️。

    愿你在容器网络的世界里,既看得见协议栈的每一层,也写得出优雅的 Spring Boot 代码。 共勉。


    🙌 感谢你读到这里! 🔍 技术之路没有捷径,但每一次阅读、思考和实践,都在悄悄拉近你与目标的距离。 💡 如果本文对你有帮助,不妨 👍 点赞、📌 收藏、📤 分享 给更多需要的朋友! 💬 欢迎在评论区留下你的想法、疑问或建议,我会一一回复,我们一起交流、共同成长 🌿 🔔 关注我,不错过下一篇干货!我们下期再见!✨

    赞(0)
    未经允许不得转载:171主机测评 » Docker - 容器的跨主机通信实现方案详解
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址