k8s 网络模型和 CNI
参考资料
Kubernetes 网络模型由以下部分构成
- Pod IP 地址
- 每个 Pod 都有一个集群内唯一的 IP 地址
- Pod 内所有容器共享同一个网络命名空间,运行在同一个 Pod 中的不同容器的进程可通过
localhost互相通信
- Pod 网络(集群网络)
- 所有 Pod(无论是否在同一节点)默认可直接互通,无需 NAT 或代理。
- 注:Windows 上的 hostNetwork Pod 除外
- 节点上的系统组件(如 kubelet)也能与本节点上的所有 Pod 通信。
- Service
- 为一组动态变化的 Pod 提供稳定的访问入口(IP 或 DNS 名称)
- Kubernetes 自动维护 EndpointSlice,记录当前提供服务的 Pod
- kube-proxy(或云平台机制)负责将流量转发到后端 Pod
- 外部访问(Ingress / Gateway)
- 使用 Ingress 或新一代 Gateway API 可让集群外客户端访问 Service
- 也可通过
Service.type: LoadBalancer(需云厂商支持)快速暴露服务
- NetworkPolicy
- 内置 API,用于限制 Pod 之间的流量或 Pod 与外部的通信,实现网络隔离
Kubernetes 网络模型少部分由 Kubernetes 自身实现,其他部分由 Kubernetes 定义 API,但相应的功能由外部组件(CRI,CNI 插件,kube-proxy,Cilium,istio 等)提供
- Pod 网络命名空间:由容器运行时(符合 CRI)在系统层面创建
- Pod 网络通信:由 CNI 插件(即 Pod 网络实现)负责,在 Linux 上通常通过 CNI 接口集成
- Service 代理:Kubernetes 默认使用 kube-proxy,但一些网络方案(如 Cilium、Calico)提供自己的服务代理以更好集成
- NetworkPolicy:由支持该功能的 CNI 插件实现;若未启用或插件不支持,策略将无效(但 API 仍可用)
- Gateway API:有多种实现,适配不同环境(如云平台、裸机或通用场景)
容器网络接口(Container Network Interface, CNI)是一个由 CNCF 主导的轻量级、通用的规范和库,用于为容器配置网络
- 参考资料
- CNI 本身不是网络插件,而是一套 规范 + 参考库 + 工具集
- 真正的网络功能由 CNI 插件(Plugin) 实现,而 CNI 插件由容器运行时负责执行
- CNI 在容器创建时为其分配网络资源,在删除时释放资源
CNI 规范定义了以下五个部分
- 管理员用于定义网络配置的格式。
- 容器运行时向网络插件发出请求的协议。
- 根据提供的配置执行插件的程序。
- 插件将功能委托给其他插件的流程。
- 插件向运行时返回结果的数据类型
CNI 操作类型
- ADD:将容器添加到网络,或应用修改
- DEL:从网络中移除容器,或撤销修改
- CHECK:检查容器的网络连接是否正常
- VERSION:探测插件版本支持
- GC:清理所有过期资源
- STATUS:检查插件状态
CNI 团队维护的通用 CNI 插件
- 创建接口
- bridge
- host-device
- Moves an already-existing device into a container
- ipvlan
- macvlan
- vlan
- ptp
- Creates a veth pair
- IPAM: IP address allocation
- dhcp
- static
- host-local
- 维护已分配 IP 地址的本地数据库
- meta
- tuning
- 更改现有接口的 sysctl 参数
- portmap
- 一个基于 iptables 的端口映射插件。将主机地址空间中的端口映射到容器
- bandwidth
- 允许通过使用流量控制 tbf(入口/出口)来限制带宽
- sbr
- 一个为接口(它链接自该接口)配置基于源的路由的插件
- firewall
- win-spec
- win-bridge
- win-overlay
安装常用的 CNI 插件
- 选择一个即可
flannel:简单可靠的 Overlay 网络
calico:高性能、企业级网络与安全方案
kubectl create -f https://raw.githubusercontent.com/projectcalico/calico/v3.31.2/manifests/tigera-operator.yaml
kubectl create -f https://raw.githubusercontent.com/projectcalico/calico/v3.31.2/manifests/custom-resources.yaml
cilium:基于 eBPF 的下一代云原生网络
ciliumprojectCilium Quick Installation — Cilium 1.18.4 documentation
Cilium Quick Installation — Cilium 1.18.4 documentation
This guide will walk you through the quick default installation. It will automatically detect and use the best configuration possible for the Kubernetes distribution you are using. All state is stored using Kubernetes custom resource definitions (CRDs).
CNI 文件常见位置
- 配置文件位置
/etc/cni/net.d/
- 二进制文件位置
/opt/cni/bin/
k8s 节点需要的端口
控制平面
Protocol | Direction | Port Range | Purpose | Used By |
TCP | Inbound | 6443 | Kubernetes API server | All |
TCP | Inbound | 2379-2380 | etcd server client API | kube-apiserver, etcd |
TCP | Inbound | 10250 | Kubelet API | Self, Control plane |
TCP | Inbound | 10259 | kube-scheduler | Self |
TCP | Inbound | 10257 | kube-controller-manager | Self |
工作节点
Protocol | Direction | Port Range | Purpose | Used By |
TCP | Inbound | 10250 | Kubelet API | Self, Control plane |
TCP | Inbound | 10256 | kube-proxy | Self, Load balancers |
TCP | Inbound | 30000-32767 | NodePort Services† | All |
UDP | Inbound | 30000-32767 | NodePort Services† | All |
k8s 原生网络资源管理
参考资料
service 为一组 Pod 提供稳定的网络访问入口
service 核心功能
- 提供独立于 Pod 的网络层:Pod 会创建/销毁,但 Service 的 IP 和名称不变
- 服务发现:通过
<service-name>.<namespace>.svc.cluster.local访问服务 cluster.local在创建集群时也可以自定义
- 负载均衡:自动将流量分发到后端健康的 Pod。
service type 字段定义 service 类型
类型 | 说明 | 使用场景 |
ClusterIP(默认) | 仅在集群内部可访问(分配虚拟 IP) | 微服务间通信 |
NodePort | 在每个节点上开放一个固定端口(如 30001),外部可通过 http://<NodeIP>:30001 访问 | 开发测试、简单暴露 |
LoadBalancer | 云厂商自动创建外部负载均衡器(如 AWS ELB、GCP LB)并绑定公网 IP | 生产环境对外暴露 |
ExternalName | 将服务映射到外部 DNS 名称(如 my.db.example.com) | 访问集群外服务 |
- service selector 字段路由到具有与此 selector 匹配的标签键值对的 Pod
service ports 字段定义公开的端口列表
- port
- 公开的端口
- targetPort
- 在 Service 所针对的 Pod 上要访问的端口号或名称
- protocol
- 端口的 IP 协议,默认为 TCP
- 支持 TCP, UDP, SCTP
- name
- 端口的名称,所有端口的名称都必须唯一
- ports 字段仅有一个元素时该字段可选
- 在考虑 Service 的端点时,必须与 EndpointPort 中的
name字段相同
ClusterIP 为 None 时,DNS 如何自动配置取决于 Service 是否定义了 selector
- 注意:
ClusterIP: None不等于未设置 ClusterIP 字段
- 定义了 selector
- 创建 EndpointSlice 对象,并且修改 DNS 配置返回直接指向 Service 的后端 Pod 集合的 A 或 AAAA 记录(IPv4 或 IPv6 地址)
- 未定义 selector
- 没有 kube-proxy 参与转发,
port必须与targetPort匹配 - 此时不会创建 EndpointSlice 对象,需要手动配置同名的 EndpointSlice
- DNS 系统对于
type: ExternalNameService,查找和配置其 CNAME 记录 - 此时不用管 EndpointSlice
- 一般用于暴露集群外部的服务,为有状态应用提供稳定的 DNS 主机名
- DNS 系统针对同名的 EndpointSlice 的所有 IP 地址,查找和配置 DNS A / AAAA 记录
Headless Services 通过内部 DNS 记录报告各个 Pod 的端点 IP 地址
- 一种特殊的 ClusterIP 类型
- Headless Service 不会获得集群 IP,不会提供负载均衡或路由支持
设置 Headless Services 样例
clusterIP: None与未设置 clusterIP 不一样
一些特殊的 Service DNS 解析样例
- 参考资料
<pod-ipv4>.<ns>.pod.<cluster-domain.example>
<pod-ipv4>.<svc>.<ns>.svc.<cluster-domain.example>- 需要 coredns 启用相关插件
<hostname>.[<subdomain>.].<svc>.<ns>.svc.<cluster-domain.example>- Pod 可选的
spec.hostname,spec.subdmain字段
service 样例
ClusterIP 样例
NodePort 样例
loadBalancer 样例
ExternalName 样例
ingress 用于将外部 HTTP/HTTPS 请求路由到集群内的不同 Service
- 必须配合 Ingress Controller(如 Nginx、Traefik、Istio)才能生效
KubernetesIngress 控制器
Ingress 控制器
为了让 [Ingress](/zh-cn/docs/concepts/services-networking/ingress/) 在你的集群中工作, 必须有一个 Ingress 控制器正在运行。你需要选择至少一个 Ingress 控制器并确保其已被部署到你的集群中。 本页列出了你可以部署的常见 Ingress 控制器。
IngressClass 定义一种 Ingress 实现和参数
Ingress 参数资源的作用域取决于所使用的 Ingress 控制器
.spec.parameters.scope字段设置为Namespace可以限制所引用资源.spec.parameters.namespace字段与该资源所在的命名空间一致
集群作用域 IngressClass 样例
- 对应参数类型为 ClusterIngressParameter
名字空间作用域 IngressClass 样例
- 对应参数类型为 IngressParameter
.spec.parameters字段可用于引用其他资源以提供与该 IngressClass 相关的配置
注解 ingressclass.kubernetes.io/is-default-class 设置默认 IngressClass
IngressClass 样例
Ingress通过 ingressClassName 字段绑定特定IngressClass实例
Ingress rules 字段参数
(可选)rules[].host:匹配特定主机名
- 可以使用通配符匹配,不允许使用端口,不允许 IP
rules[].http.paths:将请求映射到后端的路径集合
- 匹配路径最长者优先,精确路径类型优先于前缀路径类型
- paths[].path 与传入请求的路径进行匹配
- 以
/开头 - 在 pathType 值为
Exact或Prefix时必须存在
- paths[].pathType 可以是
Exact,Prefix,ImplementationSpecific "Exact"精确匹配 URL 路径,并且区分大小写"Prefix"基于由'/'分割的 URL 路径前缀进行匹配"ImplementationSpecific"路径匹配的解释取决于 IngressClass
paths[].backend:两种后端类型 resource 和 service
resource 指向同一名字空间中的另一个 Kubernetes 资源
Resource后端的一种常见用法是将所有入站数据导向保存静态资产的对象存储后端
service 指向 Kubernetes service 对象
IngressdefaultBackend 字段用于处理未匹配任何规则(rules)的请求- 不能针对默认规则使用 TLS,因为这样做需要为所有可能的子域名签发证书
Ingress tls 字段参数
hostsTLS 证书中包含的主机列表
secretName引用同命名空间下的 Secret 名称
ingress 样例
ingress 样例
ingress defaultBackend 样例
- 不能针对默认规则使用 TLS,因为这样做需要为所有可能的子域名签发证书
ingress TLS 样例
- 不能针对默认规则使用 TLS,因为这样做需要为所有可能的子域名签发证书
Gateway API 替代或补充传统的 Ingress 资源
- Gateway API 提供了更灵活、角色分离(如平台管理员 vs 应用开发者)、支持多种协议(HTTP, gRPC, TCP 等)的能力
GatewayClass 通常对应一种网关实现
- 网关实现有 Envoy、Nginx、Istio、AWS Gateway Load Balancer 等
- controllerName 绑定对应实现的控制器
- 集群范围资源(Cluster-scoped)
Gateway 声明一个具体的网关实例,定义绑定地址、监听端口、协议、TLS 配置等
- 由平台管理员或高级用户创建
- 命名空间资源,但可被多个命名空间中的 Route 引用
spec.gatewayClassName绑定特定GatewayClass
HTTPRoute 定义 HTTP(S) 流量的路由规则,将流量转发到 Service
- 由应用开发者创建
- 支持基于 Host、Path、Header、Method 等匹配规则
- 可定义权重(用于金丝雀发布)、重写(rewrite)、重定向(redirect)、超时、重试等
parentRefs绑定到一个或多个Gateway
GRPCRoute 定义 gRPC 流量的路由规则,类似于 HTTPRoute
- 由应用开发者创建
- 支持按 gRPC 服务名和方法名进行匹配
parentRefs绑定到一个或多个Gateway
Gateway API 样例
GatewayClass 样例
- 归属于此类的 Gateway 对象将由 example.com/gateway-controller 控制器来管理
Gateway 样例
- 没有定义
addresses可匹配所有地址
- 定义监听端口并绑定 TLS 证书
HTTPRoute 样例
GRPCRoute 样例
k8s 网络策略
Pod 通过如下三个标识符的组合来辩识可以与之通信的实体
- 其他被允许的 Pod
- 例外:Pod 无法阻塞对自身的访问
- 被允许的名字空间
- IP 组块
- 例外:与 Pod 运行所在的节点的通信总是被允许的, 无论 Pod 或节点的 IP 地址
需要网络策略的理由
- 默认全通:K8s 集群在未启用 NetworkPolicy 时,所有 Pod 默认可以互相通信(无论命名空间、节点),存在严重安全隐患。
- 横向移动风险:一旦某个 Pod 被攻陷(如 Web 前端漏洞),攻击者可轻易扫描并渗透数据库、缓存等后端服务
- 多租户隔离:开发、测试、生产环境若在同一集群,需防止越权访问
网络策略(NetworkPolicy)用于控制 Pod 与 Pod 之间、Pod 与外部网络之间的通信流量,在 Kubernetes 集群内部实现微隔离和最小权限访问控制
- NetworkPolicy 通过 CNI 插件来实现,因此必须使用支持 NetworkPolicy 的网络解决方案
- Flannel 默认不支持,其他如 Kube-router, Calico, Romana, Weave-net 等支持
- 在不支持的集群中仍可以创建 NetworkPolicy 资源但无法实现效果
NetworkPolicy 是为第 4 层连接 (TCP、UDP 和可选的 SCTP)所定义的
- 对于所有其他协议,这种网络流量过滤的行为可能因网络插件而异
- 第 7 层连接(如 HTTP 路径、gRPC 方法)过滤需要通过 ServiceMesh 服务网格来实现
NetworkPolicy 工作原理
- 用户创建
NetworkPolicy对象。
- 网络插件(如 Calico)监听该对象,将其转换为底层规则(如 iptables、eBPF)
- 规则被下发到每个 Node,拦截 Pod 的进出流量
- 只有明确允许的流量才可通过;未匹配任何策略的流量被拒绝
NetworkPolicy 资源定义
spec.podSelector选择满足条件的一组 Pod- 空的
podSelector选择名字空间下的所有 Pod
spec.policyTypes决定应用于入站流量或出站流量,或者两者兼具- 可选值
Ingress或Egress或两者兼具 - 如果 NetworkPolicy 未指定
policyTypes则默认情况下始终设置Ingress - 如果 NetworkPolicy 有任何出口规则的话则设置
Egress
spec.egress允许同时匹配from和ports部分的流量
spec.ingress允许匹配to和ports部分的流量
egress, ingress 的选择器 to 和 from 可以指定四种选择器
- podSelector:在与 NetworkPolicy 相同的名字空间中选择特定的 Pod
- namespaceSelector:选择特定的名字空间
- 特定 namespaceSelector 的 podSelector:选择特定名字空间中的特定 Pod
- ipBlock:此选择器将选择特定的 IP CIDR 范围
- 应该是集群外部 IP,因为 Pod IP 存在时间短暂的且随机产生
- 集群的入站和出站机制通常需要重写数据包的源 IP 或目标 IP
- 不同网络插件\云运营商\Service实现等都可能有影响,不能确定重写 IP在 NetworkPolicy 处理之前还是之后发生
namespaceSelector, podSelector 均属于 LabelSeletor 对象,有两种匹配方法
matchExpressions
- 基于集合的标签选择器
- operator 可用 In, NotIn, Exists, DoesNotExist
matchLabels
- 匹配满足键值对条件的标签
NetworkPolicy 样例
通过 podSelector 留空可以创建默认网络策略
- 默认情况下,如果名字空间中不存在任何策略,则所有进出该名字空间中 Pod 的流量都被允许
默认拒绝所有入站流量
vim service/networking/network-policy-default-deny-ingress.yaml
默认拒绝所有出站流量
vim service/networking/network-policy-default-deny-egress.yaml
允许所有入站流量
vim service/networking/network-policy-allow-all-ingress.yaml
允许所有出站流量
vim service/networking/network-policy-allow-all-egress.yaml
默认拒绝所有入站和所有出站流量
vim service/networking/network-policy-deny-all.yaml
针对 hostNetwork Pod 的 NetworkPolicy 行为是未定义的,存在以下两种实现可能
- 网络插件可以辨别出
hostNetworkPod 流量,对hostNetworkPod 应用 NetworkPolicy
- 网络插件无法正确辨别
hostNetworkPod 流量,在匹配podSelector和namespaceSelector时会忽略hostNetworkPod - 最常见的实现方式
- 由于
hostNetworkPod 具有与其所在节点相同的 IP 地址,所以它们的连接将被视为节点连接
自定义 kubernete 集群 DNS
参考资料
- Author:白鸟3
- URL:https://blog.kun2peng.top/operation/k8s_network
- Copyright:All articles in this blog, except for special statements, adopt BY-NC-SA agreement. Please indicate the source!
