## 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 < 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 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 ping 8.8.8.8 docker exec cat /etc/resolv.conf docker logs | grep -i network # 2. 容器间无法通信 docker network inspect docker exec ping # 3. 端口映射失效 docker port netstat -tlnp | grep # 4. DNS 解析失败 docker exec nslookup example.com docker exec cat /etc/hosts # 5. 网络延迟 docker run --rm --network host iperf3:latest -c docker exec mtr -r example.com # 使用 tcpdump 抓包分析 docker run --rm --cap-add NET_ADMIN --network host \ corfr/tcpdump -i eth0 -n "port 80" ```