实战:Flannel为网络CNI底座的K8S接入Cilium CNI

首发实战: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日志输出关键项解读

  1. 核心配置与模式确认
  • 后端模式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/2410.244.1.0/2410.244.2.0/24,这是集群内 Pod 的 IP 网段。
  1. 网络接口与 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,与接口配置一致。
  1. 路由规则配置
  • 子网路由添加
    • Subnet added: 10.244.0.0/24 via 192.168.2.11
    • Subnet added: 10.244.1.0/24 via 192.168.2.12
      Flannel 为集群内其他节点的 Pod 子网添加路由规则,通过对应节点的物理 IP(192.168.2.11192.168.2.12)转发流量。
  • 路由存在性检查Route to ... already exists, skipping.
    已存在的路由规则不会重复添加,避免冲突,确保路由表简洁。
  1. 网络规则与清理
  • iptables 模式启动Starting flannel in iptables mode...
    Flannel 使用 iptables 配置网络规则(如转发策略),并将默认FORWARD链策略设为ACCEPT,确保 Pod 间流量可正常转发。
  • 规则清理Cleaning-up nftables rules...
    启动时清理旧的 nftables 规则,避免残留规则干扰当前配置。
  1. 非关键警告
  • 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"] # 容器启动后保持运行状态
相关推荐
lichenyang4531 天前
Docker 学习笔记(四):Dockerfile,把项目打成自己的镜像
docker·容器
lichenyang4531 天前
Docker 学习笔记(三):Docker 网络、bridge、子网和容器互通
docker·容器
lichenyang4531 天前
Docker 学习笔记(二):docker run 的参数到底在控制什么?
docker·容器
运维开发故事4 天前
基于 Arthas 的多集群在线诊断系统设计与实现
kubernetes
Patrick_Wilson6 天前
从「改个端口」到 502:Next.js on k8s 的容器端口、Service 映射与 env 覆盖
docker·kubernetes·next.js
探索云原生6 天前
K8s 1.36 这个 GA 特性,把 initContainer 拉模型的 hack 干掉了
ai·云原生·kubernetes
云恒要逆袭6 天前
运行你的第一个Docker容器
后端·docker·容器
Java之美7 天前
一次k8s升级引发的DevicePlugin注册失败
云原生·kubernetes
程序员老赵8 天前
10 分钟部署 OpenCode:Docker 一键安装,浏览器打开就能用 AI 写代码(附完整命令与排错)
docker·容器·ai编程