首发实战:Flannel为网络CNI底座的K8S接入Cilium CNI
背景
又想使用Flannel网络,还想用NetworkPolicy功能,给出的要求也没办法啊调研看看应该怎么实现吧,网络搜索基本没有参考的内容,写出这篇用于记录如何对接适配,同需求也可进行参考。
在以 Flannel 为基础 CNI 的 Kubernetes 集群中接入 Cilium,核心是利用CNI 链式调用(CNI Chaining) 技术,让 Cilium 在保留 Flannel 网络基础能力(如 IP 分配、底层连通性)的同时,叠加其高级功能(如 eBPF 网络策略、可观测性、L7/HTTP 策略等)。这种配置不替换 Flannel 的核心网络功能,而是通过 "链式" 协作实现功能增强。
注:此为typora导入,格式和部分内容可能不美观但流程正确
核心技术原理
Kubernetes 的 CNI 规范支持多插件链式调用 :即一个主 CNI 插件(如 Flannel)负责基础网络配置(IP 分配、Pod 网络接口创建),后续插件(如 Cilium)在其基础上追加功能(如策略 enforcement、流量监控)。
在 Flannel+Cilium 的组合中:
- Flannel 仍作为 "底座",负责 Pod 的 IP 地址分配(IPAM)、跨节点 Overlay 网络(如 VXLAN)或 Underlay 网络(如 host-gw)的连通性。
- Cilium 作为 "增强插件",通过 eBPF 技术在内核层拦截 Pod 流量,实现网络策略、流量可视化、负载均衡等高级功能,且不干扰 Flannel 的基础网络逻辑。
在网络上没有寻找到对应的教程,只能自己摸索结合Cilium的官方文档AI辅助以及其他资料多次联调测验解决其中各自坑,最终完成此需求并编写文档流程。
K8S及组件版本准备
以下所使用的版本都是已经查询后完成兼容性问题版本,过程中不会遇见各种因为不支持遇见的坑
K8S安装这里不做说明直接略过,以纯净的K8S为例,部署了K8S的v1.23.6版本
shell
kubectl version --short

安装完成后,没有CNI组件K8S集群是没有准备好的异常状态,CoreDNS组件也是启动失败,基础环境就在此情况下进行。
Flannel版本

Cilium版本

Helm版本

Flannel安装
这里的安装采用K8S中文社区中的Flannel地址
下载地址:https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
需要更改Pod的IP地址段或者网络类型可以wget下来之后编辑修改,如果不用的话可以直接kubectl apply

shell
kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
flannel会创建个kube-flannel命名空间存放组件,查看Flannel是否安装完成
shell
kubectl get pod -n kube-flannel

删除coredns重新查看状态是否正常
shell
kubectl delete pod coredns-6d8c4cb4d-rpzcw coredns-6d8c4cb4d-5kgv9 -n kube-system
kubectl get pod -n kube-system

查看K8S现在的节点状态确保正常
shell
kubectl get nodes

测验网络环境就省略了,自己测试确保Flannel组件正常即可

更改Flannel的网络模式
Cilium 依赖 eBPF 在 Linux 内核层直接处理网络流量(如策略 enforcement、负载均衡等)。
当 Flannel 使用 vxlan 时,数据包会被 VXLAN 封装,导致 Cilium 的 eBPF 程序无法直接解析原始数据包的内容(如源 / 目的 IP、端口等),从而无法正常工作(例如网络策略失效、流量跟踪异常)。
不将模式改成host-gw模式,coredns组件将会启动失败无法正常工作Pod无法互通失去网络组件功能。
1. 技术冲突的核心:VXLAN 封装与 eBPF 数据路径的矛盾
Cilium 的核心优势依赖于 eBPF 技术在 Linux 内核层直接处理网络流量,实现细粒度的网络策略、流量可视化、负载均衡等功能。这要求 Cilium 能够直接解析原始数据包的内容(如源 / 目的 IP、端口、协议等)。
而 Flannel 的 vxlan 模式会对数据包进行VXLAN 隧道封装(在原始数据包外层添加 VXLAN 头部),导致:
- Cilium 的 eBPF 程序无法直接读取原始数据包的信息,无法执行网络策略、流量跟踪等操作。
- 封装后的数据包会绕过 Cilium 的 eBPF 数据路径,导致功能失效(例如策略不生效、 Hubble 监控无数据)。
2. host-gw 模式为何兼容?
Flannel 的 host-gw 模式基于主机路由表转发流量,不进行任何隧道封装,数据包保持原始格式。这种模式下:
- 数据包直接通过物理网络层(L2/L3)转发,Cilium 的 eBPF 程序可以正常解析原始流量。
- Cilium 能够在数据包经过主机时拦截并处理,确保网络策略、监控等功能正常工作。
3. 操作步骤
将Flannel的网络模式改成host-gw,如果是把文件下载了就直接改yaml
shell
kubectl edit cm kube-flannel-cfg -n kube-flannel

更改完成后一定要进行重启操作,先重启Flannel
shell
# 重启 Flannel DaemonSet
kubectl rollout restart daemonset/kube-flannel-ds -n kube-flannel
# 验证重启结果
kubectl get pods -n kube-flannel | grep flannel
接着重启coredns
shell
# 重启 CoreDNS Deployment(会滚动重启 Pod)
kubectl rollout restart deployment/coredns -n kube-system
# 验证验证验证重启结果
kubectl get pods -n kube-system | grep coredns
Cilium适配接入当前K8S环境
因为是使用Helm进行部署,需要先把Helm工具下载
下载地址:https://get.helm.sh/helm-v3.18.2-linux-amd64.tar.gz
shell
wget https://get.helm.sh/helm-v3.18.2-linux-amd64.tar.gz
mv linux-amd64/helm /usr/local/bin/
helm version

简化更改配置以及简单部署的最佳方式是使用Helm,这里Cilium的部署就以Helm包的方式进行。
下载地址:https://github.com/cilium/cilium/archive/refs/tags/v1.15.0.tar.gz
shell
wget https://github.com/cilium/cilium/archive/refs/tags/v1.15.0.tar.gz
tar xf v1.15.0.tar.gz
解压之后,实际我们用到的配置文件的路径在这里
shell
ls cilium-1.15.0/install/kubernetes/cilium/

为了精细化配置以及确保配置内容无异常,这里通过修改values.yaml文件方式部署启动。
0. 完整修改项汇总
列举部分要配置的参数以供参考,后面有全部要修改的配置内容以及步骤
| 配置路径 | 修改后值 | 核心作用 | 与 Flannel 的关联 |
|---|---|---|---|
cni.chainingMode |
"flannel" |
启用 Cilium 与 Flannel 的链式集成 | Cilium 作为上层插件工作,复用 Flannel 构建的底层网络(如 Pod 网段、跨节点隧道) |
cni.exclusive |
false |
不独占 CNI 配置目录 | 保留 Flannel 的 CNI 配置文件(如 10-flannel.conflist),避免被 Cilium 覆盖 |
tunnel |
false |
禁用 Cilium 自身的隧道功能 | 避免与 Flannel 的 VXLAN 隧道冲突(双重隧道会导致流量异常) |
routingMode |
"native" |
使用原生路由模式 | 依赖 Flannel 已配置的节点路由,Cilium 仅优化转发路径,不创建独立隧道 |
ipam.mode |
"kubernetes" |
禁用 Cilium 的 IP 地址管理 | 由 Flannel 负责 Pod IP 分配,Cilium 不再生成独立的 IP 池 |
ipv4NativeRoutingCIDR |
"10.244.0.0/16" |
声明与 Flannel 一致的 Pod CIDR | 确保 Cilium 识别 Flannel 管理的网段,避免地址冲突 |
kubeProxyReplacement |
"false" |
禁用 Cilium 对 kube-proxy 的替换 | 保留 kube-proxy 处理 Service 转发,与 Flannel 依赖的 Service 逻辑兼容 |
autoDirectNodeRoutes |
false |
禁用 Cilium 自动生成节点路由 | 节点间路由由 Flannel 管理,避免 Cilium 生成的路由覆盖 Flannel 规则 |
1. CNI 链式部署配置(关键)
需明确启用 Cilium 与 Flannel 的链式集成,确保 Cilium 在 Flannel 基础上工作而非替换它。
yaml
cni:
# 启用CNI配置安装(必须为true,否则Cilium无法注入链式配置)
install: true
# 禁用Cilium对CNI目录的独占,避免覆盖Flannel配置
exclusive: false
# 指定链式模式为Flannel(Cilium将作为Flannel的上层补充)
chainingMode: "flannel"
# 链式目标自动关联Flannel(无需手动指定,chainingMode=flannel时默认生效)
chainingTarget: ~
2. 路由与隧道模式配置(避免冲突)
Flannel 通常使用 VXLAN 隧道,需禁用 Cilium 的隧道功能,改用原生路由模式,避免网络叠加冲突。
yaml
# 手动添加配置禁用自身隧道,避免Cilium开启影响 Flannel 功能
tunnel: false
# 手动添加配置,允许CiliumC添加补充路由,不影响 Flannel 功能
hostRouting: true
# 路由模式:使用原生路由(依赖Flannel的底层网络)
routingMode: "native"
# 隧道协议:配置Cilium的隧道为空(避免与Flannel冲突)
tunnelProtocol: ""
# 禁用Cilium的自动节点路由(由Flannel管理节点间路由)
autoDirectNodeRoutes: false
3. IPAM 配置(交由 Flannel 管理)
Flannel 已负责 Pod IP 分配,需禁用 Cilium 的 IPAM 功能,避免 IP 管理冲突。
yaml
ipam:
# IPAM模式:设为"kubernetes",不使用Cilium的IP地址管理(由Flannel负责)
mode: "kubernetes"
# CIDR地址会读取kubernetes的配置,以防万一可以配置上或者清空
clusterPoolIPv4PodCIDRList: ["10.244.0.0/16"]
4.配置Flannel的CIDR(CIDR声明)
CIDR需将其设置为 Flannel 使用的 Pod CIDR (即 Flannel 为集群分配的 Pod 网段)。
Flannel 默认 Pod CIDR 通常为 10.244.0.0/16,但需根据你的集群实际配置调整(可通过 kubectl get cm kube-flannel-cfg -n kube-flannel -oyaml 查看 Flannel 的 net-conf.json 确认)。
yaml
# 配置为Flannel的Pod CIDR(示例为默认值,需根据实际情况调整)
ipv4NativeRoutingCIDR: "10.244.0.0/16"
ipMasqAgent:
enabled: false # 禁用ip-masq-agent
5. Kube-proxy 兼容配置
Flannel 依赖 kube-proxy 实现 Service 代理,需禁用 Cilium 的 kube-proxy 替换功能。
yaml
# 禁用Cilium的kube-proxy替换(保持kube-proxy运行)
kubeProxyReplacement: "false"
6.其他建议配置
1. 禁用冲突的网络功能
Cilium 的部分网络功能可能与 Flannel 冲突,需按需禁用:
yaml
# 禁用Cilium的负载均衡加速(由kube-proxy和Flannel处理)
loadBalancer:
acceleration: "disabled"
# 禁用Cilium的BGP功能(Flannel不依赖BGP)
bgp:
enabled: false
bgpControlPlane:
enabled: false
# 禁用网络加密(如需加密可单独配置,但需避免与Flannel冲突)
encryption:
enabled: false
2. 资源与调度配置(可选)
根据集群规模调整 Cilium 的资源限制,确保与 Flannel 共存时资源充足:
yaml
agent:
resources:
requests:
cpu: 100m
memory: 256Mi
limits:
cpu: 1000m
memory: 1Gi
operator:
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 500m
memory: 512Mi
3. K8S的api地址(可选)
不写的话也会通过服务发现找到,但为了更加精准识别可以加上,以防其他问题出现。
yaml
# K8S的apiserver IP地址
k8sServiceHost: ""
# K8S的服务端口
k8sServicePort: ""
7.部署Cilium
Helm部署命令
shell
helm repo add cilium https://helm.cilium.io/
helm install cilium cilium/cilium --version 1.15.0 \
--namespace kube-system \
-f values.yaml
Helm更新命令
shell
helm upgrade cilium cilium/cilium --version 1.15.0 \
--namespace kube-system \
-f values.yaml
更新后要重启Cilium组件
shell
# 重启 Cilium DaemonSet
kubectl rollout restart daemonset/cilium -n kube-system
# 验证重启结果(确保所有 Pod 状态为 Running)
kubectl get pods -n kube-system | grep cilium
Heml删除命令
shell
helm uninstall cilium -n kube-system
这里执行下安装命令
helm install cilium cilium/cilium --version 1.15.0 -namespace kube-system -f values.yaml

完成之后查看Cilium是否启动成功
shell
kubectl get pod -n kube-system

Cilium和coredns组件都为Running状态,这样就部署完成了。
查看Cilium的各项配置是否正常,其中不能出现 routing-mode: tunnel,会造成配置冲突导致coredns启动失败
shell
kubectl -n kube-system get cm cilium-config -o yaml

重启网络CNI组件日志检查
Flannel重启
shell
kubectl rollout restart daemonset/kube-flannel-ds -n kube-flannel
kubectl get pods -n kube-flannel | grep flannel
kubectl logs -f kube-flannel-ds-kbqf7 -n kube-flannel

Flannel日志输出关键项解读
- 核心配置与模式确认
- 后端模式 :
Found network config - Backend type: host-gw
明确显示 Flannel 使用host-gw模式(基于主机路由转发,无隧道封装),符合与 Cilium 兼容的要求(此前提到 vxlan 模式会冲突)。 - 子网管理 :
Starting kube subnet manager
Flannel 使用 Kubernetes 子网管理器,从节点的n.Spec.PodCIDRs中获取并管理子网:10.244.0.0/24、10.244.1.0/24、10.244.2.0/24,这是集群内 Pod 的 IP 网段。
- 网络接口与 IP 配置
- 节点网络接口 :
Using interface with name ens33 and address 192.168.2.13
Flannel 自动检测到主机的默认网络接口为ens33,绑定的物理 IP 为192.168.2.13(作为节点间通信的网关地址)。 - 节点标注验证 :
flannel.alpha.coreos.com/backend-type: "host-gw"
节点k8s-node2的 annotations 确认了后端模式为host-gw,且公网 IP(实际为物理机 IP)为192.168.2.13,与接口配置一致。
- 路由规则配置
- 子网路由添加 :
Subnet added: 10.244.0.0/24 via 192.168.2.11Subnet added: 10.244.1.0/24 via 192.168.2.12
Flannel 为集群内其他节点的 Pod 子网添加路由规则,通过对应节点的物理 IP(192.168.2.11、192.168.2.12)转发流量。
- 路由存在性检查 :
Route to ... already exists, skipping.
已存在的路由规则不会重复添加,避免冲突,确保路由表简洁。
- 网络规则与清理
- iptables 模式启动 :
Starting flannel in iptables mode...
Flannel 使用 iptables 配置网络规则(如转发策略),并将默认FORWARD链策略设为ACCEPT,确保 Pod 间流量可正常转发。 - 规则清理 :
Cleaning-up nftables rules...
启动时清理旧的 nftables 规则,避免残留规则干扰当前配置。
- 非关键警告
no subnet found for key: FLANNEL_IPV6_NETWORK
提示未配置 IPv6 子网,属于正常现象(若集群仅使用 IPv4,可忽略此警告)。
总结
Flannel 以host-gw模式正常运行,成功加载子网配置、添加节点间路由,并完成 iptables 规则初始化,与 Cilium 的兼容性基础已满足。日志中无错误信息,所有核心功能(子网管理、路由转发、网络规则)均正常启动。
cilium重启
shell
kubectl rollout restart daemonset/cilium -n kube-system
kubectl get pods -n kube-system | grep cilium
kubectl logs -f cilium-operator-774958bf7f-gftc9 -n kube-system
测验NetworkPolicy功能
Flannel是没有NetworkPolicy功能的,这里测验正好来确认Cilium的功能是否正常
创建两个命名空间
shell
kubectl create ns ns-a
kubectl create ns ns-b
跑个nginx用于测验
nginx-a
shell
[root@k8smaster network]# cat ns-a-deploy.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-a
namespace: ns-a
spec:
selector:
matchLabels:
app: nginx-a
template:
metadata:
labels:
app: nginx-a
spec:
containers:
- name: nginx-a
image: swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/nginx:1.14.2
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: nginx-a
namespace: ns-a
spec:
selector:
app: nginx-a
ports:
- protocol: TCP
port: 80
targetPort: 80
两个命名空间都创建个测试Pod用于访问
netshoot-a
yaml
[root@k8smaster network]# cat netshoot-a.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: netshoot-a
namespace: ns-a
spec:
selector:
matchLabels:
app: netshoot-a
replicas: 1
template:
metadata:
labels:
app: netshoot-a
spec:
containers:
- name: pod1
image: swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/nicolaka/netshoot:v0.13
imagePullPolicy: IfNotPresent
command: ["sleep", "3600"] # 容器启动后保持运行状态
netshoot-b
yaml
[root@k8smaster network]# cat netshoot-b.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: netshoot-b
namespace: ns-b
spec:
selector:
matchLabels:
app: netshoot-b
replicas: 1
template:
metadata:
labels:
app: netshoot-b
spec:
containers:
- name: pod1
image: swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/nicolaka/netshoot:v0.13
imagePullPolicy: IfNotPresent
command: ["sleep", "3600"] # 容器启动后保持运行状态
tshoot-b
yaml
[root@k8smaster network]# cat netshoot-b.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: netshoot-b
namespace: ns-b
spec:
selector:
matchLabels:
app: netshoot-b
replicas: 1
template:
metadata:
labels:
app: netshoot-b
spec:
containers:
- name: pod1
image: swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/nicolaka/netshoot:v0.13
imagePullPolicy: IfNotPresent
command: ["sleep", "3600"] # 容器启动后保持运行状态