## 9.7 容器网络高级特性

深入探讨容器网络的核心机制、Overlay 网络、CNI 插件生态、容器 DNS 解析、网络策略等高级特性，为生产级别的网络架构打下坚实基础。

### 9.7.1 Overlay 网络原理与配置

Overlay 网络在现有网络基础上建立虚拟网络，允许容器跨宿主机通信。它是 Kubernetes 和 Swarm 模式的基础。

#### Overlay 网络工作原理

Overlay 网络通过隧道封装技术（通常是 VXLAN）将容器网络流量封装在宿主机物理网络的 UDP 数据包中传输。

```
容器 A (192.168.0.2)
    ↓
veth 对
    ↓
br-net (网桥)
    ↓
Docker 引擎 (VXLAN 封装)
    ↓
物理网络 (172.16.0.0/24)
    ↓
Docker 引擎 (VXLAN 解封装)
    ↓
br-net (网桥)
    ↓
veth 对
    ↓
容器 B (192.168.0.3，不同宿主机)
```

#### 创建和使用 Overlay 网络

**Docker Swarm 模式下的 Overlay 网络：**

```bash
# 初始化 Swarm（创建集群）
docker swarm init

# 创建 overlay 网络
docker network create --driver overlay \
  --subnet 192.168.0.0/24 \
  --opt com.docker.network.driver.mtu=1450 \
  my-overlay-net

# 验证网络创建
docker network ls
docker network inspect my-overlay-net

# 在 Swarm 服务中使用 overlay 网络
docker service create --name web \
  --network my-overlay-net \
  --replicas 3 \
  nginx:latest

# 验证服务跨节点通信
docker service ps web
```

**单机 Overlay 网络模拟（Linux 容器）：**

```bash
# 创建自定义 overlay 网络
docker network create --driver overlay custom-overlay

# 创建两个容器
docker run -d --name container1 --network custom-overlay nginx:latest
docker run -d --name container2 --network custom-overlay nginx:latest

# 测试跨容器通信
docker exec container1 ping container2
docker exec container1 curl http://container2

# 检查网络配置
docker network inspect custom-overlay
```

#### Overlay 网络性能优化

```bash
# 调整 MTU（Maximum Transmission Unit）避免分片
# VXLAN 开销 50 字节，物理 MTU 1500，建议设置为 1450
docker network create --driver overlay \
  --opt com.docker.network.driver.mtu=1450 \
  optimized-overlay

# 启用 IP 地址管理（IPAM）自定义
docker network create --driver overlay \
  --subnet 10.0.9.0/24 \
  --aux-address "my-router=10.0.9.2" \
  my-custom-overlay

# 在 Compose 中使用 overlay 网络
version: '3.9'
services:
  web:
    image: nginx
    networks:
      - backend

  db:
    image: postgres
    networks:
      - backend

networks:
  backend:
    driver: overlay
    driver_opts:
      com.docker.network.driver.mtu: 1450
```

### 9.7.2 CNI 插件生态概览

容器网络接口（CNI）是容器编排平台（尤其是 Kubernetes）的标准化网络接口。不同的 CNI 插件提供不同的网络能力。

#### 主流 CNI 插件对比

**Calico - 基于 BGP 的网络**

Calico 使用 BGP 协议进行路由，支持网络策略和 eBPF 加速。

```yaml
# Kubernetes 中安装 Calico
apiVersion: v1
kind: ConfigMap
metadata:
  name: calico-config
  namespace: kube-system
data:
  cni_network_config: |
    {
      "name": "k8s-pod-network",
      "cniVersion": "0.4.0",
      "plugins": [
        {
          "type": "calico",
          "datastore_type": "kubernetes",
          "mtu": 1450,
          "ipam": {
            "type": "calico-ipam"
          }
        },
        {
          "type": "portmap",
          "snat": true,
          "capabilities": {"portMappings": true}
        }
      ]
    }
```

**Flannel - 简单可靠的 Overlay**

Flannel 提供简单的 overlay 网络实现，适合小到中等规模的集群。

```bash
# 安装 Flannel
kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml

# 配置 Flannel 后端（VXLAN、UDP、AWS VPC 等）
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: ConfigMap
metadata:
  name: kube-flannel-cfg
  namespace: kube-flannel
data:
  cni-conf.json: |
    {
      "name": "cbr0",
      "cniVersion": "0.3.1",
      "plugins": [
        {
          "type": "flannel",
          "delegate": {
            "hairpinMode": true,
            "isDefaultGateway": true
          }
        },
        {
          "type": "portmap",
          "capabilities": {
            "portMappings": true
          }
        }
      ]
    }
  net-conf.json: |
    {
      "Network": "10.244.0.0/16",
      "Backend": {
        "Type": "vxlan"
      }
    }
EOF
```

**Cilium - eBPF 驱动的先进网络**

Cilium 使用 eBPF 在内核级别实现网络策略和可观测性，性能优异。

```bash
# 安装 Cilium
helm repo add cilium https://helm.cilium.io
helm install cilium cilium/cilium \
  --namespace kube-system \
  --set image.tag=v1.14.0 \
  --set operator.replicas=1

# 启用 Hubble（可观测性）
helm upgrade cilium cilium/cilium \
  --namespace kube-system \
  --reuse-values \
  --set hubble.enabled=true \
  --set hubble.ui.enabled=true
```

**Weave - 跨主机网络通信**

Weave 提供简单的跨主机通信，支持加密和多播。

```bash
# Docker 中使用 Weave 网络
docker run -d --name weave \
  --net=host \
  --cap-add=NET_ADMIN \
  --cap-add=SYS_PTRACE \
  ghcr.io/weaveworks/weave:latest

# 连接到 Weave 网络
docker run -d --network weave --name web nginx:latest
```

**CNI 插件对比表：**

| 特性 | Calico | Flannel | Cilium | Weave |
|------|--------|---------|--------|-------|
| 路由方式 | BGP | VXLAN/UDP | eBPF | VxLAN |
| 网络策略 | ✓ | ✗ | ✓ (L3-L7) | ✗ |
| 性能 | ⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ |
| 可观测性 | 中 | 低 | ⭐⭐⭐⭐⭐ | 中 |
| 学习曲线 | 中 | 低 | 高 | 低 |
| 生产就绪 | ✓ | ✓ | ✓ | ✓ |

### 9.7.3 容器 DNS 解析机制

Docker 内置 DNS 服务器，但 DNS 解析涉及多个层面的配置。

#### DNS 解析流程

```
容器应用 (dig www.example.com)
    ↓
容器内 /etc/resolv.conf (127.0.0.11:53)
    ↓
Docker 内嵌 DNS 服务器 (127.0.0.11)
    ↓
用户自定义 DNS 或宿主机 /etc/resolv.conf
    ↓
外部 DNS 服务器 (8.8.8.8 等)
    ↓
DNS 响应 → 容器缓存 → 应用
```

#### 配置容器 DNS

**在运行时指定 DNS：**

```bash
# 单个容器
docker run -d \
  --dns 8.8.8.8 \
  --dns 1.1.1.1 \
  --dns-search example.com \
  nginx:latest

# DNS 选项
docker run -d \
  --dns-option ndots:2 \
  --dns-option timeout:1 \
  --dns-option attempts:3 \
  nginx:latest

# 查看容器 DNS 配置
docker exec <container_id> cat /etc/resolv.conf
```

**Docker Compose DNS 配置：**

```yaml
version: '3.9'

services:
  web:
    image: nginx
    dns:
      - 8.8.8.8
      - 1.1.1.1
    dns_search:
      - example.com
      - local

  db:
    image: postgres
    networks:
      - backend
    hostname: postgres-db

networks:
  backend:
    driver: bridge

# 容器内 /etc/resolv.conf 将被自动配置
# search example.com local
# nameserver 8.8.8.8
# nameserver 1.1.1.1
```

**Docker 守护进程级别配置：**

```json
{
  "dns": ["8.8.8.8", "1.1.1.1"],
  "dns-search": ["example.com"],
  "insecure-registries": [],
  "registry-mirrors": ["https://mirror.example.com"]
}
```

#### 自定义服务发现（Service Discovery）

**使用 Docker 内建 DNS 的服务发现：**

```bash
# 创建自定义网络
docker network create mynet

# 运行服务
docker run -d --name web --network mynet nginx:latest
docker run -d --name db --network mynet postgres:latest

# 在其他容器中通过服务名访问
docker run -it --network mynet busybox sh
# ping web  # 自动解析到 web 容器 IP
# ping db   # 自动解析到 db 容器 IP
```

**Compose 服务名自动发现：**

```yaml
version: '3.9'

services:
  frontend:
    image: nginx
    depends_on:
      - backend
    environment:
      BACKEND_URL: http://backend:8080

  backend:
    image: myapp
    depends_on:
      - database

  database:
    image: postgres
    environment:
      POSTGRES_DB: mydb

# frontend 容器可以直接访问 http://backend:8080
# backend 容器可以直接访问 postgres://database:5432
```

#### DNS 性能优化

```bash
# 检查 DNS 延迟
time docker exec <container> nslookup www.example.com

# 优化 DNS 解析
docker run -d \
  --dns 127.0.0.1 \  # 使用本地缓存 DNS (Dnsmasq)
  nginx:latest

# 在 Kubernetes 中优化
kubectl patch deployment -n kube-system coredns --patch '{
  "spec": {
    "template": {
      "spec": {
        "containers": [
          {
            "name": "coredns",
            "resources": {
              "limits": {
                "memory": "512Mi",
                "cpu": "500m"
              }
            }
          }
        ]
      }
    }
  }
}'
```

### 9.7.4 网络策略（NetworkPolicy）实践

网络策略定义了容器间的流量控制规则，是微服务架构中的安全基础。

#### 基本网络策略

**默认拒绝所有入站流量的策略：**

```yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-ingress
  namespace: default
spec:
  podSelector: {}
  policyTypes:
  - Ingress
  # 不指定 ingress 规则，表示拒绝所有入站流量
```

**允许特定来源的入站流量：**

```yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-from-frontend
spec:
  podSelector:
    matchLabels:
      tier: backend
  policyTypes:
  - Ingress
  ingress:
  - from:
    - podSelector:
        matchLabels:
          tier: frontend
    ports:
    - protocol: TCP
      port: 8080
```

**允许出站流量到数据库：**

```yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-backend-to-db
spec:
  podSelector:
    matchLabels:
      tier: backend
  policyTypes:
  - Egress
  egress:
  # 允许到数据库的流量
  - to:
    - podSelector:
        matchLabels:
          tier: database
    ports:
    - protocol: TCP
      port: 5432
  # 允许 DNS 查询
  - to:
    - namespaceSelector: {}
    ports:
    - protocol: UDP
      port: 53
  # 允许到外部 API 的流量
  - to:
    - ipBlock:
        cidr: 0.0.0.0/0
        except:
        - 169.254.169.254/32  # 阻止元数据服务
    ports:
    - protocol: TCP
      port: 443
```

#### 微服务网络策略示例

```yaml
---
# 拒绝所有默认
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-all
spec:
  podSelector: {}
  policyTypes:
  - Ingress
  - Egress

---
# Frontend 容器策略
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-frontend
spec:
  podSelector:
    matchLabels:
      app: frontend
  policyTypes:
  - Ingress
  - Egress
  ingress:
  # 允许来自 Ingress Controller 的流量
  - from:
    - namespaceSelector:
        matchLabels:
          name: ingress-nginx
    - podSelector:
        matchLabels:
          app: ingress-controller
    ports:
    - protocol: TCP
      port: 3000
  egress:
  # 允许到 API 的流量
  - to:
    - podSelector:
        matchLabels:
          app: api
    ports:
    - protocol: TCP
      port: 8080
  # 允许 DNS
  - to:
    - namespaceSelector: {}
      podSelector:
        matchLabels:
          k8s-app: kube-dns
    ports:
    - protocol: UDP
      port: 53

---
# API 容器策略
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-api
spec:
  podSelector:
    matchLabels:
      app: api
  policyTypes:
  - Ingress
  - Egress
  ingress:
  - from:
    - podSelector:
        matchLabels:
          app: frontend
    ports:
    - protocol: TCP
      port: 8080
  egress:
  # 允许到数据库的流量
  - to:
    - podSelector:
        matchLabels:
          app: postgres
    ports:
    - protocol: TCP
      port: 5432
  # 允许 DNS
  - to:
    - namespaceSelector: {}
      podSelector:
        matchLabels:
          k8s-app: kube-dns
    ports:
    - protocol: UDP
      port: 53

---
# 数据库容器策略
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-postgres
spec:
  podSelector:
    matchLabels:
      app: postgres
  policyTypes:
  - Ingress
  ingress:
  - from:
    - podSelector:
        matchLabels:
          app: api
    ports:
    - protocol: TCP
      port: 5432
```

#### 使用 Calico/Cilium 的高级网络策略

**L7 应用层策略（仅 Cilium 支持）：**

```yaml
apiVersion: "cilium.io/v2"
kind: CiliumNetworkPolicy
metadata:
  name: "api-gateway-policy"
spec:
  description: "L7 policy for API gateway"
  endpointSelector:
    matchLabels:
      app: api
  ingress:
  - fromEndpoints:
    - matchLabels:
        app: frontend
    toPorts:
    - ports:
      - port: "8080"
        protocol: TCP
      rules:
        http:
        # 允许 GET /api/users
        - method: "GET"
          path: "/api/users/.*"
        # 允许 POST /api/users 仅从管理员来源
        - method: "POST"
          path: "/api/users"
          sourceIPs:
          - "10.0.0.0/8"
```

### 9.7.5 跨主机容器通信方案对比

#### 方案对比表

| 方案 | 隔离性 | 性能 | 复杂度 | 适用场景 |
|------|--------|------|--------|---------|
| 主机网络 | ✗ | ⭐⭐⭐⭐⭐ | 低 | 高性能，单主机 |
| Bridge + Host Port | 中 | ⭐⭐⭐⭐ | 低 | 小规模集群 |
| Overlay (VXLAN) | ✓ | ⭐⭐⭐ | 中 | 跨域通信 |
| BGP (Calico) | ✓ | ⭐⭐⭐⭐ | 中 | 大规模集群 |
| eBPF (Cilium) | ✓ | ⭐⭐⭐⭐⭐ | 高 | 高性能大集群 |

#### 选择建议

```bash
# 1. 开发环境：使用 Bridge 网络
docker network create my-app
docker-compose up  # 默认使用 bridge

# 2. 小规模生产（< 50 节点）：使用 Flannel
kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml

# 3. 中等规模（50-500 节点）：使用 Calico
kubeadm init --pod-network-cidr=192.168.0.0/16
kubectl apply -f https://docs.projectcalico.org/v3.24/manifests/tigera-operator.yaml

# 4. 大规模（> 500 节点）或需要 L7 策略：使用 Cilium
helm install cilium cilium/cilium --namespace kube-system

# 5. 需要多云/跨域：使用 Weave
```

### 9.7.6 网络故障排查

**常见网络问题诊断：**

```bash
# 1. 容器无法访问外部网络
docker exec <container> ping 8.8.8.8
docker exec <container> cat /etc/resolv.conf
docker logs <container> | grep -i network

# 2. 容器间无法通信
docker network inspect <network>
docker exec <container1> ping <container2>

# 3. 端口映射失效
docker port <container>
netstat -tlnp | grep <port>

# 4. DNS 解析失败
docker exec <container> nslookup example.com
docker exec <container> cat /etc/hosts

# 5. 网络延迟
docker run --rm --network host iperf3:latest -c <target>
docker exec <container> mtr -r example.com

# 使用 tcpdump 抓包分析
docker run --rm --cap-add NET_ADMIN --network host \
  corfr/tcpdump -i eth0 -n "port 80"
```
