KubeEdge边缘节点服务暴露:MetalLB负载均衡器部署实践

发布时间:2026/10/18 19:28:00
KubeEdge边缘节点服务暴露:MetalLB负载均衡器部署实践
简介面向Kubeedge初学者的完整部署资源包围绕CentOS 7.9、Kubernetes v1.22.17与Kubeedge v1.13.1交付全套集成安装素材。除了覆盖kubeadm建集群、Kubeedge v1.13.1安装还详细演示了采用MetalLB负载均衡器将边缘服务以LoadBalancer类型对外暴露的方式解决边缘节点网络接入与实际流量调度问题。压缩包共15个文件约474.64MB6个tar镜像包内置coreedge、kubeedge、nginx、calico、metallb等离线镜像7个yaml配置文件对应网络插件、MetalLB组件、地址池和负载均衡测试实例另有keadm工具gz包与一份完整部署md文档。已有242人学习下载。从环境准备、集群创建、边缘节点接入到MetalLB配置、实例验证各环节均有对应素材读者可按文档顺序核对执行大幅缩短环境搭建和问题排查时间尤其适合K8s初级运维、边缘计算研究者以及正在尝试KubeedgeLoadBalancer方案的开发者。1. KubeEdge装上以后服务IP才是最后一公里边缘节点上的服务到底怎么暴露 IP这是很多人部署完 KubeEdge 后第一个卡住的地方。NodePort 端口不规整hostNetwork 又没法在多副本间做负载均衡内网设备的接入地址漂来漂去运维想固定一个 VIP 都难。这篇记录的是 CentOS 7.9 K8s v1.22.17kubeadm 方式 KubeEdge v1.13.1 MetalLB 负载均衡器的一条完整部署链路目标就是让边缘服务拿到稳定、可预期的 LoadBalancer 地址。压缩包里带了镜像文件、全套 yaml 和一份部署文档离线和内网环境都能照着重现。我完整走了一遍确实能跑通但中间几个坑很隐蔽这篇把参数、验证方法和踩坑点都留出来。2. 先把 K8s v1.22.17 集群装扎实kubeadm 初始化与 Calico 网络2.1 系统准备CentOS 7.9 的内核与内核参数CentOS 7.9 默认内核是 3.10跑 K8s v1.22.17 能启动但 iptables 的 nf_conntrack 模块经常报错尤其是桥接流量过滤那一环一不注意 Pod 之间的通信就时好时坏。我一般先把内核升到 5.4 以上再关 swap最后调内核参数。swapoff -a sed -i / swap / s/^/#/ /etc/fstabcat EOF /etc/sysctl.d/k8s.conf net.bridge.bridge-nf-call-iptables 1 net.bridge.bridge-nf-call-ip6tables 1 net.ipv4.ip_forward 1 vm.swappiness 0 EOF sysctl --system说明br_netfilter 模块必须先加载否则 iptables 规则不会作用到 bridge 流量后续 Calico 的转发链会拦不住包。顺手执行modprobe br_netfilter更稳妥。sysctl 里ip_forward一定要开MetalLB 做 L2 通告时宿主机要转发到达 VIP 的报文。然后是 kubeadm、kubelet、kubectl版本必须钉死在 1.22.17cat EOF /etc/yum.repos.d/kubernetes.repo [kubernetes] nameKubernetes baseurl你的镜像源/kubernetes/yum/repos/kubernetes-el7-x86_64/ enabled1 gpgcheck0 EOF yum install -y kubelet-1.22.17 kubeadm-1.22.17 kubectl-1.22.17 systemctl enable --now kubelet说明baseurl 里的镜像源地址按实际可用的内网镜像站替换gpgcheck 设 0 是为了跳过签名校验离线环境更省事。三个 RPM 版本必须对齐kubelet 版本低于 apiserver 会有一堆兼容告警高版本又可能握手失败踩过一回就长记性了。2.2 镜像预载离线包里的 image.tar压缩包里 image.tar 包含 pause、etcd、kube-apiserver、kube-controller-manager、kube-scheduler、kube-proxy、coredns 这些基础镜像。在线环境可以直接kubeadm config images pull内网环境就必须手动导入。docker load image.tar说明默认 CRD 用 docker 的情况下docker load导入后镜像对 kubelet 直接可见。确认几个关键镜像在不在docker images | grep -E kube-apiserver|etcd|coredns注意如果控制面用 containerddocker load导入的镜像对 containerd 不可见得用ctr -nk8s.io images import换一条路。我这里统一用 docker包括 KubeEdge 边缘端也用 docker避免两套运行时切换引入额外的排错变量。2.3 kubeadm init定好 Pod 网段与 API 地址主节点云端节点初始化命令kubeadm init \ --apiserver-advertise-address192.168.1.10 \ --kubernetes-versionv1.22.17 \ --pod-network-cidr10.244.0.0/16 \ --service-cidr10.96.0.0/12参数说明--apiserver-advertise-address必须写成云端节点内网 IP千万别写成公网地址或者注释掉否则 kubelet、kubectl、以及后面的 KubeEdge CloudCore 全会连不上 apiserver。--pod-network-cidr用 10.244.0.0/16因为后面 Calico 的 yaml 默认按这个网段配置两边不一致会让 Pod 一直 ContainerCreating。初始化完成后配置 kubectlmkdir -p $HOME/.kube cp -i /etc/kubernetes/admin.conf $HOME/.kube/config kubectl get nodes说明admin.conf 如果权限不对kubectl 会直接报 connection refused最常见的是 chown 没做。复制完把属主改成当前用户chown $(id -u):$(id -g) $HOME/.kube/config一步到位。2.4 Calico 网络为什么这里是必选项压缩包里的 calico.yaml 是手工套件版应用前先把 Pod 网段改成和 init 时一致的sed -i s#192.168.0.0/16#10.244.0.0/16# calico.yaml kubectl apply -f calico.yaml说明Calico 默认 IP 池是 192.168.0.0/16和 kubeadm init 里的 10.244.0.0/16 对不上时calico-node 的 IPIP 隧道路由会错乱。改成一致后等 calico-node、coredns 都 Running 再继续kubectl get pods -n kube-system -o wide为什么选 Calico 而不是 FlannelKubeEdge 边缘端很多场景是跨网段组网Flannel 的 VXLAN 在跨二层时需要额外维护 VTEP麻烦。Calico 的 BGP IPIP 对三层网络穿透更友好边缘节点分布在不同内网段时收敛也更快。这一步不 Ready后面的 CloudCore 没法正常注册边缘节点。3. KubeEdge v1.13.1 部署CloudCore 与 EdgeCore 配对全过程3.1 准备证书与 Tokenkeadm genCertScript 的用法CloudCore 和 EdgeCore 之间走 HTTPS WebSocketv1.13.1 默认端口是 10002需要 CA 证书和 token。keadm 提供了证书生成脚本tar xf keadm-v1.13.1-linux-amd64.tar.gz cd keadm-v1.13.1-linux-amd64 ./keadm genCertScript --cloudcoreIP192.168.1.10 ls /etc/kubeedge/certs/说明--cloudcoreIP必须写云端节点的内网 IP证书里的 SAN 就是它。后续 EdgeCore 连接时校验证书域名这里写错的话WebSocket 握手会报 x509 错误现象极其隐蔽日志里只一行 certificate error。Token 生成./keadm token create说明v1.13.1 的 token 是 CA 签发的临时凭证EdgeCore 加入时需要带上。每个 token 默认有效期较短如果隔天再 jointoken 已经过期直接 regenerate。旧版 keadm 生成的 token 在 v1.13.1 上不通用版本对齐这条贯穿整个部署过程。3.2 CloudCore 安装components.yaml 与 coreedge.tar压缩包里的 coreedge.tar 是 CloudCore 和边缘组件的镜像合集docker load coreedge.tar kubectl create ns kubeedge kubectl apply -f components.yaml说明components.yaml 里定义 CloudCore 的 Deployment、Service 和 RBAC。关键参数在 Deployment 环境变量里的 advertiseAddress必须改成 192.168.1.10Service 默认 ClusterIP端口 10002。v1.13.1 的 CloudCore 默认监听 HTTPS 10002不是旧版的 HTTP 10000。验证 CloudCore 起来没有kubectl get pods -n kubeedge kubectl logs -n kubeedge -l k8s-appkubeedge日志里看到 CloudCore 启动成功的标志性输出就算是活了。如果一直 CrashLoopBackOff先看镜像是启动脚本缺参数还是 advertiseAddress 配置没生效。3.3 EdgeCore 安装边缘端节点加入边缘节点上导入 kubeedge.tar然后执行 jointar xf kubeedge.tar ./keadm join \ --cloudcore-ipport192.168.1.10:10002 \ --tokentoken \ --edgenode-nameedge-node-01说明--edgenode-name建议显式指定不指定会用 hostname内网机器 hostname 一旦重复两个边缘节点会互相把对方踢下线。--skip-check-certificates这个参数不建议加除非你完全确认证书没问题否则等于让安全校验形同虚设。EdgeCore 启动后确认服务状态systemctl status edgecore journalctl -u edgecore -f日志能看到 WebSocket 连接建立成功随后边缘节点信息上报到云端。如果连接一直在 retry大概率是 token 过期或 10002 端口不通第 5 章展开说。3.4 云端确认节点状态kubectl get nodes -o wide看到边缘节点状态 Ready 后打个标签方便管理kubectl label node edge-node-01 node-role.kubernetes.io/edge说明这个标签让控制面把边缘节点和云端节点区分开。KubeEdge 调度器会优先考虑打了 edge 标签的节点方便后续把工作负载放到边缘侧。手动打标签是为了面板更清晰不打也不影响调度但建议养成习惯。边缘节点如果一直 NotReady先回头看 edgecore 的 WebSocket 日志不要急着重置。4. MetalLB 负载均衡器给边缘服务分配稳定的 VIP4.1 部署 MetalLBmetallb-native.yaml 与 IP 池MetalLB 是裸机环境下常用的负载均衡器实现通过 ARP 把 LoadBalancer IP 通告到二层网络。压缩包里 metallb-native.yaml 是 v0.13 之后的 CRD 版本docker load metallb_image.tar kubectl apply -f metallb-native.yaml说明v0.13 之后 MetalLB 把 IP 池配置从 ConfigMap 换成了 CRD所以压缩包里多了 first-ipaddresspool.yaml 和 l2-forward.yaml。先确认 controller 和 speaker 两个组件都起来了kubectl get pods -n metallb-system如果 speaker pod CrashLoopBackOff绝大多数是接口参数或 memberlist 密钥问题具体在第 5 章。接着配置 IP 池kubectl apply -f first-ipaddresspool.yaml kubectl apply -f l2-forward.yamlfirst-ipaddresspool.yaml 的基础内容apiVersion: metallb.io/v1beta1 kind: IPAddressPool metadata: name: edge-pool namespace: metallb-system spec: addresses: - 192.168.1.200-192.168.1.210说明地址段必须和边缘节点在同一个二层网络MetalLB 的 L2 模式靠 ARP 应答来认领 VIP跨三层是通告不通的。IP 范围要避开 DHCP 地址池不然局域网里其他设备可能被误分配这个 IP冲突之后流量就乱了。l2-forward.yaml 是 L2AdvertisementapiVersion: metallb.io/v1beta1 kind: L2Advertisement metadata: name: edge-l2 namespace: metallb-system spec: ipAddressPools: - edge-pool说明L2Advertisement 不指定 interfaces 时会在所有网卡上应答 ARP。生产环境建议加上spec.interfaces: [ens33]避免多网卡机器上 VIP 被内网其他网段截胡。提示这个 l2-forward.yaml 虽然名字像转发策略其实是 L2Advertisement。只建 IP 池不应用通告配置LoadBalancer 会一直 Pending。4.2 用 nginx 测试 LoadBalancer压缩包里的 nginx.yaml 和 nginx-loadbalancer.yaml 是现成的测试样例kubectl apply -f nginx.yaml kubectl apply -f nginx-loadbalancer.yamlnginx-loadbalancer.yaml 里的 Service 定义apiVersion: v1 kind: Service metadata: name: nginx-lb spec: type: LoadBalancer selector: app: nginx ports: - port: 80 targetPort: 80应用后查看分配结果kubectl get svc nginx-lb看到 EXTERNAL-IP 出现 192.168.1.200说明 MetalLB 分配成功。在局域网内任意一台机器上curl http://192.168.1.200能返回 nginx 默认页整条链路就通了。这一步验证的不只是 MetalLB还包括 Service 到 Endpoint 的转发、以及边缘节点上的 kube-proxy 规则是否生效。4.3 为什么选 LoadBalancerNodePort 与 hostNetwork 的边界给边缘服务选暴露方式我的判断依据方式端口副本扩展VIP 稳定性NodePort30000-32767 固定范围同节点端口冲突端口不标准hostNetwork宿主机端口同 IP 无法多副本依赖宿主机 IPLoadBalancerMetalLB标准 80/443无端口冲突固定 VIPNodePort 在 v1.22.17 下默认范围是 30000-32767客户端要记一个随机高位端口防火墙上漏放一条规则就全部访问失败。hostNetwork 把 Pod 和宿主机网络混在一起多副本时端口必然冲突边缘节点 IP 变动之后服务地址也跟着漂。MetalLB 给的 VIP 是稳定的对边缘网关、数据采集服务这种需要固定回调地址的场景很重要。这个项目用 nginx 做验证很合理因为它同时验证了流量从 VIP 到 Service 再到 Pod 的完整转发链。5. 避坑排查五条血泪记录5.1 kubeadm init 卡在 waiting for kubelet现象kubeadm init 执行后一直卡在 waiting for kubelet几分钟后报错退出。原因CentOS 7.9 默认内核 3.10 缺 br_netfilterdocker 的 iptables 规则没生效也可能是 kubelet 的 cgroup 驱动与 docker 不一致。解决先modprobe br_netfilter再检查 kubelet 配置里 cgroup 驱动echo KUBELET_KUBEADM_ARGS--cgroup-driversystemd /etc/sysconfig/kubelet systemctl daemon-reload systemctl restart kubelet kubeadm reset重新 init 就能过。这个坑几乎每个新环境都会踩一次先把内核模块和 cgroup 对齐后面省一半排错时间。5.2 EdgeCore 连接 CloudCore 报 10002 拒绝现象keadm join 后edgecore 日志反复出现 failed to connect to wss://192.168.1.10:10002。原因CloudCore 的 advertiseAddress 还是默认值或者 kubeedge 命名空间下没有对应的 Service10002 端口根本没有服务在监听。解决检查 CloudCore 的 Service 和 Deployment 配置kubectl get svc -n kubeedge kubectl edit -n kubeedge deployments.apps cloudcore把 advertiseAddress 改成 192.168.1.10 后重新 apply。同时确认云端节点防火墙放行 10002 端口。注意 v1.13.1 的 CloudCore 是 HTTPS 10002别在别的地方开着 10000 凑合用协议和端口都得对上。5.3 MetalLB speaker Pod CrashLoopBackOffmemberlist 加密密钥现象metallb-speaker 日志报 cannot join memberlist反复重启。原因v0.13 默认启用 memberlist 加密而 metallb-native.yaml 如果是从旧 ConfigMap 版本拼凑过来的memberlist secret 缺失或不完整。解决删掉现存的 memberlist secret 重新应用kubectl delete secret memberlist -n metallb-system kubectl apply -f metallb-native.yaml这个坑经常在复用旧 yaml 时触发直接删 secret 让 MetalLB 重新生成是最快的后悔药。5.4 LoadBalancer 一直 Pending现象svc 状态停在 ExternalIP describe 也看不到明显报错。原因IPAddressPool 没建、L2Advertisement 没应用或者地址段和节点根本不在同一二层网络。解决kubectl get ipaddresspool -n metallb-system kubectl get l2advertisement -n metallb-system确认池子和通告配置都在。如果池子存在但始终不分配看看这个 IP 是不是已经被另一个 Service 占用MetalLB 同一 VIP 不会重复分配。另外地址段和节点网段不一致时L2 通告是发不出去的。5.5 CloudCore 与 EdgeCore 版本不一致导致的握手失败现象边缘节点一直 NotReadyedgecore 日志报证书相关错误或者握手成功后状态又掉线。原因混用了 v1.12 和 v1.13.1 的 keadm证书签名算法和协议细节不匹配。解决keadm、CloudCore、EdgeCore 全部统一到 v1.13.1证书重新生成rm -rf /etc/kubeedge/ ./keadm reset ./keadm genCertScript --cloudcoreIP192.168.1.10重新 join。版本对齐是 KubeEdge 部署里最容易被忽略的一环压缩包里既然全套都是 v1.13.1就别从历史目录翻旧 keadm 出来混用。补充一条边缘端系统时间不同步也会导致证书校验失败。装完先同步一次时间再看要不要排查其他问题省得绕着证书转半天。6. 验证矩阵与一键脚本把 e2e 链路固化6.1 验证矩阵链路检查命令期望结果K8s 集群kubectl get nodes云端节点 ReadyKubeEdgekubectl get nodes -l node-role.kubernetes.io/edge边缘节点 ReadyMetalLBkubectl get pods -n metallb-systemcontroller 和 speaker RunningLoadBalancerkubectl get svc nginx-lbEXTERNAL-IP 是 192.168.1.200端到端curl http://192.168.1.200返回 nginx 默认页6.2 一键验证脚本我习惯把这套检查合并成脚本每次部署完先跑一遍再交付#!/bin/bash # e2e-check.sh echo Node Status kubectl get nodes -o wide | awk {print $1, $2} echo Edge Node kubectl get nodes | grep -i edge || echo edge node not ready echo MetalLB kubectl get pods -n metallb-system --field-selectorstatus.phase!Running echo Service VIP kubectl get svc nginx-lb -o jsonpath{.status.loadBalancer.ingress[0].ip} echo curl -s -o /dev/null -w HTTP %{http_code}\n http://$(kubectl get svc nginx-lb -o jsonpath{.status.loadBalancer.ingress[0].ip})逻辑说明前三段分别检查节点状态、边缘节点是否 Ready、MetalLB 组件是否有非 Running 的 Pod最后一段从 Service 里取出 EXTERNAL-IP 并做 HTTP 探活。awk 取节点状态用的是第二列NotReady 会直接显示出来不用再开一个终端敲命令。6.3 端到端验收的关键技巧验证不要只在本机 curl。我会在另一台与边缘节点同网段的机器上分别测 VIP、NodePort、CloudCore 10002 三条连通性再回到边缘节点上直接 ping VIP。这种交叉验证能暴露 MetalLB 的 ARP 通告边界也能看出防火墙规则到底挡没挡 10002。另一个技巧多副本场景下在 Pod 里抓包看源 IP。KubeEdge 边缘 Pod 的流量路径和普通 K8s 集群略有差异必要时在 nginx Pod 里 tcpdump确认 SYN 包到达的是 VIP 还是 NodePort 地址这决定了负载均衡是否真的生效。从那以后我每次部署完都强制走一遍这套验证流程版本号这种最基础的参数先用kubectl version和keadm version对齐再往链路里探。希望帮到你。本文还有配套的精品资源点击获取