# 数据包在 Kubernetes 中的一生（2）

原文：[Life of a Packet in Kubernetes — Part 2](https://dramasamy.medium.com/life-of-a-packet-in-kubernetes-part-2-a07f5bf0ff14)

作者：[Dinesh Kumar Ramasamy](https://dramasamy.medium.com/)

如前文所述，CNI 插件是 Kubernetes 网络的重要组件。目前有很多第三方 CNI 插件，Calico 就是其中之一，因为它的易用性和网络能力，得到很多工程师的青睐。它支持很多不同的平台，例如 Kubernetes、OpenShift、Docker EE、OpenStack 以及裸金属服务。Calico Node 组件以 Docker 容器的形式运行在 Kubernetes 的所有 Master 和 Node 节点上。Calico-CNI 插件会直接集成到 Kubernetes 每个节点的 Kubelet 进程中，一旦发现了新建的 Pod，就会将其加入 Calico 网络。

下面的内容会涉及安装、Calico 模块（Felix、BIRD 以及 Confd）和路由模式，但是不会包含网络策略方面的内容。

## CNI 的任务

1. 创建 `veth` 对，并移入容器
    
2. 鉴别正确的 POD CIDR
    
3. 创建 CNI 配置文件
    
4. IP 地址的分配和管理
    
5. 在容器中加入缺省路由
    
6. 把路由广播给所有 Peer 节点（不适用于 VxLan）
    
7. 在主机上加入路由
    
8. 实施网络策略
    

其实还有很多别的需求，但是上面几个点是最基础的。看看 Master 和 Worker 节点上的路由表。每个节点都有一个容器，容器有一个 IP 地址和缺省的容器路由。

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1745923990299/a97c3c3e-c0b5-483d-9f39-1d3b4a7836b7.png align="center")

上面的路由表说明，Pod 能够通过 3 层网络进行互通。什么模块负责添加路由，如何获取远端路由呢？为什么这里缺省网关是 `169.254.1.1` 呢？我们接下来会讨论这些问题。

Calico 的核心包括 Bird、Felix、ConfD、ETCD 以及 Kubernetes API Server。Calico 需要保存一些配置信息，例如 IP 池、端点信息、网络策略等，数据存储位置是可以配置的，本例中我们使用 Kubernetes 进行存储。

## BIRD（BGP）

Bird 是一个 BGP 守护进程，运行在每个节点上，负责相互交换路由信息。通常的拓扑关系是节点之间构成的网格：

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1745923998376/05fb841c-9256-4dd0-8181-d692494ff6c2.png align="center")

然而集群规模较大的时候，就会很麻烦了。可以使用 Route Reflector（部分 BGP 节点能够配置为 Route Reflector）来完成路由的传播工作，从而降低 BGP 连接数量。路由广播会发送给 Route Reflector，再由 Route Reflector 进行传播，更多信息可以参考 [RFC4456](https://tools.ietf.org/html/rfc4456)。

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1745924004857/38aa301a-43a7-4724-a055-24505a7115e1.png align="center")

BIRD 实例负责向其它 BIRD 实例传递路由信息。缺省配置方式就是 `BGP Mesh`，适用于小规模部署。在大规模集群中，建议使用 `Route Reflector` 来克服这个缺点。可以使用多个 RR 来达成高可用目的，另外还可以使用外部 RR 来替代 BIRD。

## ConfD

ConfD 是一个简单的配置管理工具，运行在 Calico Node 容器中。它会从 ETCD 中读取数据（Calico 的 BIRD 配置），并写入磁盘文件。它会循环读取网络和子网，并应用配置数据（CIDR 键），组装为 BIRD 能够使用的配置。这样不管网络如何变化，BIRD 都能够得到通知并在节点之间广播路由。

## Felix

Calico Felix 守护进程在 Calico Node 容器中运行，完成如下功能：

* 从 Kubernetes ETCD 中读取信息
    
* 构建路由表
    
* 配置 iptables 或者 IPVS
    

看看集群中所有的 Calico 模块：

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1745924014529/90d2f2be-c441-440a-87be-809565e3d5d7.png align="center")

是不是有点不同？`veth` 的一端是“悬空”的，没有连接。

数据包如何被路由到 Peer 节点的？

1. Master 上的 Pod 尝试 Ping `10.0.2.11`
    
2. Pod 向网关发送一个 ARP 请求
    
3. 从 ARP 响应中得到 MAC 地址
    
4. **但是谁响应的 ARP 请求？**
    

容器是怎样路由到一个不存在的 IP 的？容器的缺省路由指向了 `169.254.1.1`。容器的 eth0 需要访问这个地址，因此在使用缺省路由的时候会对这个 IP 进行 ARP 查询。

如果能捕获 ARP 响应信息，会发现 `veth` 另外一侧的（`cali123`） MAC 地址。所以到底是怎样响应一个没有 IP 接口的 ARP 请求的呢？答案是 `proxy-arp`，如果我们检查一下主机侧的 `veth` 接口，会看到启用了 `proxy-arp`：

```bash
$ cat /proc/sys/net/ipv4/conf/cali123/proxy_arp
1
```

> Proxy ARP 技术能用特定网络上的代理设备来响应针对本网络不存在的 IP 地址的 ARP 查询。这个代理知道流量的目标，会以自己的 MAC 地址进行响应。如此一来，流量就转给 Proxy，通常会被 Proxy 使用其它网络接口或者隧道路由到原定目标。这种以自己 MAC 地址响应其他 IP 地址的 ARP 请求，完成代理任务的行为有时也被称为发布。

仔细看看 Worker 节点：

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1745924022285/0880caf0-727b-4bb2-9dbe-67aa5836ca87.png align="center")

数据包进入内核之后，会根据路由表进行路由。

> 入栈流量：首先进入Worker 节点内核。 内核把数据包发给 `cali123`。

## 路由模式

Calico 支持三种路由模式，本节中会对几种模式的优劣和适用场景进行讨论。

* **IP-in-IP**：缺省，有封装行为；
    
* **Direct/NoEncapMode**：无封包（推荐）；
    
* **VxLan**：有封包（无 BGP）
    

### IP-in-IP

这是一种简单的对 IP 包进行再封包的方式。传输中的数据包带有一个外层头部，其中描述了源主机和目的 IP，还有一个内层头部，包含源 Pod 和目标 IP。

目前 Azure 还不支持 IP-IP，因此这种环境中无法使用该模式，建议关掉 IP-IP 以提高性能。

### NoEncapMode

这种模式下数据包是用 Pod 发出时的原始格式发出来的。因为没有封包和解包的开销，这种模式比较有性能优势。

AWS 中要使用这种模式需要关闭源 IP 校验。

### VXLAN

Calico 3.7 以后的版本才支持 VXLAN 路由。

> VXLAN 是 Virtual Extensible LAN 的缩写。VXLAN 是一种封包技术，二层数据帧被封装为 UDP 数据包。VXLAN 是一种网络虚拟化技术。当设备在软件定义的数据中心里进行通信时，会在这些设备之间建立 VXLAN 隧道。这些隧道能建立在屋里或虚拟交换机之上。这些交换端口被称为 VXLAN Tunnel Endpoints（VTEPs），负责 VXLAN 的封包和解包工作。不支持 VXLAN 的设备可以连接到 VTEP，由 VTEP 提供 VXLAN 的出入转换工作。

VXLAN 对于不支持 IP-in-IP 的网络非常有用，例如 Azure 或者其它不支持 BGP 的数据中心。

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1745924033310/1a4fb54c-0c23-4ebf-a5f3-582c98357f15.png align="center")

### 演示—— IPIP 和 UnEncapMode

在没安装 Calico 之前检查一下集群：

```bash
$ kubectl get nodes
NAME           STATUS     ROLES    AGE   VERSION
controlplane   NotReady   master   40s   v1.18.0
node01         NotReady   <none>   9s    v1.18.0

$ kubectl get pods --all-namespaces
NAMESPACE     NAME                                   READY   STATUS    RESTARTS   AGE
kube-system   coredns-66bff467f8-52tkd               0/1     Pending   0          32s
kube-system   coredns-66bff467f8-g5gjb               0/1     Pending   0          32s
kube-system   etcd-controlplane                      1/1     Running   0          34s
kube-system   kube-apiserver-controlplane            1/1     Running   0          34s
kube-system   kube-controller-manager-controlplane   1/1     Running   0          34s
kube-system   kube-proxy-b2j4x                       1/1     Running   0          13s
kube-system   kube-proxy-s46lv                       1/1     Running   0          32s
kube-system   kube-scheduler-controlplane            1/1     Running   0          33s
```

检查 CNI 的二进制文件和目录。其中没有任何配置文件或者 Calico 二进制，Calico 安装过程会用加载卷来填充其中的内容：

```bash
$ cd /etc/cni
-bash: cd: /etc/cni: No such file or directory
$ cd /opt/cni/bin
$ ls
bridge  dhcp  flannel  host-device  host-local  ipvlan  loopback  macvlan  portmap  ptp  sample  tuning  vlan
```

在 Master/Worker 节点上检查 `ip route`：

```bash
$ ip route
default via 172.17.0.1 dev ens3
172.17.0.0/16 dev ens3 proto kernel scope link src 172.17.0.32
172.18.0.0/24 dev docker0 proto kernel scope link src 172.18.0.1 linkdown
```

在集群环境中下载并提交 `calico.yaml`：

```bash
$ curl https://docs.projectcalico.org/manifests/calico.yaml -O
$ kubectl apply -f calico.yaml
```

看看其中的配置参数：

```yaml
cni_network_config: |-
    {
      "name": "k8s-pod-network",
      "cniVersion": "0.3.1",
      "plugins": [
        {
          "type": "calico", >>> Calico's CNI plugin
          "log_level": "info",
          "log_file_path": "/var/log/calico/cni/cni.log",
          "datastore_type": "kubernetes",
          "nodename": "__KUBERNETES_NODE_NAME__",
          "mtu": __CNI_MTU__,
          "ipam": {
              "type": "calico-ipam" >>> Calico's IPAM instaed of default IPAM
          },
          "policy": {
              "type": "k8s"
          },
          "kubernetes": {
              "kubeconfig": "__KUBECONFIG_FILEPATH__"
          }
        },
        {
          "type": "portmap",
          "snat": true,
          "capabilities": {"portMappings": true}
        },
        {
          "type": "bandwidth",
          "capabilities": {"bandwidth": true}
        }
      ]
    }
# Enable IPIP
- name: CALICO_IPV4POOL_IPIP
    value: "Always" >> Set this to 'Never' to disable IP-IP
# Enable or Disable VXLAN on the default IP pool.
- name: CALICO_IPV4POOL_VXLAN
    value: "Never"
```

安装完毕之后，检查 Pod 和节点状态。

```bash
$ kubectl get pods --all-namespaces
NAMESPACE     NAME                                       READY   STATUS              RESTARTS   AGE
kube-system   calico-kube-controllers-799fb94867-6qj77   0/1     ContainerCreating   0          21s
kube-system   calico-node-bzttq                          0/1     PodInitializing     0          21s
kube-system   calico-node-r6bwj                          0/1     PodInitializing     0          21s
kube-system   coredns-66bff467f8-52tkd                   0/1     Pending             0          7m5s
kube-system   coredns-66bff467f8-g5gjb                   0/1     ContainerCreating   0          7m5s
kube-system   etcd-controlplane                          1/1     Running             0          7m7s
kube-system   kube-apiserver-controlplane                1/1     Running             0          7m7s
kube-system   kube-controller-manager-controlplane       1/1     Running             0          7m7s
kube-system   kube-proxy-b2j4x                           1/1     Running             0          6m46s
kube-system   kube-proxy-s46lv                           1/1     Running             0          7m5s
kube-system   kube-scheduler-controlplane                1/1     Running             0          7m6s
$ kubectl get nodes
NAME           STATUS   ROLES    AGE     VERSION
controlplane   Ready    master   7m30s   v1.18.0
node01         Ready    <none>   6m59s   v1.18.0
```

Kubelet 需要 CNI 的配置文件来设置网络：

```bash
$ cd /etc/cni/net.d/
$ ls
10-calico.conflist  calico-kubeconfig
$
$
$ cat 10-calico.conflist
{
  "name": "k8s-pod-network",
  "cniVersion": "0.3.1",
  "plugins": [
    {
      "type": "calico",
      "log_level": "info",
      "log_file_path": "/var/log/calico/cni/cni.log",
      "datastore_type": "kubernetes",
      "nodename": "controlplane",
      "mtu": 1440,
      "ipam": {
          "type": "calico-ipam"
      },
      "policy": {
          "type": "k8s"
      },
      "kubernetes": {
          "kubeconfig": "/etc/cni/net.d/calico-kubeconfig"
      }
    },
    {
      "type": "portmap",
      "snat": true,
      "capabilities": {"portMappings": true}
    },
    {
      "type": "bandwidth",
      "capabilities": {"bandwidth": true}
    }
  ]
}
```

检查 CNI 的二进制文件：

```bash
$ ls
bandwidth  bridge  calico  calico-ipam dhcp  flannel  host-device  host-local  install  ipvlan  loopback  macvlan  portmap  ptp  sample  tuning  vlan
```

安装 `calicoctl` 来获取 Calico 的更多信息并能修改 Calico 配置：

```bash
$ cd /usr/local/bin/
$ curl -O -L  https://github.com/projectcalico/calicoctl/releases/download/v3.16.3/calicoctl
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   633  100   633    0     0   3087      0 --:--:-- --:--:-- --:--:--  3087
100 38.4M  100 38.4M    0     0  5072k      0  0:00:07  0:00:07 --:--:-- 4325k
$ chmod +x calicoctl
$ export DATASTORE_TYPE=kubernetes
$ export KUBECONFIG=~/.kube/config
# Check endpoints - it will be empty as we have't deployed any POD
$ calicoctl get workloadendpoints
WORKLOAD   NODE   NETWORKS   INTERFACE
```

检查 BGP Peer 的状态，会看到 Worker 节点是一个 Peer。

```bash
$ calicoctl node status
Calico process is running.
IPv4 BGP status
+--------------+-------------------+-------+----------+-------------+
| PEER ADDRESS |     PEER TYPE     | STATE |  SINCE   |    INFO     |
+--------------+-------------------+-------+----------+-------------+
| 172.17.0.40  | node-to-node mesh | up    | 00:24:04 | Established |
+--------------+-------------------+-------+----------+-------------+
```

创建一个两副本 Pod，并设置 `tolerations`，使之可以运行在 Master 节点：

```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: busybox-deployment
spec:
  selector:
    matchLabels:
      app: busybox
  replicas: 2
  template:
    metadata:
      labels:
        app: busybox
    spec:
      tolerations:
      - key: "node-role.kubernetes.io/master"
        operator: "Exists"
        effect: "NoSchedule"
      containers:
      - name: busybox
        image: busybox
        command: ["sleep"]
        args: ["10000"]
```

获取 Pod 和端点状态：

```bash
$ kubectl get pods -o wide
NAME                                 READY   STATUS    RESTARTS   AGE   IP                NODE           NOMINATED NODE   READINESS GATES
busybox-deployment-8c7dc8548-btnkv   1/1     Running   0          6s    192.168.196.131   node01         <none>           <none>
busybox-deployment-8c7dc8548-x6ljh   1/1     Running   0          6s    192.168.49.66     controlplane   <none>           <none>
$ calicoctl get workloadendpoints
WORKLOAD                             NODE           NETWORKS             INTERFACE
busybox-deployment-8c7dc8548-btnkv   node01         192.168.196.131/32   calib673e730d42
busybox-deployment-8c7dc8548-x6ljh   controlplane   192.168.49.66/32     cali9861acf9f07
```

获取 Pod 所在主机上的 VETH 信息：

```bash
$ ifconfig cali9861acf9f07
cali9861acf9f07: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1440
        inet6 fe80::ecee:eeff:feee:eeee  prefixlen 64  scopeid 0x20<link>
        ether ee:ee:ee:ee:ee:ee  txqueuelen 0  (Ethernet)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 5  bytes 446 (446.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
```

获取 Pod 网络界面的信息：

```bash
$ kubectl exec busybox-deployment-8c7dc8548-x6ljh -- ifconfig
eth0      Link encap:Ethernet  HWaddr 92:7E:C4:15:B9:82
          inet addr:192.168.49.66  Bcast:192.168.49.66  Mask:255.255.255.255
          UP BROADCAST RUNNING MULTICAST  MTU:1440  Metric:1
          RX packets:5 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:446 (446.0 B)  TX bytes:0 (0.0 B)
lo        Link encap:Local Loopback
          inet addr:127.0.0.1  Mask:255.0.0.0
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)
$ kubectl exec busybox-deployment-8c7dc8548-x6ljh -- ip route
default via 169.254.1.1 dev eth0
169.254.1.1 dev eth0 scope link
$ kubectl exec busybox-deployment-8c7dc8548-x6ljh -- arp
```

获取主节点路由：

```bash
$ ip route
default via 172.17.0.1 dev ens3
172.17.0.0/16 dev ens3 proto kernel scope link src 172.17.0.32
172.18.0.0/24 dev docker0 proto kernel scope link src 172.18.0.1 linkdown
blackhole 192.168.49.64/26 proto bird
192.168.49.65 dev calic22dbe57533 scope link
192.168.49.66 dev cali9861acf9f07 scope link
192.168.196.128/26 via 172.17.0.40 dev tunl0 proto bird onlink
```

尝试 Ping Worker 节点来触发 ARP：

```bash
$ kubectl exec busybox-deployment-8c7dc8548-x6ljh -- ping 192.168.196.131 -c 1
PING 192.168.196.131 (192.168.196.131): 56 data bytes
64 bytes from 192.168.196.131: seq=0 ttl=62 time=0.823 ms
$ kubectl exec busybox-deployment-8c7dc8548-x6ljh -- arp
? (169.254.1.1) at ee:ee:ee:ee:ee:ee [ether]  on eth0
```

注意上面的 MAC 地址。发出流量时，内核根据 IP 路由将数据包写入 `tunl0`，Proxy ARP 的配置：

```bash
$ cat /proc/sys/net/ipv4/conf/cali9861acf9f07/proxy_arp
1
```

## 目标节点如何处理数据包

```bash
node01 $ ip route
default via 172.17.0.1 dev ens3
172.17.0.0/16 dev ens3 proto kernel scope link src 172.17.0.40
172.18.0.0/24 dev docker0 proto kernel scope link src 172.18.0.1 linkdown
192.168.49.64/26 via 172.17.0.32 dev tunl0 proto bird onlink
blackhole 192.168.196.128/26 proto bird
192.168.196.129 dev calid4f00d97cb5 scope link
192.168.196.130 dev cali257578b48b6 scope link
192.168.196.131 dev calib673e730d42 scope link
```

接收到数据包之后，内核会根据路由表将数据包发给对应的 `veth`。

如果抓包的话会看出 IP-IP 协议。据我所知，Azure 不支持 IP-IP，也就是说我们无法在这种环境里使用 IP-IP。关闭 IP-IP 能获得更高性能，下面一节尝试一下。

### 禁用 IP-IP

更新 `ippool.yaml` 设置 IPIP 为 `Never`，然后用 `calicoctl` 应用配置：

```bash
$ calicoctl get ippool default-ipv4-ippool -o yaml > ippool.yaml
$ vi ippool.yaml
...
$ calicoctl apply -f ippool.yaml
Successfully applied 1 'IPPool' resource(s)
```

再次检查 `ip route`：

```bash
$ ip route
default via 172.17.0.1 dev ens3
172.17.0.0/16 dev ens3 proto kernel scope link src 172.17.0.32
172.18.0.0/24 dev docker0 proto kernel scope link src 172.18.0.1 linkdown
blackhole 192.168.49.64/26 proto bird
192.168.49.65 dev calic22dbe57533 scope link
192.168.49.66 dev cali9861acf9f07 scope link
192.168.196.128/26 via 172.17.0.40 dev ens3 proto bird
```

设备不再是 `tunl0`，而是变成 Master 节点的管理界面（`ens3`）。

Ping 一下 Worker 节点，验证工作情况，此时不再使用 IPIP 协议：

```bash
$ kubectl exec busybox-deployment-8c7dc8548-x6ljh -- ping 192.168.196.131 -c 1
PING 192.168.196.131 (192.168.196.131): 56 data bytes
64 bytes from 192.168.196.131: seq=0 ttl=62 time=0.653 ms
--- 192.168.196.131 ping statistics ---
1 packets transmitted, 1 packets received, 0% packet loss
round-trip min/avg/max = 0.653/0.653/0.653 ms
```

> 注意在 AWS 环境中使用这种模式需要禁用源 IP 检查。

### 演示 VXLAN

重新进行集群初始化，并下载 `calico.yaml` 文件，进行如下变更：

从 `livenessProbe` 和 `readinessProbe` 中删除 `bird`：

```yaml
livenessProbe:
            exec:
              command:
              - /bin/calico-node
              - -felix-live
              - -bird-live >> Remove this
            periodSeconds: 10
            initialDelaySeconds: 10
            failureThreshold: 6
          readinessProbe:
            exec:
              command:
              - /bin/calico-node
              - -felix-ready
              - -bird-ready >> Remove this
```

把 `calico_backend` 修改为 `vxlan`，不再需要 BGP：

```yaml
kind: ConfigMap
apiVersion: v1
metadata:
  name: calico-config
  namespace: kube-system
data:
  # Typha is disabled.
  typha_service_name: "none"
  # Configure the backend to use.
  calico_backend: "vxlan"
```

禁用 IPIP：

```yaml
# Enable IPIP
- name: CALICO_IPV4POOL_IPIP
    value: "Never" >> Set this to 'Never' to disable IP-IP
# Enable or Disable VXLAN on the default IP pool.
- name: CALICO_IPV4POOL_VXLAN
    value: "Never"
```

应用这个 YAML：

```yaml
$ ip route
default via 172.17.0.1 dev ens3
172.17.0.0/16 dev ens3 proto kernel scope link src 172.17.0.15
172.18.0.0/24 dev docker0 proto kernel scope link src 172.18.0.1 linkdown
192.168.49.65 dev calif5cc38277c7 scope link
192.168.49.66 dev cali840c047460a scope link
192.168.196.128/26 via 192.168.196.128 dev vxlan.calico onlink
vxlan.calico: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1440
        inet 192.168.196.128  netmask 255.255.255.255  broadcast 192.168.196.128
        inet6 fe80::64aa:99ff:fe2f:dc24  prefixlen 64  scopeid 0x20<link>
        ether 66:aa:99:2f:dc:24  txqueuelen 0  (Ethernet)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 11 overruns 0  carrier 0  collisions 0
```

获取 Pod 状态：

```bash
$ kubectl get pods -o wide
NAME                                 READY   STATUS    RESTARTS   AGE   IP                NODE           NOMINATED NODE   READINESS GATES
busybox-deployment-8c7dc8548-8bxnw   1/1     Running   0          11s   192.168.49.67     controlplane   <none>           <none>
busybox-deployment-8c7dc8548-kmxst   1/1     Running   0          11s   192.168.196.130   node01         <none>           <none>
```

查看 `ip route`：

```bash
$ kubectl exec busybox-deployment-8c7dc8548-8bxnw -- ip route
default via 169.254.1.1 dev eth0
169.254.1.1 dev eth0 scope link
```

执行 Ping，触发 ARP 查询：

```bash
$ kubectl exec busybox-deployment-8c7dc8548-8bxnw -- arp
master $ kubectl exec busybox-deployment-8c7dc8548-8bxnw -- ping 8.8.8.8
PING 8.8.8.8 (8.8.8.8): 56 data bytes
64 bytes from 8.8.8.8: seq=0 ttl=116 time=3.786 ms
^C
$ kubectl exec busybox-deployment-8c7dc8548-8bxnw -- arp
? (169.254.1.1) at ee:ee:ee:ee:ee:ee [ether]  on eth0
```

概念和前一种模式相似，区别在于数据包抵达 `vxland` 的时候，会把节点 IP 以及 MAC 地址封装并发送。另外 `vxland` 的 UDP 端口是 4789。这里会从 etcd 获取可用节点以及节点支持的 IP 范围，从而让 `vxlan-calico` 据此构建数据包。

> VxLan 模式需要更多系统开销
> 
> ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1745924051241/21a26929-bc20-4760-9d2b-548862579d9b.png align="center")

## 声明

本文未提供任何技术建议和推荐，文中所述皆为个人观点，不代表我所供职的企业。
