一、基础知识:eBPF和XDP
1.1 BPF
全称为“Berkeley Packet Filter”,于1997 年自Linux 2.1.75版本的内核引入。基于寄存器(CPU之上的小型存储空间)的虚拟机,运行于内核空间。主要功能包括:
- 负责运行从用户空间(通过系统调用)注入的代码而无须对内核进行编程(开发内核模块)。
- 使用自定义的64 位RISC指令集。
- 能够在Linux内核内部运行即时本地编译的 “BPF 程序”,并能访问内核功能和内存的子集。
tcpdump命令其实就是借助BPF把后面的选项转换为BPF程序并注入到BPF虚拟机上运行(即使用BPF作为网络数据包过滤技术)。
1.2 eBPF
eBPF,即“extended BPF”,由Alexei Straovoitov于2014年实现,最早出现在Linux 3.15版本的内核中。针对现代硬件进行了优化,较之BPF执行速度更快。
2014年6月,eBPF扩展到用户空间,从而演进成了一个通用执行引擎,应用场景不再局限于数据包过滤,而是逐步扩展到内核各子模块,随后被广泛应用在观测、网络和安全等领域。目前已然发展成为Linux内核的顶级子系统。
ePBF为用户提供了通过简单程序扩展或定制内核功能的接口。用户可编写eBPF程序与内核中的目标事件相关联,并由这些事件触发执行。
eBPF的工作逻辑如下:进程通过系统调用将eBPF代码送到内核空间。待校验通过后由JIT Compiler(Just-in-Time,即时编译器)把它编译为eBPF的可执行程序,在eBPF的执行引擎上执行。执行结果可通过SystemCall(linux系统接口)送给进程以了解执行情况。这里的可执行程序可控制Socket通信、TCP/IP的各类属性、网络接口的配置等。
eBPF通常用于SDN(软件定义网络)配置、入侵检测、可观测性、防火墙、容器安全、DDOS泛洪防范、设备驱动等功能。
1.3 XDP
XDP的全称为“express Data Path”,在内核级提供可编程数据包处理机制。它是Linux内核中基于eBPF提供的高性能数据路径,支持绕过内核的网络栈直接在网络驱动程序的级别处理数据包。
二、Cilium
2.1 简介
Cilium是一款基于eBPF和XDP的Kubernetes高性能网络插件,支持可观测性和安全机制。也是ServiceMesh的数据平面。
其功能如下:
- 容器网络解决方案和负载均衡器:CNI、Kubernetes Service、Multi-cluster。Service的功能原本需要kube-proxy组件支持,有了Cilium,就无需kube-proxy组件了。
- 网络安全:Network Policy、Identity-based(基于每个Pod的身份识别,下发证书建立TLS连接,实现端到端的加密通信)、Encryption(链路加密)。
- 可观测性:Metrics、Flow Visibility(请求流)、Service Dependency(服务依赖性)。
Kubernetes的基础网络功能,包括iptables/ipvs、服务发现、同一节点/跨节点的Pod间的通信,这些Cilium都能实现。它是节点级Agent,支持隧道和直接路由的方式通信。它是eBPF的原生数据平面,可替换由kube-proxy所支撑的Service的服务发现和负载均衡功能,完全取代kube-proxy。使用Cilium代替kube-proxy,网络请求报文无需遍历iptables/ipvs表,使得集群性能更加高效。
2.2 Cilium的关键组件
2.2.1 Cilium Agent
- 由DaemonSet编排运行集群中的每个节点上。
- 里面运行的程序用于从Kubernetes或API接口接受配置:网络、LB、Network Policy等。将这些配置转换为eBPF程序并送到节点内核中的eBPF引擎上。
- 基于SDK调用节点上的eBPF实现相关的功能。
2.2.2 Cilium Client
- 命令行工具,通过Rest API同当前节点上的Cilium Agent进行交互去了解Cilium Agent的各类状态信息。
- 常用于检查本地Cilium Agent的状态。
- 也可用于直接访问eBPF Map。
- 另外还有一个客户端工具称为Cilium CLI,负责管理整个Cilium集群,而非当前Cilium Agent。
2.2.3 Cilium Operator
负责监视和维护整个集群。
2.2.4 Cilium Plugin
Cilium自身即为Kubernetes CNI插件,同时还可以完全取代Kube Proxy的功能。
三、Kubernetes使用Cilium插件
3.1 Pod网络模式
3.1.1 隧道封装
- VXLAN:默认模式,8472/UDP
- Geneve:6081/UDP
3.1.2 直接路由
- 将所有非本地目标地址报文都交由内核的路由子系统,处理逻辑等同于本地进程生成的报文。类似于Calico的BGP模式和Flannel的host-gw模式。
- 节点上的路由表将决定如何路由Pod报文。
- 开启方式:--set tunnel=disabled --set routing-mode=native
3.2 部署Kubernetes集群和Cilium网络插件
部署Kubernetes集群时,在kubeadm init命令上使用“--skip-phases=addon/kube-proxy”选项,以跳过Kube Proxy的部署。
kubeadm init --control-plane-endpoint="kubeapi.wxd.com" --kubernetes-versinotallow=v1.29.8 --pod-network-cidr=10.244.0.0/16 --service-cidr=10.96.0.0/12 --token-ttl=0 --upload-certs --image-repository=registry.aliyuncs.com/google_containers --cri-socket=unix:///var/run/cri-dockerd.sock --skip-phases=addon/kube-proxy
部署Cilium网络插件,方式有helm和Cilium cli。这里使用Cilium cli。
Cilium cli安装参考https://github.com/cilium/cilium-cli
wget https://github.com/cilium/cilium-cli/releases/download/v0.16.16/cilium-linux-amd64.tar.gz
tar -xf cilium-linux-amd64.tar.gz
mv cilium /usr/local/bin
#显示 Cilium 的状态信息,包括节点、代理、网络等信息。进入cilium agent的Pod内部使用
cilium status
#列出可用的Cilium版本,默认为目前最新的稳定版
cilium install --list-versions
#使用默认的VXLAN模式,并自定义要使用的子网
cilium install --set kubeProxyReplacement=true --set ipam.mode=kubernetes --set routingMode=tunnel --set tunnelProtocol=vxlan --set ipam.operator.clusterPoolIPv4PodCIDRList=10.244.0.0/16 --set ipam.Operator.ClusterPoolIPv4MaskSize=24
#卸载
cilium uninstall
#使用原生路由(直接路由)模式
cilium install --set kubeProxyReplacement=strict --set ipam.mode=kubernetes --set routingMode=native --set ipam.operator.clusterPoolIPv4PodCIDRList=10.244.0.0/16 --set ipam.Operator.ClusterPoolIPv4MaskSize=24 --set ipv4NativeRoutingCIDR=10.244.0.0/16 --set autoDirectNodeRoutes=true --set bpf.masquerade=true
3.3 Cilium网络插件的实现
Cilium会在宿主机上创建四个虚拟网络接口。
- cilium_host和cilium_net。一组veth pair,由Cilium Agent创建。cilium_host会被配置为该主机分配到的PodCIDR中的第一个地址,并作为该子网的默认网关(例如下面的10.244.3.57)。CNI插件负责创建BPF规则,以便于在内核接通veth pair的两端。
- cilium_vxlan。负责在vxlan模式下,封装或解封vxlan报文。
- lxc_health。节点健康状态检测。
关于Pod网络接口。Cilium会为每个Pod创建一组veth pair。一端作为Pod中的网络接口存在,网关指向cilium_host的地址。另一端表现为宿主机上名字形如“lxcXXXX”的虚拟接口。LXC接口的MAC地址用于响应ARP请求。
#以当前节点(这里是K8S-Node2节点)为中心显示Cilium的隧道状态信息。需要进入Cilium agent的Pod内执行
cilium bpf tunnel list
3.4 Cilium网络插件的配置要点
3.4.1 Cilium在Kubernetes上的运行模式
- 与kube-proxy共存:通常在内核版本较低时采用的模式,替换kube-proxy的部分功能
- kubeProxyReplacement=probe:自动探测内核中支持BPF特性,并自行决定如何替换
- kubeProxyReplacement=partial:由用户手动指定由BPF替换的特性
- 完全替换kube-proxy:kubeProxyReplacement=strict
如上配置可通过kubectl edit cm -n kube-system cilium-config命令修改。
3.4.2 Masquerading(地址伪装)
将来自集群外部流量转发至集群上的Pod时依赖的功能,传统方式是使用iptables nat机制(称为iptables mode)。eBPF提供了更加高效的masquerading机制(eBPF mode),但仅在4.19及以上版本的Linux内核上支持。启用方式:“bpf.masquerade=true”。
3.4.3 Host-Routing(主机路由)
eBPF模式下,网络报文仍会通过常规网络栈中的某些部分,例如netfilter框架,这会增加网络开销。Cilium自v1.9版本引入的基于eBPF的Host-Routing机制,可让报文完全绕过netfilter和上层网络栈。该功能存在Legacy Mode和BPF Mode两种模式,后一种依赖于多个条件:Kernel >= 5.10、eBPF-based kube-proxy replacement、eBPF-based masquerading。
四、Hubble及Cilium指标
4.1 关于Hubble
Hubble是建立在Cilium和eBPF之上、分布式的网络可观察性平台。存储、展示从Cilium获取的相关数据。Hubble还可以对接像Prometheus、Grafana等主流的云原生监控体系,实现可扩展的监控策略。
4.2 配置Cilium启用Hubble
通过cilium命令启用:cilium hubble enable --ui
部署cilium时直接启用,在cilium命令上使用如下选项即可:
--set hubble.enabled="true" --set hubble.listenAddress=":4244" --set hubble.relay.enabled="true" --set hubble.ui.enabled="true"
同Prometheus对接:
--set prometheus.enabled=true --set operator.prometheus.enabled=true --set hubble.metrics.port=9665 --set hubble.metrics.enableOpenMetrics=true --set metrics.enabled="{dns:query;ignoreAAAA;destinatinotallow=pod-short,drop:sourceCnotallow=pod;destinatinotallow=pod,tcp,flow,port-distribution,icmp,http}"
上面的设置,表示开启了hubble的metrics输出模式,并输出以上这些信息。默认情况下,Hubble daemonset会自动暴露metrics API给Prometheus。
五、Cilium Ingress Controller
5.1 简介
Cilium内置支持用于Kubernetes Cluster的Ingress Controller。支持通过将ingressClassName的值设定为“cilium”来解析Ingress资源,也兼容 “kubernetes.io/ingress.class”注解方式。支持各类Ingress,包括TLS类型。启用Kube Proxy时,设置了“nodePort.enabled=true”;未启用Kube Proxy,由Cilium代替其功能。
Cilium Ingress的负载均衡器模式:
- dedicated:独占模式,即Cilium会为每个Ingress资源在同一个namespace下创建一个专用的LoadBalancer类型的Service资源。
- shared:共享模式,多个Ingress资源共享使用Cilium默认创建的LoadBalancer类型的Service资源(位于Cilium所在的名称空间,默认为kube-system)。类似于Ingress Nginx。
5.2 启用Cilium Ingress Controller
# 启用Ingress Controller
cilium install \
…
--set kubeProxyReplacement=true \
--set ingressController.enabled=true \ # 启用Ingress Controller
--set ingressController.loadbalancerMode=dedicated \ # 设定默认的LoadBalancer模式为dedicated
--set ingressController.default=true # 可选项,设定Cilium作为默认使用的Ingress Controller
当然,也可以采用配置Ingress的方式来完成。在ingress资源上,将“spec.ingressClassName”字段或者“kubernetes.io/ingress.class”注解的值设置为“cilium”。
ingress资源的LoadBalancer类型默认继承Cilium的全局设定,也可通过注解“ingress.cilium.io/loadbalancer-mode”注解单独配置。dedicated模式下,还可通过注解“ingress.cilium.io/service-type”指定专用Service的类型,可用值有“LoadBalancer”和 “NodePort”。
对于dedicated模式的ingress,cilium会自动为其创建一个Service作为Ingress Controller入口,名称格式为“cilium-ingress-INGRESS_NAME”。客户端要通过Ingress中声明的主机名,和专用Service的入口 (NodePort或LB_IP)来访问对应的Ingress中要暴露的服务。
5.3 共享模式
以下命令采用共享模式创建Cilium Ingress Controller。
cilium install --set kubeProxyReplacement=true --set ipam.mode=kubernetes --set routingMode=tunnel --set tunnelProtocol=vxlan --set ipam.operator.clusterPoolIPv4PodCIDRList=10.244.0.0/16 --set ipam.Operator.ClusterPoolIPv4MaskSize=24 --set ingressController.enabled=true --set ingressController.loadbalancerMode=shared
之后部署MetalLB,部署成功后就可以让Cilium作为Ingress为服务暴露于集群外部提供支持。服务就以之前的hubble-ui为例进行说明。
此时,kube-system名称空间下的hubble-ui服务需要通过cilium-ingress这个Ingerss控制器去对外开放服务。
#创建ingress规则,ingressclass为cilium,把kube-system名称空间下hubble-ui:80这个服务通过主机名hubble.wxd.com开放出去。
kubectl create ingress hubble-ui --class='cilium' --rule='hubble.wxd.com/*=hubble-ui:80' -n kube-system
在物理机做如下解析,查看访问效果:
192.168.131.201 hubble.wxd.com
5.4 独占模式
先创建好对应的Deployment和clusterip类型的Service
kubectl create deploy demoapp --image=ikubernetes/demoapp:v1.0 --replicas=3
kubectl create svc clusterip demoapp --tcp=80:80
创建相应的Ingress
vim demoapp.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: demoapp
annotations:
ingress.cilium.io/loadbalancer-mode: 'dedicated'
ingress.cilium.io/service-type: 'LoadBalancer'
spec:
ingressClassName: cilium
rules:
- host: demoapp.wxd.com
http:
paths:
- backend:
service:
name: demoapp
port:
number: 80
path: /
pathType: Prefix
status:
loadBalancer: {}
kubectl apply -f demoapp.yaml
apply清单后,发现demoapp.wxd.com被分配一个为192.168.131.202的外部IP地址,此地址隶属cilium-ingress-demoapp这个svc的。这个Service的意思是专门用于通过 cilium Ingress开放demoapp服务的Service。用域名demoapp.wxd.com即可访问demoapp服务,访问效果为负载均衡。
注意:192.168.131.202只能被demoapp这个ingress所使用,尽管为此创建了专有的Service,但该Service只是被Ingress作为LoadBalancer的流量入口来使用。
标签:插件,set,eBPF,--,Ingress,网络,Cilium,cilium From: https://blog.51cto.com/u_15796303/12009293