简介:本资源面向刚接触边缘计算与容器编排的运维及开发人员,提供一套基于 Centos7.9、K8s v1.22.17(kubeadm 部署)与 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.17(kubeadm 方式)、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-version=v1.22.17 \ --pod-network-cidr=10.244.0.0/16 \ --service-cidr=10.96.0.0/12 \ --apiserver-advertise-address=<master-ip> \ --image-repository=registry.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 和 speaker,first-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 DaemonSet,speaker 以 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-IP,speaker 负责将该 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-address=<master-ip> --kubeedge-version=1.13.1 # 获取边缘节点加入所需的 token keadm gettoken # 在边缘节点上执行 join,--cloudcore-ipport 指向 master 的 10000 端口 keadm join --cloudcore-ipport=<master-ip>:10000 --token=<token> --kubeedge-version=1.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 和 firewalld,kubelet 启动时被拦截,或者 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_METHOD=interface=eth0(替换为实际网卡名),强制 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,或者没有部署 CNI,edgecore 虽然能注册,但无法创建 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 都正常才继续下一步。希望帮到你。
本文还有配套的精品资源,点击获取