news 2026/9/28 1:33:58

Kubeedge 1.13.1 部署实践:CentOS 7.9 + K8s 1.22.17 + MetalLB 全流程

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Kubeedge 1.13.1 部署实践:CentOS 7.9 + K8s 1.22.17 + MetalLB 全流程

简介:面向 Kubeedge 初学者的完整部署资源包,聚焦 Centos7.9 系统上基于 kubeadm 搭建的 Kubernetes v1.22.17 集群,安装 Kubeedge v1.13.1 并借助 MetalLB 负载均衡器实现组件对外访问。资源共 15 个文件,压缩包约 474.64MB,核心内容包括 7 个 yaml 配置清单(涉及 calico、metallb-native、nginx-loadbalancer 及 IP 地址池等)、6 个 tar 镜像文件(如 metrics-server、coreedge、kubeedge 等)、1 份 kubeedge 部署 md 文档以及 keadm-v1.13.1-linux-amd64.tar.gz 工具包,各类型文件按部署流程归置,便于对照操作。已有 242 人学习,适合想要快速复现云边协同环境、理解 LoadBalancer 网络模式并完成 Kubeedge 边缘节点接入的运维或开发人员。通过该包可获得从环境准备、集群搭建到负载均衡器配置、测试实例验证的完整落地方案,有效减少手动搜集组件和排错的时间。

1. 从零打通 Kubeedge:CentOS 7.9 + K8s 1.22.17 + Kubeedge 1.13.1 这套教程包能省掉你一周的试错

先交代一下背景,Kubeedge 是 CNCF 里把 Kubernetes 延伸到边缘计算场景的框架,云端跑 CloudCore,边缘节点跑 EdgeCore,两边通过 WebSocket/QUIC 通信。听起来不算复杂,真正动手装的时候才发现坑都在版本匹配和网络暴露上:K8s 版本差一个小版本,keadm init 就报证书错误;CloudCore 的地址写错,边缘节点永远连不上;镜像拉取超时直接把部署卡死在第一步。这套资源就是冲这三个痛点来的——CentOS 7.9 上先用 kubeadm 搭 K8s 1.22.17,再部署 Kubeedge 1.13.1,最后用 MetalLB 做负载均衡器把 CloudCore 的通信端口稳定暴露出来。镜像文件、yaml 配置、keadm 工具包全部打好包,适合已经能独立搭起 K8s 集群、但还没碰过边缘计算或者被 Kubeedge 连接问题卡住的运维和研发。

2. 环境准备与 K8s 集群搭建:版本匹配是第一步,卡版本比卡命令更常见

很多人一上来就急着跑 keadm init,结果 Keblet 都没起来,CloudCore 更是无从谈起。Kubeedge 对 K8s 版本有明确的兼容区间,1.13.1 这个版本配 K8s 1.22.17 是验证过的组合。下面的步骤先把系统基础打好,再搭集群,最后解释为什么这么选版本。

2.1 系统初始化:swap、selinux、内核参数一个都不能少

CentOS 7.9 装完第一件事不是装 docker,而是先把系统参数捋顺。Kubeedge 边缘节点要跑容器,K8s 的 kubelet 对 swap 和 selinux 有硬性要求,这三条命令缺一不可:

# 关闭 swap,kubelet 默认不允许 swap 超过阈值 swapoff -a && sed -i 's/.*swap.*/#&/' /etc/fstab # selinux 设为 permissive,enforcing 状态会导致容器挂载目录被拒 setenforce 0 sed -i 's/^SELINUX=enforcing/SELINUX=permissive/' /etc/selinux/config # 开启 bridge-nf-call-iptables,否则 Pod 间通信会因 iptables 规则不生效而异常 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 EOF sysctl --system

swapoff和sed改 fstab 是配套操作,只执行前者重启后 swap 会回来,kubelet 又会报错。net.ipv4.ip_forward = 1经常会被人漏掉,EdgeCore 里的 EdgeHub 模块转发流量时依赖它,漏掉之后边缘节点与云端通信会间歇性失败,表现成一种很难排查的玄学问题。

2.2 kubeadm 部署 K8s 1.22.17:从初始化到 Node 节点加入

K8s 1.22.17 算是 1.22 系列比较稳的版本,支持 containerd 和 Docker 运行时。这里以 containerd 为例,因为 Kubeedge 的 EdgeCore 默认 runtime 类型就是 containerd,保持统一能少改一个配置:

# 安装 kubeadm、kubelet、kubectl,版本锁在 1.22.17 cat > /etc/yum.repos.d/kubernetes.repo << EOF [kubernetes] name=Kubernetes baseurl=https://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64/ enabled=1 gpgcheck=0 EOF yum install -y kubeadm-1.22.17 kubelet-1.22.17 kubectl-1.22.17 systemctl enable --now kubelet # 初始化 Master 节点,Pod 网段必须和 Calico 保持一致 kubeadm init \ --apiserver-advertise-address=192.168.20.11 \ --pod-network-cidr=10.244.0.0/16 \ --kubernetes-version=v1.22.17 \ --image-repository=registry.cn-hangzhou.aliyuncs.com/google_containers

初始化时指定阿里云镜像仓库是必要操作,默认的k8s.gcr.io在国内环境会直接拉超时。--pod-network-cidr=10.244.0.0/16是 Calico 的默认网段,后面部署网络插件时不用改配置。--apiserver-advertise-address是 Master 的内网 IP,别填公网 IP,否则 kubelet 探测 apiserver 时会走不通。

初始化完成后按输出提示执行export KUBECONFIG=/etc/kubernetes/admin.conf,然后部署 Calico:

# 应用 Calico 网络插件,资源包里已提供 calico.yaml kubectl apply -f calico.yaml # 查看集群状态,等 node 变成 Ready kubectl get nodes

Calico 的 yaml 里默认使用 IPIP 模式,如果你的集群所有节点在同一二层网络,可以改成 BGP 模式,性能更好。这个后面踩坑章节会细说。Node 节点加入的命令很简单,但注意 token 有效期只有 24 小时,如果集群搭完隔天才装 Kubeedge,token 已经失效,需要用kubeadm token create --print-join-command重新生成。

2.3 版本匹配的硬约束:为什么是 1.22.17 而不是更新的版本

选版本这事我吃过亏。Kubeedge 1.13.1 的 CloudCore 对 Kubernetes API 的兼容性是经过官方验证的,直接看兼容性矩阵,它对应的 K8s 版本区间就是 1.22 到 1.23 左右。你如果非要用 K8s 1.28 去配 Kubeedge 1.13.1,keadm 初始化时 CloudCore 拉取资源就会因为 CRD 版本差异直接报错。

还有一个隐性问题值得注意:K8s 1.24 之后彻底移除了 dockershim,如果习惯用 Docker 做运行时,就得装 cri-dockerd 适配层。而 Kubeedge 1.13.1 的 EdgeCore 在设计上对 containerd 的支持更完整,保持 K8s 1.22.17 + containerd 的组合,相当于同时避开两个坑——版本不兼容和运行时适配。

提示:这套资源里的 yaml 文件和镜像都是基于上述版本组合打包的,换版本意味着 yaml 可能失效,离线镜像也可能用不上。

3. 部署 Kubeedge:CloudCore 和 EdgeCore 的初始化与通信机制

Kubeedge 的部署逻辑分三步走:云端装 CloudCore、边缘节点装 EdgeCore、两端建立通信隧道。这套资源用 keadm 命令行工具完成第一和第二步,再把 CloudCore 的通信端口用 LoadBalancer 方式暴露出去,这一步是打通边缘节点和云端的关键。

3.1 keadm init 部署 CloudCore:云端组件装到 Master 节点

CloudCore 承载着 CloudHub、EdgeController、DeviceController 三个核心模块。CloudHub 负责监听边缘节点连接,EdgeController 通过 K8s API 监听资源变化并下发。把这个组件部署到 K8s 集群里,直接用 keadm 命令完成所有编排:

# 解压 keadm 工具包 tar -zxvf keadm-v1.13.1-linux-amd64.tar.gz # 部署 CloudCore,advertise-address 指定为 MetalLB 将要分配的 VIP ./keadm init --advertise-address=192.168.20.100 --kubeedge-version=v1.13.1

--advertise-address这个参数是全文最容易出错的地方。如果你把这理解成 Master 节点的内网 IP,那 CloudCore 的 Service 即使创建成功,边缘节点也会拿着这个 IP 去连 CloudHub,跨网段直接失败。正确做法是先规划好 MetalLB 的 IP 池范围,从这个范围里挑一个 IP 作为 CloudCore 的访问入口。

初始化完成后,CloudCore 会以 Deployment 形式跑在kubeedge命名空间:

# 查看 CloudCore 状态 kubectl get pods -n kubeedge kubectl get svc -n kubeedge

3.2 keadm join 把边缘节点拉进来:token 引导与 EdgeCore 拉起过程

边缘节点上需要先安装好 containerd 和 kubelet,然后对应不同的系统架构选择加入参数。加入流程会先拉取 EdgeCore 镜像,再生成 edgecore.service 服务并由 systemd 拉起运行时,整个过程像这样:

# 获取 CloudCore 的 token(在 Master 上执行) kubectl get secret -n kubeedge token -o jsonpath='{.data.token}' | base64 -d # 边缘节点加入集群(在边缘机上执行) ./keadm join --cloudcore-ipport=192.168.20.100:10000 \ --token=xxxxx \ --kubeedge-version=v1.13.1

--cloudcore-ipport的 IP 必须和 CloudCore 的--advertise-address保持一致,端口用 10000 是 CloudHub 的默认 WebSocket 端口,如果用的是 HTTPS 则对应 10002。EdgeCore 内部的 EdgeHub 模块会通过这个地址与云端建立长连接。加入完成后,回到 Master 上执行kubectl get nodes,如果看到边缘节点状态带node.kubernetes.io/kubeedge标签,说明加入成功。

3.3 CloudCore 服务化:为什么用 LoadBalancer 暴露是正解

默认情况下 CloudCore 的 Service 是 ClusterIP 类型,边缘节点只能通过节点 IP + NodePort 方式访问。但有三个问题:节点 IP 变化会导致连接断开、端口映射容易冲突、跨网段时边缘设备无法感知节点 IP。资源包里把 CloudCore 改造成了 LoadBalancer 类型的 Service,YAML 里大概是这样的核心配置:

apiVersion: v1 kind: Service metadata: name: cloudcore namespace: kubeedge spec: type: LoadBalancer loadBalancerIP: 192.168.20.100 selector: k8s-app: kubeedge kubeedge: cloudcore ports: - name: cloudhub port: 10000 targetPort: 10000 - name: cloudhub-https port: 10002 targetPort: 10002

把type改成LoadBalancer并指定loadBalancerIP,MetalLB 会从配置好的 IP 池里分配这个地址,并借助 Layer2 模式通过 ARP 响应让整个二层网络内的设备都能访问这个 IP。这比用externalIPs字段手动绑定节点 IP 更稳定,后者没有健康检查,IP 对应的节点挂了服务就断了。MetalLB 会持续监控后端 Pod 的健康状态,自动切换流量。

4. MetalLB 负载均衡器:Layer2 模式下的 IP 分配与服务暴露

Kubeedge 场景里引入 MetalLB 不只是为了给 nginx 测试服务分配 IP,更重要的是给 CloudCore 一个稳定的通信入口。这一章把 MetalLB 的部署、IP 池配置和验证流程走一遍。

4.1 为什么选 Layer2 模式:没有 BGP 环境的最省事方案

MetalLB 支持 Layer2 和 BGP 两种模式。Layer2 模式下,MetalLB 的 speaker 组件会在节点上响应 Service IP 的 ARP 请求,把 VIP 的流量引导到某个节点,再由 kube-proxy 转发到后端 Pod。BGP 模式则需要物理路由器配合,需要额外配置 BGP peer,对多数内网测试环境来说成本偏高。

这套资源走的就是 Layer2 模式,两个 yaml 文件——first-ipaddresspool.yaml定义地址池,l2-forward.yaml开启通告。如果你只有一台物理机做测试,Layer2 模式完全够用,它不依赖路由器能力,只要节点互通就能工作。

4.2 metallb-native.yaml 与 IP 地址池配置全过程

MetalLB 的部署方式随版本演进变化很大,metallb-native.yaml表明用的是 v0.13.x 以上的 native 方式,不需要单独的 manifests 目录。安装流程分三步:

# 1. 安装 MetalLB 的全部组件,包括 controller 和 speaker kubectl apply -f metallb-native.yaml # 2. 定义可用 IP 池,网段必须和集群节点在同一二层网络 cat > first-ipaddresspool.yaml << EOF apiVersion: metallb.io/v1beta1 kind: IPAddressPool metadata: name: first-pool namespace: metallb-system spec: addresses: - 192.168.20.100-192.168.20.200 EOF kubectl apply -f first-ipaddresspool.yaml # 3. 开启 Layer2 通告,把 IP 池与通告规则绑定 cat > l2-forward.yaml << EOF apiVersion: metallb.io/v1beta1 kind: L2Advertisement metadata: name: l2-forward namespace: metallb-system spec: ipAddressPools: - first-pool EOF kubectl apply -f l2-forward.yaml

IP 池的范围建议单独规划一段,别跟 DHCP 的分配范围重叠,否则其他设备拿到相同 IP 会导致 ARP 冲突,Service 的访问时通时不通。L2Advertisement里的ipAddressPools数组可以关联多个池,适合按业务划分不同网段的场景。

4.3 验证负载均衡:从 pending 到 EXTERNAL-IP 的完整过程

部署完 MetalLB,创建测试 Service,验证 VIP 分配是否正常工作:

# 创建 nginx 部署和 LoadBalancer Service,yaml 在资源包里 kubectl apply -f nginx.yaml kubectl apply -f nginx-loadbalancer.yaml # 查看服务状态,等待 EXTERNAL-IP 从 pending 变为具体 IP kubectl get svc nginx-lb

第一次执行kubectl get svc时看到EXTERNAL-IP是<pending>是正常的,MetalLB 需要几秒钟完成 IP 分配和通告。如果超过 30 秒还是 pending,执行kubectl logs -n metallb-system -l component=controller看日志,八成是 IP 池没有关联到通告规则。

拿到 VIP 后在集群内任意节点执行curl http://192.168.20.100,能返回 nginx 默认页面,说明负载均衡链路已打通。此时再回头看 CloudCore 的 Service,确认它也拿到了192.168.20.100这个 IP,边缘节点就能通过它建立连接了。

5. 避坑指南:Kubeedge 部署中最常翻车的五个场景

Kubeedge 的部署文档写得不差,但实际操作中翻车的点非常集中。下面五个坑都是我在部署过程中真实踩过的,按「现象 → 原因 → 解决」的格式写清楚,遇到同类问题可以直接照着排查。

5.1 坑一:镜像导入后 Pod 仍然 ImagePullBackOff

现象:用ctr images import kubeedge.tar导入了镜像,但是 Pod 启动时仍然报拉取镜像失败。

原因:containerd 的分区 namespace 机制。kubelet 默认使用k8s.io这个 namespace,用ctr images import不指定 namespace 时导入到的是default,kubelet 根本看不到这些镜像。

解决:导入镜像时显式指定 namespace:

ctr -n k8s.io images import kubeedge.tar ctr -n k8s.io images import coreedge.tar ctr -n k8s.io images import metallb_image.tar

5.2 坑二:边缘节点加入后状态一直是 Ready,Unknown

现象:kubectl get nodes看到边缘节点存在,但状态列显示Ready,Unknown,过几分钟又变回NotReady。

原因:CloudCore 和 EdgeCore 之间的 WebSocket 连接没有建立成功。最常见的是 CloudCore 的 Service 类型没有改成 LoadBalancer,边缘节点拿不到正确端口;或者--advertise-address配置成了 Master 的节点 IP,边缘节点访问的是内网地址,实际不可达。

解决:先确认 CloudCore Service 拿到了 VIP,再检查边缘节点的journalctl -u edgecore日志,搜索failed to connect字段,定位是网络不通还是端口错误。

5.3 坑三:keadm init 报证书相关错误

现象:初始化 CloudCore 时提示证书签名不匹配,或者证书有效期异常。

原因:keadm 会自动为 CloudCore 生成证书,但生成过程依赖 K8s API Server 的版本。K8s 版本和 Kubeedge 版本不在兼容区间时就会出现这类问题。

解决:确认 K8s 版本是 1.22.17,不要用最新的 1.29 之类的版本。如果你是先升级过集群再装 Kubeedge,建议直接重建集群,别在版本错乱的环境里硬磕。

5.4 坑四:MetalLB 分配不到外部 IP

现象:kubectl get svc显示 EXTERNAL-IP 一直是<pending>,MetalLB 的 controller 日志没有异常。

原因:IP 池配置的网段和集群节点不在同一个二层网络,或者 IP 池被其他设备占用。Layer2 模式下 MetalLB 的 speaker 要把 VIP 宣告到局域网,网段不互通就永远分配不了。

解决:把 IP 池里的 IP 改成和 Master 节点同一网段192.168.20.x,确保这个网段的路由是可达的。另外检查节点防火墙有没有屏蔽 7946 端口的 VRRP 协议(Layer2 模式会用到)。

5.5 坑五:CloudCore 重启后边缘节点全部掉线

现象:kubectl rollout restart deployment cloudcore -n kubeedge后,所有边缘节点的 Pod 都报连接失败。

原因:CloudCore 重启导致 WebSocket 连接断开,EdgeCore 的 EdgeHub 模块需要重新发起握手请求,但 token 已经过期。边缘节点持有的 token 和云端重新生成的 token 对不上。

解决:在边缘节点上重新执行 keadm join,使用最新的 token:

# Master 上重新获取 token kubectl get secret -n kubeedge token -o jsonpath='{.data.token}' | base64 -d # 边缘节点重新加入 ./keadm join --cloudcore-ipport=192.168.20.100:10000 --token=<新token> --kubeedge-version=v1.13.1

6. 从部署到验证:用 nginx 服务打通 LoadBalancer 全链路

部署完 Kubeedge 和 MetalLB,最后一步是验证整个链路能不能跑通。资源包里提供了现成的 nginx 和 Service 配置,直接复现一遍能从 CloudCore、MetalLB、边缘节点三个维度确认系统的健康状态。

先部署测试服务:

# 应用 nginx Deployment 和 LoadBalancer Service kubectl apply -f nginx.yaml kubectl apply -f nginx-loadbalancer.yaml # 确认 Pod 已经 Running,且 EXTERNAL-IP 已分配 kubectl get pods -l app=nginx kubectl get svc nginx-lb

验证链路分三层来看,对应不同的组件:

第一层验证 MetalLB 是否正常工作,在任意节点上curl http://192.168.20.100,如果返回 nginx 欢迎页,说明 VIP 分配和二层宣告都正常。如果超时,优先检查l2-forward.yaml是否有语法错误,kubectl describe svc nginx-lb里的 Events 会给出具体报错。

第二层验证 CloudCore 通信端口是否正常暴露,在 Master 上检查:

# 确认 cloudcore Service 的 EXTERNAL-IP 是否已分配到规划 IP kubectl get svc -n kubeedge cloudcore # 如果 VIP 没分配成功,看 MetalLB 的 controller 日志 kubectl logs -n metallb-system -l component=controller --tail=50

如果 CloudCore 的 EXTERNAL-IP 能正常访问,说明 MetalLB 工作正常。边缘节点通过这个 IP 连接 CloudCore 的 10000 端口就是一条干净的链路。

第三层验证边缘节点是否真正纳入集群管理,到边缘节点上执行:

# 检查 EdgeCore 服务的运行状态 systemctl status edgecore # 回到 Master 查看节点状态,"Ready" 和 "agent" 标签都存在 kubectl get nodes -o wide

边缘节点日志里出现connection established字样,就表示 EdgeHub 与 CloudHub 的 WebSocket 连接已稳定建立。这套资源的完整验证流程看似四个步骤,实际上是把 CloudCore、EdgeCore、MetalLB、Calico 四条线串起来做了一次端到端连通性测试。

最后说个个人习惯:我在确认边缘节点加入成功之后,会立刻把 keadm 和所有 tar 包归档到一个固定目录,并记录 CloudCore Service 的 VIP 到本地笔记。因为每次 CloudCore 重启后边缘节点都需要重新 join,如果没有记录 VIP 和 token,后面排查问题时又要重新翻资源包里的文档。希望这套流程能帮你在搭 Kubeedge 的时候少走几个来回,一次跑通。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/28 1:33:22

MATPOWER交流级联故障模型:电网弹性分析与脆弱线路识别实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/28 1:33:22

国网698.45报文解析实战:从字节流到电能数据的完整拆解

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/28 1:33:20

SPWM三种调制方式对比:原理、Simulink实现与工程选型

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/28 1:33:20

STM32与Zigbee智能家居环境监测系统实战:从选型到组网

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/28 1:33:00

IMU标定实战:kalibr_allan、imu_tk与imu_utils三大工具对比指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/28 1:32:38

I2C信号排查四步法:万用表、示波器与逻辑分析仪协同诊断

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华