kubernetes(K8s)学习笔记(第八期):集群治理与控制(上篇):网络策略——NetworkPolicy

本笔记为 Kubernetes 系列第八期,聚焦集群网络安全的核心机制——NetworkPolicy。涵盖:Kubernetes 网络基础(单主机/跨主机、CNM vs CNI)、网络策略规约详解、四种选择器、多个实战实验(Pod 标签/Namespace/IP 段限定)、默认策略配置。所有命令和 YAML 示例均已经过整理和注释。全文约 3200 字,包含 12 个 YAML 示例30+ 命令示例10 张对比表格,是 Kubernetes 网络安全的入门指南。

— Compiled and Authored by Whisky — June 30th, 2026

目录

  1. Kubernetes 网络基础
  2. 网络策略概述
  3. 网络策略规约详解
  4. 网络策略实战实验
  5. 默认策略
  6. 总结与知识点一览表

一、Kubernetes 网络基础

在理解网络策略之前,先回顾 Kubernetes 网络的基本原理。

1.1 单主机网络通信

无论是 Docker 还是 Containerd,容器网络接口默认都是虚拟接口。Linux 内核通过 veth pair(虚拟以太网对)技术,在宿主机和容器之间建立通信通道。

核心原理:数据包在宿主机内核中直接复制,不经过外部物理网络设备,因此转发效率极高。

以 Docker 为例:

  • Docker 服务默认创建 docker0 Linux 网桥
  • 每个容器有一个虚拟接口(eth0)连接到网桥
  • 宿主机和容器之间通过 veth pair 通信

Containerd 的网络模型与 Docker 类似,使用 nerdctl0 网桥。

1.2 跨主机网络通信

跨主机容器通信有两大方案:

方案 原理 代表技术
Overlay 网络 建立主机间 VxLAN 隧道,封装数据包 Flannel(vxlan)、Weave
Underlay 网络 依赖三层 IP 转发,不封装数据包 Flannel(host-gw)、Calico

性能对比

  • Underlay 网络性能优于 Overlay 网络(无需封装/解封装)
  • Overlay 网络支持更多二层网段,避免物理交换机 MAC 表耗尽

选型建议:若追求性能且网络环境支持三层互通,优先选择 Calico(BGP 模式);若需要跨子网通信且对性能要求不高,Overlay 方案更灵活。

1.3 CNM vs CNI

容器网络模型经历了两个重要标准:

特点 CNM(Container Network Model) CNI(Container Network Interface)
提出方 Docker 公司 Google + CoreOS
最小单元 容器 Pod
守护进程 依赖 dockerd 不依赖任何守护进程
扩展性 被 Docker 绑定 插件可随意替换
适用平台 Docker Kubernetes

关键理解:Kubernetes 采用 CNI 标准,这也是为什么我们可以灵活选择 Calico、Flannel、Weave 等不同网络插件。

1.4 Kubernetes 网络模型核心要求

Kubernetes 对网络模型有四个基本要求(源自 CNI 规范):

  1. 所有 Pod 可以不经过 NAT 直接通信
  2. 所有节点可以不经过 NAT 直接与所有 Pod 通信
  3. Pod 看到的自身 IP 与其他 Pod 看到的一致
  4. 每个 Pod 拥有独立的 IP 地址

这些要求确保了网络行为的可预测性,也为 NetworkPolicy 的实现奠定了基础。

二、网络策略概述

2.1 默认网络行为

默认情况下,Kubernetes 集群的网络连通性是全开放的:

  • 集群外部主机可以访问集群内部应用(通过 NodePort/LoadBalancer)
  • 集群内部应用可以访问集群外部主机
  • 各个 Namespace 之间没有做任何隔离策略

这意味着:任何 Pod 可以与集群中的任何其他 Pod 通信。这在生产环境中存在安全隐患。

2.2 什么是网络策略?

NetworkPolicy 是 Kubernetes 用于控制 Pod 之间网络通信的 API 对象。它允许你在 IP 地址或端口层面定义哪些流量被允许、哪些被拒绝。

  • NetworkPolicy 是一种以应用为中心的结构
  • 适用于一端或两端与 Pod 的连接
  • 前提条件:必须使用支持 NetworkPolicy 的网络插件(如 Calico)

通俗理解:NetworkPolicy 就像 Pod 的“防火墙规则”——你告诉 Kubernetes“谁可以访问我、我可以访问谁”,Kubernetes 在网络层执行这些规则。

2.3 两种隔离类型

隔离类型 方向 默认行为 受 NetworkPolicy 影响后
入口隔离(Ingress) 流入 Pod 允许所有入站连接 仅允许策略中指定的连接
出口隔离(Egress) 流出 Pod 允许所有出站连接 仅允许策略中指定的连接

2.4 关键原则:策略是相加的

NetworkPolicy 是相加的,不会产生冲突。 如果多个策略适用于同一个 Pod,所有策略允许的连接的并集就是最终生效的规则。

重要:要允许从源 Pod 到目的 Pod 的连接,源 Pod 的出口策略目的 Pod 的入口策略都需要允许连接。任何一方不允许,连接都会失败。

三、网络策略规约详解

3.1 完整 YAML 示例

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: test-network-policy
  namespace: default
spec:
  podSelector:
    matchLabels:
      role: db
  policyTypes:
  - Ingress
  - Egress
  ingress:
  - from:
    - ipBlock:
        cidr: 172.17.0.0/16
        except:
        - 172.17.1.0/24
    - namespaceSelector:
        matchLabels:
          project: myproject
    - podSelector:
        matchLabels:
          role: frontend
    ports:
    - protocol: TCP
      port: 6379
  egress:
  - to:
    - ipBlock:
        cidr: 10.0.0.0/24
    ports:
    - protocol: TCP
      port: 5978

3.2 核心字段详解

字段 说明
spec.podSelector 策略适用的 Pod。{} 表示命名空间中的所有 Pod
spec.policyTypes Ingress、Egress 或两者兼具。默认:有 Ingress 规则时自动包含 Ingress
spec.ingress 入站规则白名单。匹配 fromports 的流量才被允许
spec.egress 出站规则白名单。匹配 toports 的流量才被允许

3.3 四种选择器

选择器 作用 示例
podSelector 选择同一 Namespace 中的特定 Pod role: frontend
namespaceSelector 选择特定 Namespace 中的所有 Pod project: myproject
namespaceSelector + podSelector 选择特定 Namespace 中的特定 Pod 组合使用
ipBlock 选择特定 IP CIDR 范围(通常用于集群外部 IP) 172.17.0.0/16

组合示例

ingress:
- from:
  - namespaceSelector:
      matchLabels:
        user: alice
  - podSelector:
      matchLabels:
        role: client

含义:允许来自任何 Namespace 中标有 user=alice 的 Pod 的流量,来自本地 Namespace 中标有 role=client 的 Pod 的流量。

四、网络策略实战实验

4.1 实验环境准备

环境说明

  • namespace-web:web1、web2、test 三个 Pod
  • namespace-whisky:test 一个 Pod
  • 默认 Namespace 是 web
# 创建命名空间
root@master30:~# kubectl create ns web
root@master30:~# kubectl create ns whisky
root@master30:~# kubens web

# 创建 web1
root@master30:~# kubectl run web1 --image=nginx --image-pull-policy=IfNotPresent
root@master30:~# kubectl exec -it web1 -- bash -c 'echo Hello web1 > /usr/share/nginx/html/index.html'

# 创建 web2
root@master30:~# kubectl run web2 --image=nginx --image-pull-policy=IfNotPresent
root@master30:~# kubectl exec -it web2 -- bash -c 'echo Hello web2 > /usr/share/nginx/html/index.html'

# 创建 test(同一 Namespace)
root@master30:~# kubectl run test --image=busybox -- sleep 3600

# 在 whisky Namespace 创建 test(不同 Namespace)
root@master30:~# kubectl run test -n whisky --image=busybox -- sleep 3600

# 创建 Service(NodePort 用于外部访问验证)
root@master30:~# kubectl expose pod web1 --port=80 --target-port=80 --type=NodePort
root@master30:~# kubectl expose pod web2 --port=80 --target-port=80 --type=NodePort

4.2 实验一:根据 Pod 标签限定

目标:允许同一 Namespace 中具有标签 run: test 的 Pod 访问 web1 的 80 端口,其他 Pod 禁止。

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: my-network-policy
  namespace: web
spec:
  podSelector:
    matchLabels:
      run: web1
  policyTypes:
  - Ingress
  ingress:
  - from:
    - podSelector:
        matchLabels:
          run: test
    ports:
    - protocol: TCP
      port: 80
# 应用策略
root@master30:~# kubectl apply -f netpol.yaml

# 验证:test 可以访问 web1
root@master30:~# kubectl exec test -- wget -q -O- web1
Hello web1

# 验证:web2 无法访问 web1
root@master30:~# kubectl exec web2 -- wget -q -O- web1
wget: can't connect to remote host (10.103.36.143): Connection timed out

# 修改 test 的标签,使其不再匹配
root@master30:~# kubectl label pod test run=web2 --overwrite

# 再次验证:test 无法访问 web1
root@master30:~# kubectl exec test -- wget -q -O- web1
wget: can't connect to remote host (10.103.36.143): Connection timed out

关键理解:NetworkPolicy 通过标签选择器动态匹配 Pod。当 Pod 标签变更时,策略实时生效,无需重启 Pod 或重新应用策略。

4.3 实验二:根据 Namespace 限定

目标:允许具有标签 project: myproject 的 Namespace 中的所有 Pod 访问 web1

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: my-network-policy
  namespace: web
spec:
  podSelector:
    matchLabels:
      run: web1
  policyTypes:
  - Ingress
  ingress:
  - from:
    - namespaceSelector:
        matchLabels:
          project: myproject
    ports:
    - protocol: TCP
      port: 80
# 应用策略
root@master30:~# kubectl apply -f netpol.yaml

# 验证:web 命名空间中的 Pod 无法访问
root@master30:~# kubectl exec test -- wget -q -O- web1
wget: can't connect...

# 给 whisky 命名空间添加标签
root@master30:~# kubectl label namespace whisky project=myproject

# 验证:whisky 命名空间中的 Pod 可以访问
root@master30:~# kubectl exec -n whisky test -- wget -q -O- web1.web
Hello web1

4.4 实验三:根据 IP 段限定

目标:允许 10.1.8.0/24 网段(但不包括 10.1.8.128/26 子网)访问 web1

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: my-network-policy
  namespace: web
spec:
  podSelector:
    matchLabels:
      run: web1
  policyTypes:
  - Ingress
  ingress:
  - from:
    - ipBlock:
        cidr: 10.1.8.0/24
        except:
        - 10.1.8.128/26
    ports:
    - protocol: TCP
      port: 80
# 应用策略
root@master30:~# kubectl apply -f netpol.yaml

# 验证:节点 IP 在允许范围内可以访问
root@client:~# curl http://10.1.8.30:30790   # 取决于 nodePort
Hello web1

⚠️ 注意:ipBlock 策略对集群外部访问 NodePort 的实际效果取决于流量来源 IP。实验中通过节点 IP 访问时,源 IP 会被 SNAT 转换,因此建议在验证时使用 Pod IP 直连测试。

4.5 实验四:限定所有端口

目标:允许特定 Pod 访问 web1所有端口(不限制端口范围)。

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: my-network-policy
  namespace: web
spec:
  podSelector:
    matchLabels:
      run: web1
  policyTypes:
  - Ingress
  ingress:
  - from:
    - podSelector:
        matchLabels:
          run: test
    # 不指定 ports → 允许所有端口
# 应用策略
root@master30:~# kubectl apply -f netpol.yaml

# 验证:可以 ping 通 Pod IP(ICMP 协议不经过端口)
root@master30:~# kubectl get pod web1 -o wide
web1   1/1     Running   0   82m   10.224.193.67

root@master30:~# kubectl run --rm -it ubuntu -l run=test --image=ubuntu -- bash
root@ubuntu:/# apt update && apt install -y iputils-ping
root@ubuntu:/# ping -c1 10.224.193.67
PING 10.224.193.67 (10.224.193.67) 56(84) bytes of data.
64 bytes from 10.224.193.67: icmp_seq=1 ttl=62 time=0.831 ms

4.6 实验五:限定端口范围

目标:允许访问 web132000-32768 端口范围。

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: my-network-policy
  namespace: web
spec:
  podSelector:
    matchLabels:
      run: web1
  policyTypes:
  - Ingress
  ingress:
  - from:
    - podSelector:
        matchLabels:
          run: test
    ports:
    - protocol: TCP
      port: 32000
      endPort: 32768

说明endPort 支持指定端口范围,适用于 NodePort 等需要开放端口的场景。此特性需要 Kubernetes 1.24+ 版本支持。

五、默认策略

5.1 默认允许所有入站流量

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-all-ingress
spec:
  podSelector: {}
  policyTypes:
  - Ingress
  ingress:
  - {}

5.2 默认拒绝所有入站流量

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-ingress
spec:
  podSelector: {}
  policyTypes:
  - Ingress

5.3 默认允许所有出站流量

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-all-egress
spec:
  podSelector: {}
  policyTypes:
  - Egress
  egress:
  - {}

5.4 默认拒绝所有出站流量

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-egress
spec:
  podSelector: {}
  policyTypes:
  - Egress

5.5 默认拒绝所有入口和出口流量

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-all
spec:
  podSelector: {}
  policyTypes:
  - Ingress
  - Egress

生产推荐:在关键 Namespace 中部署 default-deny-all 策略,然后按需添加允许策略(白名单模式),实现零信任网络隔离。

六、总结与知识点一览表

6.1 NetworkPolicy 核心字段速查

字段 作用 示例
podSelector 策略作用的 Pod 范围 matchLabels: {role: db}
policyTypes 策略类型 [Ingress, Egress]
ingress.from 允许的入站来源 podSelector / namespaceSelector / ipBlock
ingress.ports 允许的入站端口 {protocol: TCP, port: 80}
egress.to 允许的出站目标 ipBlock: {cidr: 10.0.0.0/24}
egress.ports 允许的出站端口 {protocol: TCP, port: 443}

6.2 四种选择器对比

选择器 匹配范围 适用场景
podSelector 同一 Namespace 的特定 Pod 微服务间访问控制
namespaceSelector 特定 Namespace 的所有 Pod 多租户隔离
namespaceSelector + podSelector 特定 Namespace 的特定 Pod 精确控制
ipBlock 特定 IP 段(含 except) 集群外部来源控制

6.3 默认策略模板一览

场景 模板
允许所有入站 ingress: [{}]
拒绝所有入站 不指定 ingress
允许所有出站 egress: [{}]
拒绝所有出站 不指定 egress
完全隔离 policyTypes: [Ingress, Egress],不指定规则

6.4 常见错误排查

错误现象 可能原因 解决方法
策略不生效 网络插件不支持 NetworkPolicy 确认使用 Calico 等支持 NetworkPolicy 的插件
Pod 无法访问 入口/出口策略未同时允许 检查源 Pod 出口策略和目的 Pod 入口策略
ipBlock 不生效 流量来源 IP 被 SNAT 检查实际来源 IP,使用 Pod IP 直连测试
策略冲突 误以为策略是拒绝的 记住策略是相加的,只能添加允许规则

6.5 生产环境最佳实践

  1. 启用网络策略前:确保使用支持 NetworkPolicy 的网络插件(如 Calico)
  2. 采用白名单模式:先部署 default-deny-all,再按需开放
  3. 命名空间级别隔离:在不同 Namespace 中部署不同的默认策略
  4. 监控策略影响:使用网络策略可视化工具(如 Calico Cloud 或 Cilium Hubble)
  5. 逐步推广:先在测试环境验证策略,再逐步应用到生产环境

下一期预告:kubernetes(K8s)学习笔记:集群治理与控制(下篇):调度与节点管理——Scheduler + 污点容忍 + 节点维护。涵盖:kube-scheduler 调度过程、nodeName/nodeSelector/亲和性控制 Pod 位置、污点与容忍度、cordon/drain 节点维护操作。

— Compiled and Authored by Whisky — June 30th, 2026
Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐