Centos7.9 + K8s v1.22.17 + Kubeedge v1.13.1 边缘计算部署包实战
简介本资源面向刚接触边缘计算与容器编排的运维及开发人员提供一套基于 Centos7.9、K8s v1.22.17kubeadm 部署与 Kubeedge v1.13.1 的完整部署实践包重点解决边缘节点接入与负载均衡器 LoadBalancer 配置问题。压缩包共 15 个文件包含 7 个 yaml 清单如 metallb-native、nginx-loadbalancer、calico 等、6 个 tar 镜像含 kubeedge、metallb、metrics-server、nginx 等、1 个 md 部署文档及 1 个 keadm 安装包整体约 474.64MB覆盖集群网络、负载均衡与边缘组件镜像。已有 242 人学习下载。读者可借助文档与清单完成从 K8s 集群准备、Kubeedge 安装到 MetalLB 负载均衡器部署与实例验证的全流程快速理解边缘节点纳管与外部访问暴露的配置思路适合作为边缘计算入门与实验环境搭建的参考。1. 从一台裸机到边缘节点这套 Centos7.9 K8s v1.22.17 Kubeedge v1.13.1 部署包到底解决了什么如果你手里正好有一批 Centos7.9 的机器想搭一套能跑边缘计算的 K8s 集群又不想在版本兼容性上反复试错这套部署包值得先拆开看看。它把 K8s v1.22.17kubeadm 方式、Kubeedge v1.13.1 和 MetalLB 负载均衡器串成了一条完整的落地链路附带镜像 tar 包、yaml 清单和一份部署文档。最直接的价值在于Kubeedge 对 K8s 版本有硬性区间要求v1.22.0 到 v1.24.0而 Centos7.9 的内核和容器运行时配置又有自己的脾气这套组合相当于把版本匹配和基础环境适配这两件最耗时间的事提前做完了。适合谁手里有 Centos7.9 物理机或虚拟机、需要快速验证边缘节点纳管流程的运维和平台工程师以及想搞明白 LoadBalancer 在裸金属环境下怎么落地的 K8s 使用者。它不是给生产环境直接抄的万能模板但作为实验环境和部署逻辑参考省下的排查时间很实在。2. 版本锁定与镜像预载为什么这套组合能绕开依赖地狱2.1 K8s v1.22.17 与 Kubeedge v1.13.1 的版本咬合逻辑Kubeedge 的版本兼容性表里v1.13.x 明确支持 K8s v1.22 到 v1.24。选 v1.22.17 而不是更新的 v1.23 或 v1.24核心原因在于 Centos7.9 默认内核 3.10 对较新 K8s 特性的支持边界。v1.22 是最后一个默认使用 Docker 作为容器运行时且 kubeadm 配置相对稳定的版本再往上走containerd 的配置复杂度和 cgroup 驱动问题会明显增加。这套包里的 kubeedge.tar、coreedge.tar 和 keadm-v1.13.1-linux-amd64.tar.gz 就是为这个版本组合准备的省去了从外网拉取镜像的步骤。镜像清单里还有几个关键角色metrics-server.tar 负责资源指标采集nginx.tar 和 nginx.yaml 用于后续的负载均衡测试calico.yaml 提供 Pod 网络方案metallb_image.tar 和 metallb-native.yaml 则是 LoadBalancer 能力的来源。把这些镜像提前打成 tar 包意味着在无外网或外网受限的环境里部署流程不会卡在 image pull 失败上。2.2 镜像预载与容器运行时配置Centos7.9 上跑 K8s v1.22.17容器运行时通常还是 Docker。先把镜像 tar 包导入本地再初始化集群顺序不能反。常见做法是写一个批量导入脚本避免手动 docker load 一个个敲。# 批量导入镜像 tar 包注意文件路径按实际存放位置调整 for img in metrics-server.tar image.tar nginx.tar coreedge.tar kubeedge.tar metallb_image.tar; do echo Loading $img ... docker load -i /root/images/$img done # 确认关键镜像已就位 docker images | grep -E kubeedge|metallb|metrics-server|nginx|calico逻辑说明docker load 会把 tar 包里的镜像层解压到本地镜像库-i 指定输入文件。导入完成后用 docker images 过滤确认重点看 kubeedge 和 metallb 相关镜像的 tag 是否与 yaml 里引用的版本一致。如果 tag 对不上kubeadm init 或 apply yaml 时会报 ImagePullBackOff这时候要么改 yaml 里的 image 字段要么重新打 tag。参数上需要注意Centos7.9 的 Docker 默认存储驱动是 overlay2如果之前装过其他版本 Docker 且存储驱动是 devicemapper导入大镜像时可能遇到空间不足。提前用 docker info 看一眼 Storage Driver 和 Docker Root Dir确保根分区或数据分区有足够空间。另外kubelet 的 cgroup 驱动要和 Docker 保持一致v1.22 默认是 cgroupfs如果系统启用了 systemd cgroup需要在 kubelet 配置里显式指定否则节点 NotReady 是常见翻车点。2.3 kubeadm 初始化时的网络与负载均衡前置条件这套包使用 MetalLB 作为 LoadBalancer 实现意味着 K8s 集群本身不依赖云厂商的 LB 能力。但 kubeadm init 之前有几件事必须确认节点 IP 规划、Pod CIDR 和 Service CIDR 不能与宿主机网段冲突、防火墙规则放行必要端口。MetalLB 的 L2 模式需要一段可用的 IP 地址池first-ipaddresspool.yaml 和 l2-forward.yaml 就是干这个的。# kubeadm 初始化示例注意 pod-network-cidr 与 calico 配置匹配 kubeadm init \ --kubernetes-versionv1.22.17 \ --pod-network-cidr10.244.0.0/16 \ --service-cidr10.96.0.0/12 \ --apiserver-advertise-addressmaster-ip \ --image-repositoryregistry.aliyuncs.com/google_containers # 初始化完成后配置 kubectl mkdir -p $HOME/.kube cp -i /etc/kubernetes/admin.conf $HOME/.kube/config chown $(id -u):$(id -g) $HOME/.kube/config # 安装 calico 网络插件 kubectl apply -f calico.yaml逻辑说明--kubernetes-version 锁定 v1.22.17--pod-network-cidr 必须和 calico.yaml 里的 CALICO_IPV4POOL_CIDR 一致否则 Pod 之间跨节点通信会出问题。--image-repository 指向国内可访问的镜像仓库如果本地已经导入了所有镜像这一步也可以省略kubeadm 会优先使用本地镜像。calico.yaml 应用后用 kubectl get pods -n kube-system 观察 calico 相关 Pod 是否 Running再继续后续步骤。这里有个容易忽略的点MetalLB 的 IP 地址池必须和集群节点在同一二层网络L2 模式依赖 ARP 广播。如果地址池选了一个路由不可达的网段Service 的 EXTERNAL-IP 会一直 pending。first-ipaddresspool.yaml 里定义的地址范围建议从节点同网段里挑一段未被占用的 IP。3. MetalLB 落地与 Kubeedge 纳管从 LoadBalancer 到边缘节点上线3.1 MetalLB 的 L2 模式配置与地址池绑定MetalLB 在裸金属 K8s 里提供 LoadBalancer 类型的 Service 支持两种模式L2 和 BGP。这套包用的是 L2 模式配置简单不需要路由器配合。metallb-native.yaml 负责部署 controller 和 speakerfirst-ipaddresspool.yaml 定义地址池l2-forward.yaml 开启 L2 广播。# 部署 MetalLB 核心组件 kubectl apply -f metallb-native.yaml # 等待 metallb-system 命名空间下的 Pod 就绪 kubectl get pods -n metallb-system -w # 应用 IP 地址池和 L2 广播配置 kubectl apply -f first-ipaddresspool.yaml kubectl apply -f l2-forward.yaml逻辑说明metallb-native.yaml 里包含 controller Deployment 和 speaker DaemonSetspeaker 以 hostNetwork 模式运行负责响应 ARP 请求。first-ipaddresspool.yaml 里的 addresses 字段填写可用 IP 范围比如 192.168.1.240-192.168.1.250。l2-forward.yaml 里的 L2Advertisement 资源将地址池与节点绑定不写 nodeSelectors 则所有节点都可参与宣告。参数上addresses 范围不要跨网段否则 speaker 无法正确响应 ARP。如果集群有多个网卡speaker 默认在所有接口上监听可能造成 ARP 冲突可以在 speaker 配置里通过 --node-labels 或接口过滤来限制。验证方法是创建一个 LoadBalancer 类型的 Service看 EXTERNAL-IP 是否从地址池里分配出来。3.2 nginx-loadbalancer.yaml 测试 Service 的对外暴露镜像包里的 nginx.yaml 和 nginx-loadbalancer.yaml 是一对测试用例。前者部署一个 nginx Deployment后者创建一个 LoadBalancer 类型的 Service 指向它。这一步是验证 MetalLB 是否生效的最短路径。# nginx-loadbalancer.yaml 关键字段 apiVersion: v1 kind: Service metadata: name: nginx-lb spec: type: LoadBalancer selector: app: nginx ports: - protocol: TCP port: 80 targetPort: 80逻辑说明type 设为 LoadBalancer 后MetalLB 的 controller 会从地址池分配一个 EXTERNAL-IPspeaker 负责将该 IP 的流量引导到对应节点。selector 必须匹配 nginx Deployment 的 Pod 标签否则 Endpoints 为空Service 虽然分配了 IP 但访问不通。应用后执行 kubectl get svc nginx-lb观察 EXTERNAL-IP 列。如果显示 pending检查 metallb-system 下 speaker 的日志常见原因是地址池耗尽或 L2Advertisement 未正确关联。拿到 EXTERNAL-IP 后在集群外任意同网段机器上 curl 这个 IP返回 nginx 欢迎页即表示 LoadBalancer 链路通了。3.3 Kubeedge v1.13.1 的 keadm 初始化与边缘节点加入Kubeedge 的部署分云端和边缘端。云端用 keadm init 在 K8s master 上安装 cloudcore边缘端用 keadm join 将节点纳管。keadm-v1.13.1-linux-amd64.tar.gz 里就是 keadm 二进制文件。# 解压 keadm 并放到 PATH tar -zxvf keadm-v1.13.1-linux-amd64.tar.gz cp keadm-v1.13.1-linux-amd64/keadm/keadm /usr/local/bin/ # 云端初始化--kubeedge-version 指定版本--advertise-address 为 master IP keadm init --advertise-addressmaster-ip --kubeedge-version1.13.1 # 获取边缘节点加入所需的 token keadm gettoken # 在边缘节点上执行 join--cloudcore-ipport 指向 master 的 10000 端口 keadm join --cloudcore-ipportmaster-ip:10000 --tokentoken --kubeedge-version1.13.1逻辑说明keadm init 会在 kube-system 命名空间下部署 cloudcore Deployment并创建 CRD。--advertise-address 是边缘节点访问云端服务的地址必须是边缘节点能路由到的 IP。keadm gettoken 返回的 token 用于边缘节点认证默认有效期有限过期后需要重新获取。边缘节点执行 join 之前需要确保 10000 端口cloudcore 的 websocket 端口和 10002 端口https 服务在 master 上放行。join 成功后在 master 上执行 kubectl get nodes会看到边缘节点以 edge 角色注册进来。如果节点状态一直是 NotReady检查边缘节点上的 edgecore 日志常见问题是容器运行时未就绪或 CNI 插件未安装。3.4 边缘节点纳管后的验证与 metrics-server 集成节点加入后metrics-server.tar 导入的镜像开始发挥作用。Kubeedge 场景下metrics-server 需要能采集边缘节点的资源指标但边缘节点通常网络受限默认的 metrics-server 配置可能无法直接工作。# 部署 metrics-server kubectl apply -f components.yaml # 查看 metrics-server Pod 状态 kubectl get pods -n kube-system | grep metrics-server # 验证指标采集 kubectl top nodes kubectl top pods -A逻辑说明components.yaml 里定义了 metrics-server 的 Deployment、Service 和 RBAC。关键参数是 --kubelet-insecure-tls因为 kubelet 的证书通常是自签的不加这个参数 metrics-server 会报证书验证失败。--kubelet-preferred-address-types 建议设为 InternalIP避免 metrics-server 尝试用主机名连接 kubelet 导致超时。如果 kubectl top nodes 返回 error: Metrics API not available先确认 metrics-server Pod 是否 Running再看日志里是否有 kubelet 连接错误。边缘节点上 kubelet 的 10250 端口需要放行且 metrics-server 所在节点能路由到边缘节点 IP。这套包把 metrics-server 镜像单独打包说明作者已经预判了外网拉取困难的问题导入后直接 apply 即可。4. 避坑与排查Centos7.9 上跑这套组合最容易翻车的五个点4.1 现象kubeadm init 卡在 waiting for the kubelet to boot up原因Centos7.9 默认启用 SELinux 和 firewalldkubelet 启动时被拦截或者 Docker 的 cgroup 驱动与 kubelet 不一致。另外如果之前装过 K8s 且未彻底清理/etc/kubernetes 下的残留配置也会导致初始化失败。解决先执行 setenforce 0 并修改 /etc/selinux/config 将 SELINUX 设为 disabled然后 systemctl stop firewalld systemctl disable firewalld。用 kubeadm reset -f 清理残留删除 /etc/kubernetes 和 /var/lib/etcd 目录。确认 docker info 里 Cgroup Driver 为 cgroupfs与 kubelet 默认一致。如果系统启用了 systemd cgroup需要在 kubeadm 配置里显式指定。4.2 现象calico Pod 一直 CrashLoopBackOff日志报 BIRD 无法启动原因calico.yaml 里的 CALICO_IPV4POOL_CIDR 与 kubeadm init 时的 --pod-network-cidr 不一致或者节点上存在多个默认路由导致 BIRD 选错网卡。解决检查 calico.yaml 中 CALICO_IPV4POOL_CIDR 的值确保与 kubeadm init 参数完全一致。如果节点有多网卡在 calico.yaml 的 env 里添加 IP_AUTODETECTION_METHODinterfaceeth0替换为实际网卡名强制 calico 使用指定网卡。修改后重新 apply观察 calico-node Pod 日志。4.3 现象MetalLB 分配了 EXTERNAL-IP 但外部无法访问原因L2 模式下 speaker 通过 ARP 宣告 IP如果地址池 IP 与节点不在同一二层网络或者交换机做了 ARP 抑制外部请求无法到达。另外如果 Service 的 externalTrafficPolicy 设为 Local只有运行 Pod 的节点才响应 ARP其他节点不转发。解决确认地址池 IP 与节点 IP 在同一网段且交换机未开启 ARP 代理或抑制。将 Service 的 externalTrafficPolicy 改为 Cluster让所有节点都能响应。用 arping 或 tcpdump 在节点上抓包确认 speaker 是否发出了 ARP 响应。如果还是不通检查 speaker 日志里是否有 no available IPs 或 ARP request ignored 的记录。4.4 现象Kubeedge 边缘节点 join 成功但状态为 NotReady原因边缘节点上的 edgecore 需要容器运行时和 CNI 插件才能运行 Pod。如果边缘节点没有安装 Docker 或 containerd或者没有部署 CNIedgecore 虽然能注册但无法创建 Pod 沙箱。解决在边缘节点上安装与云端一致的容器运行时并部署 CNI 插件。Kubeedge 场景下常用 calico 或 flannel 的轻量配置。确认 edgecore 的配置文件 /etc/kubeedge/config/edgecore.yaml 里 containerRuntime 和 cni 相关字段正确。重启 edgecore 服务后用 kubectl get nodes 观察状态变化。4.5 现象metrics-server 报 x509 certificate error 或 connection refused原因metrics-server 连接 kubelet 时kubelet 使用自签证书metrics-server 默认验证证书链导致失败。或者 kubelet 的 read-only port 未开放metrics-server 无法获取指标。解决在 components.yaml 的 metrics-server 启动参数里添加 --kubelet-insecure-tls跳过证书验证。确认 kubelet 的 --read-only-port 不为 0默认 10255。如果边缘节点网络隔离确保 metrics-server 所在节点能路由到边缘节点的 10250 端口。修改后删除 metrics-server Pod 让其重建再执行 kubectl top nodes 验证。5. 从实验到半生产把这套包用稳的三个进阶习惯这套部署包的价值在于把版本匹配和镜像预载做完了但真正要把它用稳还得在几个细节上形成固定动作。第一个习惯是每次 kubeadm init 之前先跑一遍环境预检脚本把 SELinux、firewalld、swap、内核参数、Docker cgroup 驱动这些检查项过一遍。我一般会写一个 check.sh把 ip_forward、bridge-nf-call-iptables、vm.swappiness 这些值打印出来确认无误再执行初始化。这个动作花不了两分钟但能省掉后面半小时的排查。第二个习惯是给 MetalLB 的地址池留足余量并且做好记录。first-ipaddresspool.yaml 里定义的 IP 范围建议单独用一个表格维护标注哪些 IP 已经被 Service 占用、哪些是预留的。L2 模式下如果地址池耗尽新的 LoadBalancer Service 会一直 pending而 kubectl get svc 不会告诉你原因只能去 speaker 日志里翻。提前记录能避免这种黑匣子式的排查。第三个习惯是边缘节点 join 之后不要只看 kubectl get nodes 的 Ready 状态就完事。用 kubectl describe node 看一眼 Conditions 里的 NetworkUnavailable 和 MemoryPressure再用 kubectl get pods -n kube-system -o wide 确认边缘节点上的 daemonset Pod 是否都正常调度。Kubeedge 的边缘节点有时候会显示 Ready但实际 CNI 没配好Pod 调度上去也跑不起来。从那以后我每次加完边缘节点都强制走一遍「describe node 边缘节点上 crictl ps」的检查确认容器运行时和 CNI 都正常才继续下一步。希望帮到你。本文还有配套的精品资源点击获取