K3s HA 终极筑基:eBPF 与 VIP 的暴力美学
This content is not available in your language yet.
📖 认识赛博靶场:K3s + Cilium + kube-vip
Section titled “📖 认识赛博靶场:K3s + Cilium + kube-vip”在正式给这 3 台 Ubuntu 虚拟机敲下回车之前,我们先理清这套终极架构的底牌和初衷。
“高可用的本质不是不犯错,而是机器内部炸了之后,你还能在朋友面前装作无事发生。”
必须坦白,如果你的 Homelab 只是为了跑几个家庭服务(比如看剧、下电影、做个网盘),那么 Docker 已经完全足够了。K3s 的维护成本并不低,我极其不推荐只追求家庭网络稳定性的朋友来蹚这趟浑水。
那我为什么还要折腾这套架构?
- 我想彻底理解 Kubernetes 的整体架构与流量走向。
- 我想在 Homelab 里搭建一个真正具备“集群化思维”的测试环境。
网上的 K3s 教程大多教你单节点起步,自带的 Flannel 网络和 Traefik 网关确实够用。但在咱们“赛博工地”,这套“全家桶”过于黑盒,缺乏折腾的乐趣。今天我们要搭建的,是一套完全解耦、职责分离的终极形态靶场:
- 大脑 (K3s 控制平面):这 3 台虚拟机(10.0.10.10/20/30)将共同组成控制平面。为什么必须是 3 台? 因为 K3s 依赖内嵌的 etcd 数据库同步状态,它采用“选举机制”,必须有超过半数的节点存活才能工作。1 台挂了全军覆没;2 台挂 1 台不够半数,依然瘫痪;只有 3 台挂 1 台还剩 2 台(>50%),集群才能继续存活。这就是实现高可用的最低成本模型。
- 护卫 (kube-vip):既然有 3 个大脑,我们访问谁?
kube-vip会在集群外围生成一个虚拟入口(VIP:10.0.10.2)。不管底层哪台机器挂了,这个 IP 会自动、无缝地漂移到健康的节点上。你只需访问这个 VIP,永远不会失联。 - 灵魂 (Cilium):利用 eBPF 黑科技完全接管数据面网络,不仅消除传统 iptables 转发的性能损耗,还兼职负责内部网络分配和规则通信。
🧱 施工前置准备 (Requirements)
Section titled “🧱 施工前置准备 (Requirements)”在开干之前,请盘点你的赛博作案工具:
- 受害者们: 3 台已经装好纯净版 Ubuntu 22.04+ 的虚拟机(建议至少 2C2G)。
- 静态资产: - Master 01:
10.0.10.10- Master 02:
10.0.10.20 - Master 03:
10.0.10.30 - 集群 VIP:
10.0.10.2 - 业务 IP 池:
10.0.10.50 - 10.0.10.200
- Master 02:
- 指挥中心: 一台装好高颜值 SSH 工具(如 Termius)的电脑,准备多开窗口。
🗺️ 赛博靶场底层拓扑图 (Architecture Blueprint)
Section titled “🗺️ 赛博靶场底层拓扑图 (Architecture Blueprint)”在敲击键盘之前,请先将这张系统架构图刻在脑子里。搞懂了它,后面的排错将犹如探囊取物。
💡 图纸核心解析:
- 控制面护卫 (红圈):
kube-vip三兄弟随时在内网里抢地盘。只要还有一台机器活着,10.0.10.2这个大门就不会塌。 - 数据面发牌 (蓝框):
Cilium不仅接管了内部路由,还像个全自动的 DHCP 服务器一样,从10.0.10.50开始给咱们的业务发内网 IP,并向物理交换机广播。 - etcd 数据库同步 (紫色):数据库之间通过粗连线进行毫秒级的强同步。
🔄 流量到底是怎么跑的?(Traffic Flow)
Section titled “🔄 流量到底是怎么跑的?(Traffic Flow)”上面的架构图解决的是“组件怎么摆”。
但如果你还不清楚请求是怎么一步步走到底层容器里的,我们换个视角,剥离掉那些复杂的配置概念,只看最核心的数据流向(Data Path)。
在咱们的集群里,有两条互不干扰的高速公路:
💡 极简流量剖析:
- 走下路(管理线):当你在电脑上敲下
kubectl命令时,请求会打向红色 VIP(10.0.10.2)。kube-vip通过 ARP 广播 + Leader Election 确保这个 IP 始终绑定在一台健康的 Master 上,请求最终进入 API Server,并写入etcd。 - 走上路(业务线):当用户在浏览器访问服务时,请求会打向蓝色的 LoadBalancer IP(如
10.0.10.50)。 Cilium 会通过 L2 Announcement (ARP) 向局域网宣告“这个 IP 在某个节点上”,流量因此被引导到对应节点。 数据包进入节点后,Cilium eBPF 在内核态(早于 iptables)直接完成转发决策,通过 eBPF 程序在 TC / XDP 层对数据包进行重定向,将流量“瞬移”到目标 Pod,实现低延迟高性能访问。
- kube-vip:保证你能“连上 Kubernetes”
- Cilium:保证你的“服务能被访问”
- etcd:保证“集群不会失忆”
📜 官方蓝图 (Official Resources)
Section titled “📜 官方蓝图 (Official Resources)”遇到玄学问题,查官方文档永远比百度强。特别是下面这两份专门针对 K3s 适配的官方指引,是本次施工的核心参考图纸:
- 🌐 K3s 官方高可用指南:了解内置 etcd 的运作机制。
- 🛡️ kube-vip 官方 K3s 部署指南:专门针对 K3s 环境部署 kube-vip 的权威说明,也是本次高可用护卫配置的主要参考。
- 🐝 Cilium 官方 K3s 部署指南:在 K3s 上完美部署 Cilium 的标准答案与前置排雷说明。
- 🐝 Cilium 替换 kube-proxy 官方文档:eBPF 黑科技接管底层路由的核心发源地。
🎬 施工演示录像 (Video Walk-through)
Section titled “🎬 施工演示录像 (Video Walk-through)”🔨 核心施工流程 (Installation Steps)
Section titled “🔨 核心施工流程 (Installation Steps)”-
拨钟对表 (时钟同步防脑裂)
在所有 3 台虚拟机上执行。这是防止集群自杀的第一道防线。为了条理清晰,我们将它分为两步操作:
步骤 1.1:安装 QEMU Guest Agent 这能让虚拟机与 PVE 宿主机保持底层互动,不仅能进行基础时钟对齐,还能让你在 PVE 后台优雅地重启/关闭虚拟机。
Terminal window sudo apt update && sudo apt install qemu-guest-agent -ysudo systemctl enable --now qemu-guest-agent步骤 1.2:配置稳定的 NTP 时钟源
Terminal window # 1. 设置内网主 NTP 服务器 (⚠️ 请将 10.0.10.1 替换为你的真实网关 IP)sudo sed -i '/^#NTP=/c\NTP=10.0.10.1' /etc/systemd/timesyncd.conf# 2. 设置公网备用 NTP 服务器 (阿里云与国家授时中心,作为兜底)sudo sed -i '/^#FallbackNTP=/c\FallbackNTP=ntp.aliyun.com cn.pool.ntp.org' /etc/systemd/timesyncd.conf# 3. 重启服务并检查状态sudo systemctl restart systemd-timesyncdtimedatectl status稍等片刻,确认输出的信息中包含
System clock synchronized: yes,说明这三台机器的时间已经死死咬合在一起了。 -
安装helm 在所有节点安装helm
Terminal window # 安装helmsudo curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-4 | bash -
浇筑 1 号主控节点 (Master 01)
登录
10.0.10.10。这串命令是整个赛博靶场地基的核心。我们不仅显式声明了集群网段(避免未来与你的家庭 VPN 发生惨烈的路由冲突),更重要的是,我们通过一连串的--disable参数,无情地卸载了 K3s 原生的“傻瓜式”网络组件。Terminal window curl -sfL https://get.k3s.io | INSTALL_K3S_EXEC="server \--cluster-init \--tls-san 10.0.10.2 \--node-ip 10.0.10.10 \--cluster-cidr=10.60.0.0/16 \--service-cidr=10.61.0.0/16 \--flannel-backend=none \--disable-network-policy \--disable servicelb \--disable traefik \--disable-kube-proxy" sh -💡 包工头硬核解析:我们到底禁用了什么,为什么要禁?
为了给终极形态的网络底座腾出空间,这串命令执行了一场彻底的“大清洗”:
- 🔪 禁用
flannel与network-policy- 它是什么:K3s 默认的 CNI(容器网络接口)和网络策略控制器。
- 为什么禁:Flannel 默认走 VXLAN 隧道,封包解包有性能损耗,且网络策略比较基础。
- 用什么代替:Cilium。我们将用它实现基于 eBPF 的局域网原生直通路由(Native Routing),性能直接拉满。
- 🔪 禁用
servicelb- 它是什么:K3s 自带的轻量级负载均衡器(Klipper),靠占用宿主机端口来暴露服务。
- 为什么禁:功能简陋,且会与我们后续高级的 IP 分配机制产生端口和 IP 冲突。
- 用什么代替:Cilium 的 L2 Announcement。让 eBPF 直接从我们的 IP 池(
10.0.10.50-100)里抽调真实的内网 IP 发给业务服务。
- 🔪 禁用
traefik- 它是什么:K3s 捆绑安装的 Traefik Ingress 网关。
- 为什么禁:捆绑版通过晦涩的 HelmChart CRD 部署,你想改个配置极其痛苦,且版本更新完全受制于 K3s 发版。
- 用什么代替:手动 Helm 部署纯净版 Traefik v3。底层剥离干净后,我们将用标准企业级方法独立部署,拥有 100% 的掌控权。
- 🔪 禁用
kube-proxy- 它是什么:Kubernetes 经典的“交通警察”,通过在 Linux 里写海量的
iptables规则来转发集群流量。 - 为什么禁:
iptables是用来做防火墙的,不是用来做微服务路由的!当集群变大,规则匹配极其缓慢。 - 用什么代替:Cilium eBPF (kubeProxyReplacement=true)。把交通警察干掉,直接在网卡底层修立交桥,彻底消除 iptables 的历史包袱。
- 它是什么:Kubernetes 经典的“交通警察”,通过在 Linux 里写海量的
具体见官方文档
为了避免后续每次执行
kubectl命令都必须加sudo,或者频频遭遇permission denied权限拒绝,我们需要将 K3s 自动生成的认证文件复制到当前用户的.kube目录下,并赋予对应权限:Terminal window mkdir -p ~/.kubesudo cp /etc/rancher/k3s/k3s.yaml ~/.kube/configsudo chown $(id -u):$(id -g) ~/.kube/configecho "export KUBECONFIG=$HOME/.kube/config" >> ~/.bashrcsource ~/.bashrc🔍 初步验收:不要慌,它现在是个“植物人”
K3s 启动后,你可以敲下这行命令来看看你的 1 号节点状态:
Terminal window sudo kubectl get nodes - 🔪 禁用
-
召唤金牌护卫 (配置 kube-vip)
依然在
10.0.10.10上。这一步我们将引入 kube-vip,让 6443 入口实现真正的“大门不倒”。🔍 寻宝环节:版本号与网卡确认 为了保证教程的透明度,你可以通过以下官方指令查询 kube-vip 的最新稳定版本:
Terminal window # 查看当前官方发布的最新版本号 (需安装 jq)curl -sL https://api.github.com/repos/kube-vip/kube-vip/releases | jq -r ".[0].name"# 确认你的真实网卡名称 (在输出中找到带 10.0.10.10 的那个名字)ip a# 或者执行这个命令ip -o -4 addr show | awk '{print $2,$4}'🧱 分步施工:配置与镜像准备
Terminal window # 1. 准备目录并获取权限模板sudo mkdir -p /var/lib/rancher/k3s/server/manifests/sudo curl https://kube-vip.io/manifests/rbac.yaml -o /var/lib/rancher/k3s/server/manifests/kube-vip-rbac.yamlTerminal window # 2. 设置施工变量 (请修改为你自己的 IP 和网卡名)export VIP=10.0.10.2export INTERFACE=<你的网卡名>export KVVERSION="v1.1.2"Terminal window # 3. 预拉取护卫镜像sudo ctr image pull ghcr.io/kube-vip/kube-vip:$KVVERSION⚡ 核心生成:生成 kube-vip 部署清单 执行下面这个长命令。它的作用是让 kube-vip 容器跑一次“自我介绍”,并将生成的部署配置保存到 K3s 的自动部署目录。
Terminal window sudo ctr run --rm --net-host ghcr.io/kube-vip/kube-vip:$KVVERSION vip \/kube-vip manifest daemonset \--interface $INTERFACE \--address $VIP \--inCluster \--taint \--controlplane \--arp \--leaderElection | sudo tee /var/lib/rancher/k3s/server/manifests/kube-vip.yaml > /dev/null📖 命令参数“白话说明书” 为了让你死个明白,这几个参数分别代表了:
--interface: 告诉 kube-vip 在哪块物理网卡上广播 VIP 地址。--address: 指定我们要生成的那个虚拟 IP(10.0.10.2)。--inCluster: 声明这是在集群内运行,生成 DaemonSet 格式的配置。--taint: 关键!允许 kube-vip 运行在带有“污点”的主节点上(默认主节点是不跑业务的,不加这个它跑不起来)。--controlplane: 明确这是为控制平面 API Server 提供高可用。--arp: 开启二层 ARP 广播模式。不需要交换机支持 BGP,非常适合咱们 Homelab。--leaderElection: 开启“带头大哥”选举。多台机器会商量谁来接管 IP,防止冲突。
具体见官方文档
🔧 补强施工:注入免死金牌 这一步非常重要,由于 K3s 自动部署可能需要一点时间,请确认文件生成后再执行:
Terminal window # 补丁 1:注入最高调度优先级 (免死金牌,防止节点压力大时 kube-vip 被 K8s 驱逐)sudo sed -i '/hostNetwork: true/a \ priorityClassName: system-cluster-critical' /var/lib/rancher/k3s/server/manifests/kube-vip.yaml# 补丁 2:注入本地 API 指路牌 (强行指引它访问本机的 6443 端口,解决 Timeout 报错)sudo sed -i 's/env:/env:\n - name: KUBERNETES_SERVICE_HOST\n value: "127.0.0.1"\n - name: KUBERNETES_SERVICE_PORT\n value: "6443"/' /var/lib/rancher/k3s/server/manifests/kube-vip.yaml最后,提取你的集群钥匙 (Token)
Terminal window sudo cat /var/lib/rancher/k3s/server/node-token🔍 阶段验收:验证金牌护卫是否到岗
代码敲完了,现在我们要看看这个 VIP 到底有没有在你的局域网里“显灵”。
步骤 A:检查 Pod 是否正常启动 kube-vip 是以 DaemonSet 形式运行的。首先确认它的进程有没有在你的 1 号节点上跑起来:
Terminal window sudo kubectl get pods -n kube-system期望结果:看到
STATUS为Running。如果显示Pending,多半是--taint参数没加对,导致它不敢在主节点上落脚。步骤 B:检查 VIP 是否成功绑定网卡 这是最关键的一步。kube-vip 会在你的物理网卡上“挂载”一个额外的 IP。再次执行
ip a:Terminal window # ⚠️ 请将 <你的网卡名> 换成你自己的网卡名ip addr show <你的网卡名>期望结果:在输出中,除了你原本的
10.0.10.10,你应该能看到一行inet 10.0.10.2/32 ...。如果看到了这个/32的 IP,说明 kube-vip 已经强行接管了这条街道。步骤 C:连通性生死测试 在你的**个人电脑(Mac/Win)**打开终端,直接尝试去 ping 这个虚拟 IP:
Terminal window ping 10.0.10.2期望结果:如果能 ping 通,说明你的二层网络广播(ARP)工作正常。
步骤 D:API Server 业务验收 最后,我们看看这个 VIP 能不能带我们找到 K8s 的大门:
Terminal window curl -k https://10.0.10.2:6443/livez期望结果:你会收到一段包含
"message": "Unauthorized", "code": 401的 JSON 报错。步骤 E:查看vip在哪个节点下
Terminal window kubectl get lease plndr-cp-lock -n kube-system看
HOLDER这一列,写着谁的名字,10.0.10.2这个 VIP 就在谁的网卡上。步骤 F:审查图纸(验证注入是否成功) 确认我们刚才的
sed命令确实把“免死金牌”塞进去了:Terminal window sudo grep -C 2 "priorityClassName" /var/lib/rancher/k3s/server/manifests/kube-vip.yaml期望结果:你能看到
priorityClassName: system-cluster-critical和上面的hostNetwork: true对齐得严严实实。如果没输出,说明你没注入成功。 -
备用主控入列 (Master 02 & 03 加入)
登录
10.0.10.20和10.0.10.30。 注意看这里的--server参数,我们直接打向了 VIP 10.0.10.2。既然大门已经建好,就绝对不能再走 1 号节点的“后门”,这才是纯正的高可用。🔍 寻宝环节:再次确认本机 IP 在执行加入命令前,请分别在 Master 02 和 03 上确认自己的物理 IP:
Terminal window ip a记住那个用于集群内部通信的网卡 IP(例如
10.0.10.20)。🧱 施工:执行集群加入命令
Terminal window # 在 Master 02 上执行时,--node-ip 填 10.0.10.20(你实际规划的ip)# 在 Master 03 上执行时,--node-ip 填 10.0.10.30(你实际规划的ip)curl -sfL https://get.k3s.io | K3S_TOKEN="<替换为你的真实_TOKEN>" INSTALL_K3S_EXEC="server \--server https://10.0.10.2:6443 \--tls-san 10.0.10.2 \--node-ip <替换为当前机器的真实_IP> \--cluster-cidr=10.60.0.0/16 \--service-cidr=10.61.0.0/16 \--flannel-backend=none \--disable-network-policy \--disable servicelb \--disable traefik \--disable-kube-proxy" sh -我们这里也将 K3s 自动生成的认证文件复制到当前用户的
.kube目录下,并赋予对应权限:Terminal window mkdir -p ~/.kubesudo cp /etc/rancher/k3s/k3s.yaml ~/.kube/configsudo chown $(id -u):$(id -g) ~/.kube/configecho "export KUBECONFIG=$HOME/.kube/config" >> ~/.bashrcsource ~/.bashrc
🔍 阶段验收:多节点 etcd 状态查房
现在你有了三台 Master,集群应该已经开始进行内部的“民主选举”了。
步骤 A:检查节点名录 在任意一台机器上执行:
Terminal window sudo kubectl get nodes期望结果:你应该能看到三台机器全员到齐。虽然状态全是
NotReady(因为我们还没装 Cilium),但只要名字都在列表里,说明加入成功。步骤 B:查看 API 端点负载 (Endpoints)** 这是最硬核的验证。我们要看看 Kubernetes 内部大门背后,到底有几个保安在执勤:
Terminal window sudo kubectl get endpoints kubernetes -n default期望结果:你会看到
ENDPOINTS这一列,输出了类似10.0.10.10:6443,10.0.10.20:6443,10.0.10.30:6443的 IP 列表。这意味着你的 3 台物理机都已经成为 API Server 的合法入口,etcd 的高可用底座已完美浇筑!步骤 C:查看集群核心组件状态 (埋下伏笔)
控制平面大阵已经结成,我们最后来看看 K3s 内部的基础业务组件现在的生存状态:
Terminal window sudo kubectl get pods -n kube-system -o wide期望结果:你会看到咱们的金牌护卫
kube-vip正在坚挺地Running,但是coredns、metrics-server等原生组件,全部处于Pending(挂起排队)状态。 -
注入 eBPF 灵魂 (安装 Cilium 完全体)
回到
10.0.10.10的终端。此时你的集群处于没有网络的NotReady植物人状态。 我们将下载官方的 Cilium CLI,并用极其激进的参数来唤醒它:开启原生路由、全面接管伪装、切断不必要的七层代理(为了省内存),并开启二层广播。🧱 施工:安装并注入 Cilium
Terminal window # 1. 安装 Cilium CLI (自动拉取最新稳定版)CILIUM_CLI_VERSION=$(curl -s https://raw.githubusercontent.com/cilium/cilium-cli/main/stable.txt)CLI_ARCH=amd64if [ "$(uname -m)" = "aarch64" ]; then CLI_ARCH=arm64; ficurl -L --fail --remote-name-all https://github.com/cilium/cilium-cli/releases/download/${CILIUM_CLI_VERSION}/cilium-linux-${CLI_ARCH}.tar.gz{,.sha256sum}sha256sum --check cilium-linux-${CLI_ARCH}.tar.gz.sha256sumsudo tar xzvfC cilium-linux-${CLI_ARCH}.tar.gz /usr/local/binrm cilium-linux-${CLI_ARCH}.tar.gz{,.sha256sum}Terminal window # 2. 执行终极底层替换# ⚠️ 如果你的节点不在同一二层网络(例如 VLAN / 跨网段),请关闭:--set autoDirectNodeRoutes=falsecilium install \--set kubeProxyReplacement=true \--set k8sServiceHost=10.0.10.2 \--set k8sServicePort=6443 \--set ipam.operator.clusterPoolIPv4PodCIDRList="10.60.0.0/16" \--set ipv4NativeRoutingCIDR="10.60.0.0/16" \--set routingMode=native \--set autoDirectNodeRoutes=true \--set bpf.masquerade=true \--set endpointRoutes.enabled=true \--set l7Proxy=true \--set bandwidthManager.enabled=true \--set l2announcements.enabled=true \--set externalIPs.announcements.enabled=true \--set externalIPs.enabled=true \--set devices='{en+,eth+}' \--set operator.replicas=1 \--set resources.requests.cpu=100m \--set resources.requests.memory=128Mi📖 这堆长串参数到底干了啥? 对于 Homelab 玩家,我不建议无脑复制,这几个核心参数你必须懂:
- 🔪 干掉历史包袱
kubeProxyReplacement=true:这就是我们前面不装kube-proxy的原因。Cilium 利用 eBPF 深入 Linux 内核态,彻底接管了所有的网络流量转发。再也不用面对几万条低效的 iptables 规则了。
- 🛣️ 原生直通路由 (Native Routing)
routingMode=native&autoDirectNodeRoutes=true:抛弃了传统的 VXLAN 隧道封装。局域网内的 Pod 互访直接走 Linux 原生路由表,网络延迟降到最低,跑满万兆网卡不是梦。bpf.masquerade=true:利用 eBPF 处理 SNAT(源地址转换),比传统的 iptables MASQUERADE 快得多。
- 🔌 精准锁定“主干道” (物理网卡接管)
devices='{en+,eth+}':Homelab 的底层环境五花八门,你的节点网卡可能叫传统的eth0,也可能是 PVE 虚拟机里的ens18,或者是迷你主机直通的enp2s0。- 防翻车原理解析:这个带有正则通配符的参数明确指令 Cilium:“去把你的 eBPF 探针挂载到这些真正负责节点对外通信的主网卡上”。如果不加这个限制,Cilium 可能会“抓瞎”,错把探针挂载到内部的虚拟网桥(比如 Docker 遗留网卡或虚拟机内部桥接)上,直接导致数据包进了黑洞,集群网络瞬间瘫痪。精准认路,是跑满万兆的前提。
- ⚖️ 性能与功能的平衡术
l7Proxy=true:虽然会额外消耗约 150MiB 内存,但它解锁了 Cilium 的七层协议解析能力。没有它,Hubble 只能看个寂寞;有了它,你才能在监控中洞察每一次 HTTP 请求的细节。operator.replicas=1:在 3 节点的 Homelab 规模下,单副本 Operator 配合 K8s 的自愈能力已经足够稳健,多开一个副本除了浪费几十兆内存,并不能带来质的飞跃。
- 📢 化身二层发牌员
l2announcements.enabled=true:由于我们前面禁用了 Klipper (servicelb),开启这个参数后,Cilium 就能自己通过 ARP 协议,把后面生成的业务 IP 广播到局域网里,充当咱们的 LoadBalancer 发牌员。externalIPs.announcements.enabled=true:极其隐蔽的附属开关!除了 LoadBalancer,它确保 K8s 原生的ExternalIPs也能被二层网络正确广播,实现服务暴露的全场景覆盖。
- 🛡️ 抢占“低保”生存权 (Resource Requests)
resources.requests.cpu=100m与memory=128Mi:这是 K8s 的“资源请求”机制。Cilium 作为企业级网络插件,默认的预留资源预期是比较高的。如果我们不显式声明,它可能会向 K8s 申请过高的配额,导致我们只有 2G 内存的节点直接拒绝分配,Pod 永远卡在Pending状态。- 包工头原理解析:注意,这是
requests(低保),不是limits(封顶)。我们强行设定100m(0.1个CPU核)和128Mi内存,主要是向 K8s 调度器宣告:“这是我这具网络躯壳的最低生存口粮,只要节点还剩这点资源,就必须让我开机;而且系统再卡,也绝不能克扣我的这部分粮草!”。
具体见官方文档 ,cilium-cli
🔍 阶段验收:植物人满血复活
命令敲完后,大概需要等待 1-2 分钟让镜像拉取并启动。现在,见证奇迹的时刻到了。
步骤 A:Cilium 自检 在
10.0.10.10上执行官方的健康检查命令:Terminal window # 如果已经配置了环境变量,直接执行cilium status期望结果:你会看到极其舒适的全绿
OK状态。最重要的是,请盯紧这两行:KubeProxyReplacement: True(说明 eBPF 成功接管,老交警下班)Routing: Native(说明直通路由开启,没有隧道损耗)Cluster Pods: 3/3 managed by Cilium(说明所有 Pod 已被收编)
步骤 B:检查节点是否苏醒 还记得第 2 步里那个令人不安的
NotReady吗?现在再敲一次:Terminal window sudo kubectl get nodes期望结果:由于网络大动脉已经被 Cilium 彻底打通,三台 Master 节点的状态将全部华丽地转变为
Ready!这代表你的大脑与肢体已经完美连接。步骤 C:查看 Cilium 集群
Terminal window # 查看底层工兵状态sudo kubectl get pods -n kube-system -l k8s-app=cilium -o wide期望结果:你应该能看到 3 个
cilium-xxxxx的 Pod 分别稳定运行在 master-01/02/03 上。步骤 D:查看全家福 (Pod 状态深度检查)
Terminal window sudo kubectl get pods -n kube-system -o wide期望结果:你会发现
coredns、metrics-server已经拿到了以10.60.x.x开头的 Pod IP,并且状态全部变为了Running。🔭 安装Cilium Hubble UI 既然用了 Cilium,怎么能不装 Hubble?这是一个能让你拥有上帝视角的网络流量动态拓扑图。谁在连谁,哪个包被丢弃了,一目了然。
🛠️ 终极排错照妖镜 如果你想知道 Cilium 到底吃进去了哪些底层配置,千万别去翻最初的安装脚本,直接在终端敲这个命令:
Terminal window helm get values -n kube-system cilium它会把当前真正在底层运行的所有 Helm 参数(包括默认生成的和我们手动设置的)原形毕露,这是后期排错的绝佳利器!
- 🔪 干掉历史包袱
-
发放数据面牌照 (配置 Cilium L2 IP 池)
底层大动脉已经通了,但谁来给未来的业务服务(比如你的博客、网盘、面板)发 IP?在传统的云厂商那里是外置的 ELB,但在咱们的 Homelab 里,我们直接甩给 Cilium 一本“支票簿”,让它兼职当发牌员。
🧱 施工:编写并发放牌照 在
10.0.10.10(Master 01)上创建配置文件。创建并编辑文件
cilium-lb-pool.yaml:---apiVersion: "cilium.io/v2"kind: CiliumLoadBalancerIPPoolmetadata:name: "homelab-pool"spec:blocks:- start: "10.0.10.50" # ⚠️ 替换为你的真实起始 IPstop: "10.0.10.200" # ⚠️ 替换为你的真实结束 IP---apiVersion: "cilium.io/v2alpha1"kind: CiliumL2AnnouncementPolicymetadata:name: "default-l2-policy"spec:interfaces:- ^<你的网卡名> # ⚠️ 极度危险:千万换成你自己的物理网卡名!- ^<你的网卡名2> # 其他网卡loadBalancerIPs: true # ⚠️ 致命开关:允许向局域网广播 LB IPexternalIPs: true # ⚠️ 致命开关:允许广播 External IP执行应用:
Terminal window kubectl apply -f cilium-lb-pool.yaml📖 包工头原理解析
CiliumLoadBalancerIPPool:这就是那本支票簿。以后你在 K8s 里只要声明一个type: LoadBalancer的服务,Cilium 就会自动从这段 IP 里抽一个没用过的发给它。CiliumL2AnnouncementPolicy:这是广播许可证。它告诉 Cilium:“拿到 IP 后,请通过指定的网卡,用二层 ARP 协议向局域网里大喊,告诉家里所有的设备这个新 IP 在我这里!”
关于更多CiliumL2AnnouncementPolicy见官网文档
🔍 阶段验收:支票簿入库核验
步骤 A:检查配置是否被 Cilium 吞下 执行以下命令查看我们刚建的自定义资源(CRD):
Terminal window kubectl get CiliumLoadBalancerIPPoolkubectl get CiliumL2AnnouncementPolicy期望结果:终端应返回
homelab-pool和default-l2-policy,说明配置已生效且没有冲突。步骤 B:终极实战演习(封顶大吉!) 光看配置没用,发牌员到底能不能干活,我们得拉一个真实的项目出来“遛遛”。
我们将部署一款极具赛博朋克风格的轻量级 Kubernetes 可视化面板 —— Headlamp,并向 Cilium 申请我们的第一张 LoadBalancer 业务 IP(10.0.10.50)!如果能通过这个 IP 在浏览器里直接打开面板,那么恭喜你,这套终极高可用架构的底层网络正式宣告“封顶”!
🏗️ 8. 扩充工兵连:加入 Agent 子节点 (Adding Worker Nodes)
Section titled “🏗️ 8. 扩充工兵连:加入 Agent 子节点 (Adding Worker Nodes)”虽然 3 台 Master 构成了坚不可摧的“大脑”,但在咱们这种内存只有 2G 的“受害者”节点上,大脑已经快被 Cilium 和 etcd 榨干了。为了让业务(比如下一篇的容器化应用)有更宽敞的住处,我们需要引入只干活、不思考的 Agent 节点。
-
工兵前置整备 (Requirements)
在新节点(如
192.168.100.182)上,执行基础初始化。必须安装存储依赖,否则后续 Longhorn 无法挂载硬盘。Terminal window # 安装基础工具、NFS 客户端和 iSCSI 组件 (Longhorn 必需)sudo apt update && sudo apt install -y nfs-common open-iscsisudo systemctl enable --now iscsid# 永久关闭 Swap (K8s 运行稳定性要求)sudo swapoff -asudo sed -i '/swap/s/^/#/' /etc/fstab -
提取集群入场券 (Get Token)
回到你的 Master 01 节点,取出那串密钥:
Terminal window sudo cat /var/lib/rancher/k3s/server/node-token -
奔赴工地:执行加入命令
登录到你的子节点。注意,这里的
K3S_URL必须指向你的 VIP!Terminal window # ⚠️ 请将 <TOKEN> 替换为你刚才提取的密钥# ⚠️ 请将 --node-ip 替换为当前子节点的真实 IPcurl -sfL https://get.k3s.io | KUBERNETES_SERVICE_HOST=10.0.10.2 \K3S_URL=https://10.0.10.2:6443 \K3S_TOKEN="<替换为你的真实_TOKEN>" \INSTALL_K3S_EXEC="agent --node-ip <当前子节点_IP>" sh -🔍 包工头硬核解析:为什么加了 KUBERNETES_SERVICE_HOST? 由于我们禁用了
kube-proxy,新节点在加入的一瞬间可能会因为找不到本地路由而无法联系上 API Server。通过显式声明环境变量,我们强行给新兵指明了 VIP 这座“灯塔”的方向。 -
点名验收 (Verify Nodes)
回到你的 指挥中心 (Mac/Win),查看全家福:
Terminal window kubectl get nodes -o wide期望结果:你会看到一个角色为
<none>的新节点。稍等 1 分钟,它的状态会从 NotReady 变为 Ready。 -
🚨 紧急避坑:打通跨网段大动脉 (解决 Longhorn 插件无限重启)
如果你加入的新节点与 Master 节点不在同一个物理网段(例如 Master 在
10.0.10.x,而子节点在192.168.100.x),你会发现新节点虽然Ready,但上面的longhorn-csi-plugin容器会陷入无限重启,日志疯狂报错 DNS 超时(i/o timeout)。🔍 包工头硬核解析: 这是因为咱们之前配置 Cilium 时开启了
Native Routing(原生直通路由)。跨网段通信时,物理路由器根本不认识咱们 K8s 内部的10.60.x.xPod 网段,直接把通信包当成非法流量丢弃了。🧱 抢修施工:热切换至 VXLAN 隧道模式 回到你的 Master 01 节点,执行以下命令。这能让 Cilium 在物理机之间建立 UDP 加密暗道,强行“骗过”底层路由器:
Terminal window # 1. 确保已添加 Cilium 官方 Helm 仓库helm repo add cilium https://helm.cilium.io/helm repo update# 2. 强制热更新:切断 Native 路由,开启 VXLAN 隧道# (这里用 10.60.0.0/16 骗过 Helm 的死板校验语法)helm upgrade cilium cilium/cilium \--namespace kube-system \--reuse-values \--set routingMode=tunnel \--set tunnelProtocol=vxlan \--set autoDirectNodeRoutes=false \--set ipv4NativeRoutingCIDR="10.60.0.0/16" \--force-conflicts配置刷入后,必须强制底层的网络保安重新交接班:
Terminal window kubectl rollout restart ds/cilium -n kube-system稍等片刻,等所有
cilium-agent重新恢复 Running 后,跨网段的暗道就彻底打通了。再去查看那个报错的 Longhorn 插件,它已经奇迹般地变绿干活了!
🚪 终极交付:提取指挥权与防线极限跑分
Section titled “🚪 终极交付:提取指挥权与防线极限跑分”地基彻底打完了!在引入具体的业务(比如我们下一篇要搞的 Headlamp 可视化面板)之前,我们需要做最后的交付验收。
🔑 步骤 A:提取集群最高指挥权 (Kubeconfig)
Section titled “🔑 步骤 A:提取集群最高指挥权 (Kubeconfig)”你总不能以后每次折腾集群,都要用 SSH 连到服务器的黑框框里。我们要把集群的“遥控器”拿回你的个人电脑(Mac/Win)。
在 10.0.10.10 服务器上执行:
sudo cat /etc/rancher/k3s/k3s.yaml配置指南:
- 复制终端里输出的全部 YAML 文本。
- 回到你自己的个人电脑(Mac/Windows),打开或新建
~/.kube/config文件,将内容粘贴进去。 - 关键一步:找到
server: https://127.0.0.1:6443这一行,无情地把 IP 修改为你那扇永不宕机的大门 —— VIPhttps://10.0.10.2:6443。 - 在你的个人电脑终端里敲下
kubectl get nodes。如果能看到节点列表,说明遥控器配对成功!以后你就可以优雅地在本地掌控整个赛博工地了。 - 如果你有多个集群,可以设置不同名称,例如
~/.kube/N100config命令行执行export KUBECONFIG=~/.kube/N100config就可以切换到对应集群 官方文档:
🏎️ 步骤 B:赛博防线极限跑分 (Cilium Connectivity Test)
Section titled “🏎️ 步骤 B:赛博防线极限跑分 (Cilium Connectivity Test)”是骡子是马,拉出来跑跑。Cilium 官方提供了一个企业级的连通性测试工具,它会自动拉起大量的 Pod,进行跨节点、跨策略的疯狂互殴测试。
cilium connectivity test此时你可以去泡杯咖啡。当你回来,如果能看到满屏绿色的 ✅ [cilium-test-1] All XX tests (XX actions) successful, XX tests skipped, 0 scenarios skipped.,那么恭喜你!这套 K3s + kube-vip + Cilium 的终极硬核底座,已经完美通过了企业级的极限检验!
测试后删除测试数据
kubectl delete ns cilium-test-1 cilium-test-ccnp1 cilium-test-ccnp2🎯 下一步施工计划: 纯命令行的世界太枯燥了。现在,带上你的安全帽,跟我去申请第一个发牌员 IP,部署极具赛博朋克风格的轻量级 Kubernetes 面板! 👉 实战演练:部署 Headlamp 仪表盘检验集群战力
📂 竣工归档 (资产建档)
Section titled “📂 竣工归档 (资产建档)”老规矩,把核心参数记录到知识库里,防止半年后遗忘。
## 🚀 K3s-HA 核心资产备忘 (替换为你的参数)- **网段规划**: Pod CIDR: `10.60.0.0/16` | Service CIDR: `10.61.0.0/16`- **控制平面 VIP**: `10.0.10.2` (由 kube-vip 提供 ARP 宣告)- **业务负载均衡池**: `10.0.10.50 - 200` (由 Cilium eBPF L2 提供)- **底层特性**: 完全抛弃 kube-proxy,开启 Native Routing,关闭自带 Traefik。🔗 赛博包工头的秘密书签 (Useful Links)
Section titled “🔗 赛博包工头的秘密书签 (Useful Links)”- 💣 K3s 官方卸载脚本
- 包工头点评:在 Homelab 折腾,推倒重来是家常便饭。如果集群被你玩炸了,千万别直接删虚拟机,在节点上执行
k3s-uninstall.sh,这能把网络规则和文件残留清理得干干净净。
- 包工头点评:在 Homelab 折腾,推倒重来是家常便饭。如果集群被你玩炸了,千万别直接删虚拟机,在节点上执行
❓ 常见问题与解答 (Q & A)
Section titled “❓ 常见问题与解答 (Q & A)”[Q] 为什么要给 kube-vip 打最高优先级?
[A]: 在资源吃紧的 Homelab 环境里(比如你跑了个转码吃满 CPU 的服务),Kubernetes 的驱逐机制六亲不认。如果不给 kube-vip 免死金牌,它一旦被干掉,整个集群的控制平面大门就直接消失了。
[Q] 为什么分配了 LoadBalancer IP,但在宿主机执行
[A]: 这是 Cilium eBPF 的“降维打击”。IP 并没有挂载在 Linux 内核的网络栈上,而是直接存在于 eBPF 的内存映射表中。流量在进入网卡的瞬间就被劫持并转发给容器了,Linux 内核全程甚至都不知道这个 IP 的存在。ip a 看不到它?
[Q] 业务分配了 IP,局域网能访问,但 Ping 却丢包或超时?
[A]: 正常现象。Cilium 的 L2 LB 默认只放行 Service 定义的端口(如 TCP 80)。由于这个 VIP 并不真实存在于宿主机内核,宿主机不会自动回复 ICMP 请求。这反而是一种天然的安全屏障。
[Q] 未来加入不同网卡名(如 eth0)的机器,会导致网络瘫痪吗?
[A]: 不会。由于我们在 Helm 配置中使用了 devices="en+,eth+" 正则,并在 L2 策略中预留了匹配规则,新节点会自动识别自己的物理大门并上岗,实现了“异构节点”的自适应兼容。
[Q] 部署完成后,想修改或追加 Cilium 的底层参数怎么办?
[A]: 绝对不要卸载重装!作为架构师,我们要习惯使用 Helm 进行“热更新”。操作时有两步铁律:
- 必须携带护身符:使用
upgrade命令时,必须带上--reuse-values参数。它会继承你之前所有的老配置,只覆盖或追加你新写的--set,否则之前的网络地基会被瞬间清空! - 强制交接班:Helm 更新的只是 K8s 里的“图纸”(ConfigMap)。必须要重启底层的
cilium-agent,保安们才会按照新图纸上岗。
标准施工命令:
# 1. 刷新配置图纸helm upgrade cilium ./cilium \ --namespace kube-system \ --reuse-values \ --set <你的新参数>=<值>
# 2. 强制底层保安重新加载配置kubectl rollout restart ds/cilium -n kube-system📋 工地日常巡检秘籍
Section titled “📋 工地日常巡检秘籍”➡️ 下一步施工图纸 (Next Steps)
Section titled “➡️ 下一步施工图纸 (Next Steps)”赛博地基虽然打好了,但现在的集群还只是一个没有记忆、无法与外界通信的“孤岛”。接下来的施工顺序极其关键,请严格按步骤推进:
- 🚦 流量网关:部署 Traefik v3 与 Gateway API
- 任务:替换掉被我们卸载的 K3s 默认网关,让外部流量优雅地根据域名流入咱们的赛博靶场。
- 🛡️ 内网穿透:集成 Cloudflare Tunnel
- 任务:没有公网 IP 也能建站。安全打穿内网,把咱们的服务发布到互联网上。
- 💾 数据堡垒:部署 Longhorn 分布式存储
- 任务:(核心前置节点) 没有持久化存储的 Kubernetes 只是没有记忆的鱼。我们将把 3 台虚拟机的剩余硬盘捏合成一个高可用存储池,为数据库和核心业务提供保障。
- 🐙 GitOps 革命:引入 Argo CD
- 任务:(强烈建议在 Longhorn 完成后再搞) 抛弃手敲
kubectl apply的低级趣味。让 GitHub 仓库成为你集群的唯一真理,实现“代码即基建”的自动化部署。
- 任务:(强烈建议在 Longhorn 完成后再搞) 抛弃手敲