简介:面向Kubeedge新手与边缘计算运维人员,这套部署资源聚焦于在Centos7.9中基于K8s v1.22.17(kubeadm)集成Kubeedge v1.13.1,并引入MetalLB负载均衡器对外暴露服务,解决高可用访问问题。压缩包共15个文件,包含7个YAML配置、6个TAR镜像、1个Markdown部署文档和1个GZ安装包,整体474.64MB;YAML负责编排组件与LoadBalancer策略,TAR/GZ用于离线加载镜像和工具,MD文档则串联整个安装流程。目前已有242人浏览学习,适合希望按部就班复现边缘集群的初学者。内容从系统准备、K8s集群搭建起步,覆盖Kubeedge部署、MetalLB配置、测试实例与验证结果,并附有排错要点,使读者能快速搭建可运行的负载均衡版Kubeedge环境。
1. KubeEdge 部署的拦路虎:不只是装个 EdgeCore
把 KubeEdge 跑起来这件事,90% 的教程会告诉你 keadm init、keadm join 两行命令完事,但你真去复现就会发现:云边通道握手失败、CloudCore 起不来、边缘节点调度不了 Pod、LoadBalancer 拿到 EXTERNAL-IP 但流量进不来。这个资源包的设置是把 CentOS7.9、Kubernetes v1.22.17、KubeEdge v1.13.1 和 MetalLB 负载均衡器串成一条完整链路,所有离线镜像和 YAML 都给你备好,跟着一步步走就能得到一个云边协同 + 负载均衡可用的集群。适合刚接触 KubeEdge 的部署人员,也适合准备在裸机环境里跑边缘计算实验的人。
2. 集群地基:为什么非得是 CentOS7.9 + K8s v1.22.17
2.1 版本匹配的第一道坎:KubeEdge 对 Kubernetes 的版本窗口
KubeEdge v1.13.1 官方支持的 Kubernetes 版本范围是 v1.22.0 到 v1.24.0,这个窗口卡得很死。版本太新,CloudCore 与 API Server 的协议兼容性就会出现问题,比如 informer 缓存不一致、watch 断流;版本太旧,很多 CRD 字段又不存在。kubeadm 部署 v1.22.17 是社区验证比较多的一条主线,在 etcd 3.5、containerd 1.6 的组合下表现稳定,这也是资源里选这个版本的原因。
还有一个容易被忽略的点:KubeEdge 的 keadm 二进制是分架构的,这个压缩包提供的是 linux-amd64 版本,所以控制节点和边缘节点都得是 x86_64 架构,纯 arm64 机器上直接用会报“exec format error”。也不建议在一个集群里混用不同大版本的 KubeEdge,否则 CloudCore 与 EdgeCore 的 websocket 协议握手会失败。
2.2 控制节点初始化:系统参数与镜像源一次配到位
CentOS7.9 装完后先做三件事:关 swap、放行防火墙端口、配内核转发参数。防火墙是 KubeEdge 云边通道最常见的隐性杀手,端口 10000(HTTP)和 10002(HTTPS)没放行的话,边缘节点会在 join 阶段反复超时。
# 关闭 swap 并注释 /etc/fstab 中 swap 行 swapoff -a && sed -i '/ swap / s/^/#/' /etc/fstab # 内核参数:ip_forward 和 bridge-nf 必须打开 cat > /etc/sysctl.d/k8s.conf <<'EOF' net.bridge.bridge-nf-call-iptables = 1 net.bridge.bridge-nf-call-ip6tables = 1 net.ipv4.ip_forward = 1 net.ipv6.conf.all.forwarding = 1 EOF sysctl --system # 放行 Kubernetes 与 KubeEdge 所需端口 firewall-cmd --permanent --add-port=6443/tcp firewall-cmd --permanent --add-port=2379-2380/tcp firewall-cmd --permanent --add-port=10250/tcp firewall-cmd --permanent --add-port=10000/tcp firewall-cmd --permanent --add-port=10002/tcp firewall-cmd --reload这里 net.bridge.bridge-nf-call-iptables 确保经过网桥的流量也能被 iptables 规则处理,Calico 的 overlay 网络全靠它;10000/10002 是 KubeEdge 云边通道的守门员,前者用于 HTTP,后者用于 HTTPS,后面部署 EdgeCore 时缺一不可。镜像源方面,我一般习惯提前把 kubeadm 需要的组件镜像通过 docker pull 拉下来导出,再用 ctr -n k8s.io import 导入 containerd,避免初始化时卡在镜像拉取。
2.3 kubeadm init 的参数选择与 Calico 的落地
初始化命令用--control-plane-endpoint还是--apiserver-advertise-address,在这个场景里有个讲究。资源里的架构使用了负载均衡器,但控制节点本身就是 LoadBalancer 的流量入口,所以这里直接用 apiserver 的 VIP 地址做 advertise,Pod 网段给 10.244.0.0/16 与 Calico 默认网段对齐:
kubeadm init \ --kubernetes-version=v1.22.17 \ --apiserver-advertise-address=192.168.1.100 \ --pod-network-cidr=10.244.0.0/16 \ --service-cidr=10.96.0.0/12 \ --image-repository=registry.cn-hangzhou.aliyuncs.com/google_containers mkdir -p $HOME/.kube cp -i /etc/kubernetes/admin.conf $HOME/.kube/config--image-repository指向国内可访问的镜像仓库,这个参数覆盖的是 kubeadm 默认的 registry.k8s.io 前缀。因为资源包里有离线镜像 tar,所以更稳妥的做法是把镜像先 docker load 再 ctr -n k8s.io import,然后去掉这个参数,避免初始化时网络抖动。Calico 的部署直接 apply 资源包里的 calico.yaml,安装完成确认kubectl get pods -n kube-system里 calico-kube-controllers 和 calico-node 都处于 Running,再继续下一步。
3. 安装 KubeEdge v1.13.1:CloudCore 与 EdgeCore 的分工
3.1 云边架构:ControlPlane 上跑什么,边缘节点上跑什么
KubeEdge 安装不像 K8s 那样一条命令完成,它拆成两块:CloudCore 运行在云端控制节点,负责与 Kubernetes API Server 通信、下发资源变更、维护设备 CRD;EdgeCore 运行在边缘节点,内部又分两个关键进程——EdgeController 做 Pod 生命周期管理,Edgestream 专门处理 Pod 访问日志和 exec。这两个进程分别对应 keadm join 时的--cloudcore-ipport只需要填 CloudCore 的端口,而 Pod 内的 kubectl logs/exec 是走独立 stream 隧道协议的。
资源包里 coreedge.tar 封装了 cloudcore 和 edgecore 所需的镜像。实际操作顺序是:先把 coreedge.tar 导入,再执行 keadm init。我先在控制节点准备好 kubernetes config 后,再执行初始化命令。预先使用docker load -i 镜像文件的方式离线导入:
# 在控制节点导入镜像 docker load -i coreedge.tar docker load -i kubeedge.tar docker load -i metrics-server.tar镜像导入完成后确认镜像名,很多部署翻车在名字上——云端用的 CloudCore 镜像 tag 是 v1.13.1,但 docker load 出来可能带着别的仓库前缀,需要 docker tag 成部署 YAML 里写的名字。资源包自带的 kubeedge 目录里有对应的部署文件,用docker images | grep kubeedge一一核对即可。
3.2 keadm init:证书、advertise 地址与 token
令牌过期这个问题我踩过至少两次,keadm 生成的 token 有时效性,时间一长 EdgeCore 就注册不进来。稳妥的做法是把 token 记录下来,或使用--token参数显式指定。
# 在控制节点初始化 CloudCore ./keadm init \ --advertise-address=192.168.1.100 \ --kube-config=/root/.kube/config \ --kubeedge-version=v1.13.1 # 查看生成的 token(如果忘记) ./keadm gettoken --kube-config=/root/.kube/config--advertise-address必须填边缘节点能访问到的地址,如果有多网卡,这里只填真正通信的那张网卡 IP,填错了边缘节点会连不上 websocket。--kube-config指定 kubeconfig 路径,执行后 CloudCore 会以 Deployment 形式落在 kubeedge-system 命名空间,同时创建证书存放目录/etc/kubeedge/。建议初始化完成后立刻验证 Pod 状态,CloudCore 处于 CrashLoopBackOff 时排查日志,注意查看kubectl logs -n kubeedge-system的报错信息。
3.3 EdgeCore 加入:keadm join 与边缘节点 pre-check
边缘节点不需要安装 Kubernetes,但要预装 docker 和 kubeadm 的部分依赖。EdgeCore 通过 websocket 主动连云端,意味着边缘节点只要能访问到 CloudCore 的 10000/10002 端口就行,不需要云端主动访问边缘节点,这是 KubeEdge 在 NAT 环境下还能工作的原因。加入命令如下:
# 在边缘节点执行 ./keadm join \ --cloudcore-ipport=192.168.1.100:10000 \ --token=你的token \ --kubeedge-version=v1.13.1加入后检查两个层面:edgecore 进程是否存活(ps -ef | grep edgecore),以及云端是否看到节点注册成功。云端执行kubectl get nodes看到边缘节点且状态为 Ready 时,安装才算真正落地。若节点一直 NotReady,多半是边缘节点时钟不同步导致证书校验失败,跑一遍ntpdate校准之后再重置 edgecore。
3.4 镜像清单核对:哪些 tar 用在哪一步
resource 包里六个 tar 不是一次性全部导入的,按阶段分成三组,表格里列清楚避免操作到一半发现镜像缺失:
| 镜像文件 | 用途 | 导入时机 |
|---|---|---|
| metrics-server.tar | 集群资源指标采集 | K8s 集群初始化后 |
| image.tar | 基础组件补充镜像 | CloudCore 部署前 |
| nginx.tar | 测试负载均衡示例的镜像 | 测试 LoadBalancer 前 |
| coreedge.tar | CloudCore / EdgeCore 主镜像 | keadm init 之前 |
| kubeedge.tar | KubeEdge 辅助镜像 | keadm init 之前 |
| metallb_image.tar | MetalLB controller/speaker 镜像 | 部署 MetalLB 之前 |
镜像导入用docker load还是ctr -n k8s.io images import,取决于容器运行时。若容器运行时是 containerd,则 K8s 组件镜像要用ctr导入;若运行 docker,则全部docker load。两种方式不要混用,混用的后果是kubectl describe pod里面出现拉取镜像失败的错误。
4. 部署 MetalLB 负载均衡器:把 LoadBalancer 服务真正跑起来
4.1 为什么裸机集群需要 MetalLB:Service Type=LoadBalancer 的空白地带
在云平台上声明一个 LoadBalancer 类型 Service 会获得云厂商提供的 IP,但裸机环境没有这个能力,Service 会一直处于<pending>状态。MetalLB 是一个纯二层/协议栈解决方案,它通过两种方式提供外部 IP:第二种是 BGP,把分配的 IP 通告给网络设备。本资源包采用的是 L2 模式,spaker 通过 ARP 响应抢占 VIP,流量直接进入节点。
L2 模式的局限要提前知道:所有流量先走选中的节点再转发给 Pod,本身是一个干脆的集群转发,所以单节点的带宽上限就是带宽的上限。适合边缘计算场景的默认选择,节点少、拓扑简单。
4.2 安装 MetalLB 与 IP 地址池规划
先用资源包里的 metallb-native.yaml 创建 CRD 和 controller,然后导入 metallb_image.tar 镜像:
docker load -i metallb_image.tar kubectl apply -f metallb-native.yaml # 等待 controller 和 speaker 就绪 kubectl get pods -n metallb-system -w等 metallb-controller 和 metallb-speaker 都 Running 后,再创建 IP 池和 L2 通告。地址池的规划建议是:从宿主机网络中选一段未被 DHCP 占用的地址,比如 192.168.1.200-192.168.1.220,不要把网关 IP 或您自己的物理 IP 填进去,否则会有 ARP 冲突风险。
4.3 核心配置:IPAddressPool 与 L2Advertisement 的参数细节
# first-ipaddresspool.yaml apiVersion: metallb.io/v1beta1 kind: IPAddressPool metadata: name: first-pool namespace: metallb-system spec: addresses: - 192.168.1.200-192.168.1.220 autoAssign: true# l2-forward.yaml(L2Advertisement 配置) apiVersion: metallb.io/v1beta1 kind: L2Advertisement metadata: name: l2-forward namespace: metallb-system spec: ipAddressPools: - first-pool interfaces: - eth0两个 YAML 配合工作:addresses这一段决定了 LoadBalancer Service 拿到的 IP 范围,autoAssign: true允许自动分配;interfaces这个字段在必须被多次复用的情况下可以留空,不填则所有网卡都参与 ARP 应答。还有一种情形是集群存在多网卡,比如管理网与业务网分离,此时指定interfaces只让业务网卡参与通告。
4.4 Speaker 与 Calico 共存时的流量路径
Calico 使用 BGP 和 iptables 规则管理 Pod 网络,MetalLB 的 speaker 通过 ARP 拿到 VIP 之后,数据包路径是:外部请求 -> 本机 eth0 -> Kubernetes Service iptables 规则 -> Calico veth -> Pod。如果集群同时装了 kube-proxy 的 ipvs 模式,也不会与 MetalLB 冲突,因为 MetalLB 只管 IP 宣告,内核数据转发由 kube-proxy 负责。
验证安装是否成功的命令是kubectl get crd | grep metallb,能看到 ipaddresspools.metallb.io 和 l2advertisements.metallb.io 这两个 CRD 就说明 CRD 层没问题。
5. 常见问题排查:四个反复出现的原因与分析
5.1 问题:kubeadm init 一直卡在拉取镜像
现象:kubeadm init执行两分钟后停在 “Waiting for the kubelet to boot” 或直接输出拉取镜像超时。原因:kubeadm 默认拉取 registry.k8s.io 等官方仓库地址,在部分网络环境下直连成功率很低。解决:改用--image-repository=registry.cn-hangzhou.aliyuncs.com/google_containers;或者先kubeadm config images pull导出后再导入 containerd。这个资源包里的 image.tar 就是干这个用的,导入后再执行 init 就不会卡在镜像环节。
5.2 问题:CloudCore 容器反复重启,日志报 “failed to load certificates”
现象:kubectl logs -n kubeedge-system日志中出现 certificate 相关错误,Pod 状态 CrashLoopBackOff。原因:执行keadm init前没有让 /etc/kubeedge 目录处于可写状态,或之前有多次 init 残留了旧证书。解决:删除旧的 /etc/kubeedge 目录,重新keadm init。在模块化部署时避免频繁重置,资源包里的部署文档描述的就是一个干净的状态。
5.3 问题:EdgeCore 一直提示 “Fail to connect to broker”
现象:边缘节点 run keadm join 后,edgecore 进程活着但不发心跳,云端kubectl get nodes里边缘节点一直是 NotReady。原因:云边通信的 10000/10002 端口被防火墙拦截,或者--cloudcore-ipport里填写的 IP 边缘节点根本 ping 不通。解决:在边缘节点测试telnet 192.168.1.100 10000,不通就回到控制节点的防火墙检查;通的话再检查 token 是否过期,过期则在云端执行keadm gettoken重新赋值。
5.4 问题:MetalLB 分配了 IP,但外部 ping 不通
现象:kubectl get svc显示 EXTERNAL-IP 有值,但从同网段其他主机 ping 该地址不通。原因:地址段内有真实设备占用了相同 IP,或 L2Advertisement 与 IPAddressPool 的命名空间/名字不匹配。解决:先用arping检查 IP 是否被占用,再确认kubectl get l2advertisement -n metallb-system的ipAddressPools名字与first-pool完全一致;最后确认 MetalLB 部署的命名空间是 metallb-system。
6. 端到端验证:从 nginx 到 LoadBalancer EXTERNAL-IP 的完整闭环
资源包里带了 nginx.tar 和 nginx-loadbalancer.yaml,这个组合就是负载均衡功能的最终验证:创建一个 LoadBalancer 类型的 Deployment,让它拿到地址池里的 IP,然后从外部访问服务。我把验证流程固定成了五步,每一轮部署 KubeEdge 之后都用这套操作确认链路没有断裂。
# 第一步:导入 nginx 镜像并启动负载测试应用 docker load -i nginx.tar kubectl apply -f nginx.yaml # 第二步:为 Deployment 创建 LoadBalancer 类型 Service kubectl apply -f nginx-loadbalancer.yaml # 第三步:观察 Service 是否拿到外部 IP kubectl get svc nginx-loadbalancer -w等待输出中 EXTERNAL-IP 列由<pending>变成地址池范围内的 IP,比如 192.168.1.200,说明 MetalLB 的 IPAddressPool 和 L2Advertisement 已正常工作。第四步在集群外的机器访问这个地址,得到 nginx 默认页面即通过。第五步是把 Pod 调度到边缘节点,验证云边协同的真实效果:
# 给边缘节点打标签,再用 nodeSelector 把测试 Pod 拉过去 kubectl label node 边缘节点名 node-role.kubernetes.io/edge=nginx-test kubectl apply -f ./配置文件 # 在 nginx.yaml 里增加 nodeSelector 后 apply算上这一步,整个资源包的价值才算完整发挥出来:LoadBalancer 分配 IP、外部流量进集群、流量进入边缘节点上的 Pod,这条链路把 CloudCore、EdgeCore、MetalLB 三个组件串了起来。验证通过之后,资源包里的 kubeedge部署.md 就很适合作为日常操作手册,我把里面的命令和实际验证结果对照过一遍,里面标注的keadm gettoken、kubectl get nodes检查点都有效,即使以后换用其他版本,这五步验证法也可以迁移过去。
从那以后我每次装完 KubeEdge,都会强制走一遍 LoadBalancer 到边缘节点的完整流量测试,而不是只看节点状态就宣布部署成功——节点 Ready 只是表面工程,像边缘节点上的 Pod 被 DNS 解析到错误 IP 这类小概率问题,只有把请求真正打过去才能暴露出来,希望帮到你。
本文还有配套的精品资源,点击获取