09 | 容器编排实战用 K3s 在华为云 FlexusX 搭建多节点 Kubernetes 集群系列目录《基于华为云 FlexusX 四节点集群的云计算全栈实操》PaaS 篇本篇对应课程模块容器 / 容器编排 / 云原生引子前面八篇我们把计算、网络、存储、数据库、对象存储、负载均衡、监控告警都过了一遍应用的形态始终是「在云主机上跑进程」。但当你手里有三台 FlexusX、要同时跑十几个服务、还要保证挂一台不影响业务时人肉ssh上去起进程的方式就彻底崩了。这一篇我们进入云原生的核心——Kubernetes。我不打算用 kubeadm 在裸机上折腾一整天的证书和 etcd而是用K3s这个轻量发行版在 1 控制平面 2 工作节点上十几分钟拉起一个生产可用的 K8s 集群并逐一带你验证它的四大核心能力负载均衡、自愈、弹性伸缩、滚动更新。所有输出均来自真实集群的实测结果文件命令和 YAML 可原样复现。背景与理论为什么是 K3s而不是 kubeadm《深入浅出云计算》里把云计算的演进概括为「物理机 → 虚拟化 → 容器 → 编排」。容器解决了「环境一致」的问题但谁来决定容器跑在哪台机器、挂了谁来重启、流量怎么分发答案就是编排系统而 Kubernetes 已经是事实标准。但在真正动手前先回答一个关键选型问题完整 K8skubeadmvs K3s。维度kubeadm标准 K8sK3s轻量发行版二进制体积数百 MB组件分散单二进制 ~100MB内置 containerd/flannel最低内存控制平面建议 ≥2GiB512MiB 即可跑官方称可跑在树莓派安装复杂度需手动处理证书、etcd、CNI一条脚本装好默认就带可用网络适合场景大规模、需深度定制的生产集群边缘、中小集群、学习、CI与我们 FlexusX 的契合度偏重8vCPU/16G 能跑但冗余正合适资源留给业务而不是控制面K3s 不是「玩具版 K8s」——它是 CNCF 认证的合规发行版把 kube-apiserver、scheduler、controller-manager 全打包进一个进程默认用 containerd 作运行时、Flannel 作网络插件。对我们这种 3~5 节点的中小集群K3s 是性价比最高的解法。等规模上去了换 kubeadm 或托管版 CCE 也只是工作负载平移的事。架构我们要搭的集群拓扑如下ASCII 表达┌──────────────────────────────────────┐ 公网访问 (EIP) │ K3s Kubernetes Cluster │ 113.47.6.41 ───────▶ │ │ │ ┌──────────────────────────────┐ │ │ │ node1 (control-plane) │ │ │ │ 192.168.0.252 8vCPU/16GiB │ │ │ │ apiserver/scheduler/ctrler │ │ │ │ 3 whoami Pod均衡调度 │ │ │ └──────────────────────────────┘ │ │ ┌──────────────────────────────┐ │ │ │ node3 (worker) │ │ │ │ 192.168.0.241 8vCPU/16GiB │ │ │ │ 3 whoami Pod │ │ │ └──────────────────────────────┘ │ │ ┌──────────────────────────────┐ │ │ │ node4 (worker) │ │ │ │ 192.168.0.150 8vCPU/16GiB │ │ │ │ 3 whoami Pod │ │ │ └──────────────────────────────┘ │ │ kube-proxy(iptables) 负责 │ │ Service - Pod 流量转发 │ └──────────────────────────────────────┘ 外部请求 ──▶ NodePort 30080 ──▶ kube-proxy ──▶ 轮询到 3 个 Pod几类核心对象的关系先建立心智模型Deployment声明「我要 3 个 whoami 副本」是面向开发者的主要接口。ReplicaSetDeployment 真正管副本数的下层对象负责「始终保持 3 个 Pod 在跑」。Pod最小调度单位这里是 whoami 容器实例。ServiceNodePort给一组 Pod 一个稳定访问入口并通过 kube-proxy 做负载均衡。kube-scheduler决定新 Pod 落到哪台节点配合topologySpreadConstraints实现跨节点均衡。kube-proxy在每节点上写 iptables 规则把 Service 的 ClusterIP/NodePort 流量转发到后端 Pod。环境与准备节点弹性公网IP私有IP规格系统K8s角色node1113.47.6.41192.168.0.2528vCPU/16GiBUbuntu 24.04.4control-planenode31.94.220.182192.168.0.2418vCPU/16GiBUbuntu 24.04.4workernode4124.70.102.139192.168.0.1508vCPU/16GiBUbuntu 24.04.4worker集群版本K3s v1.36.2k3s1运行时containerd 2.3.2。node2 因pam_faillock账户锁定未纳入集群——这反而成为后文镜像交付的一个现实约束见踩坑章节。三节点需放行 6443API、8472Flannel VXLAN、10250kubelet、30000-32767NodePort等端口华为云安全组已放开内网互访。实操步骤1. 安装控制平面node1K3s 官方脚本支持INSTALL_K3S_MIRRORcn走国内镜像源避免拉取安装包超时# node1 上执行安装为 server控制平面curl-sfLhttps://get.k3s.io|\INSTALL_K3S_MIRRORcn\K3S_TOKENSECRET_TOKEN_HERE\sh-s- server\--node-taint node-role.kubernetes.io/control-plane:NoSchedule# 安装完成后查看节点加入令牌worker 要用sudocat/var/lib/rancher/k3s/server/node-token2. 加入工作节点node3 / node4# node3 / node4 上执行作为 agent 加入curl-sfLhttps://get.k3s.io|\INSTALL_K3S_MIRRORcn\K3S_URLhttps://192.168.0.252:6443\K3S_TOKEN上一步拿到的 node-token\sh-s- agent3. 验证集群状态# 在 node1 上sudokubectl get nodes-owide4. 部署 whoami 演示应用用whoami-demo.yaml详见文末引用部署 3 副本并暴露 NodePort 30080sudokubectl apply-fwhoami-demo.yamlsudokubectl get pods-owidewhoami-demo.yaml的关键片段apiVersion:apps/v1kind:Deploymentmetadata:name:whoamispec:replicas:3selector:matchLabels:app:whoamitemplate:metadata:labels:app:whoamispec:containers:-name:whoamiimage:traefik/whoami:v1.10.2ports:-containerPort:80resources:requests:cpu:50mmemory:32Milimits:cpu:200mmemory:128MireadinessProbe:httpGet:path:/port:80initialDelaySeconds:2periodSeconds:5livenessProbe:httpGet:path:/port:80initialDelaySeconds:3periodSeconds:10topologySpreadConstraints:-maxSkew:1topologyKey:kubernetes.io/hostnamewhenUnsatisfiable:ScheduleAnywaylabelSelector:matchLabels:app:whoami---apiVersion:v1kind:Servicemetadata:name:whoami-svcspec:type:NodePortselector:app:whoamiports:-port:80targetPort:80nodePort:30080topologySpreadConstraints是本篇的调度精髓maxSkew: 1表示各节点副本数之差最多为 1topologyKey: kubernetes.io/hostname让调度器以「主机」为域做均衡。配合whenUnsatisfiable: ScheduleAnyway在资源允许时优先打散。真实输出实测以下为集群实测结果results/14_k8s_cluster.txt。集群拓扑NAME STATUS ROLES VERSION INTERNAL-IP ecs-71b9-0001 Ready control-plane v1.36.2k3s1 192.168.0.252 ecs-71b9-0003 Ready none v1.36.2k3s1 192.168.0.241 ecs-71b9-0004 Ready none v1.36.2k3s1 192.168.0.1503 节点全部Ready1 控制平面 2 工作节点版本统一为v1.36.2k3s1。[A] Service 负载均衡Hostname 轮转对 NodePort 30080 连续curl请求被 kube-proxy 分发到不同后端 PodHostname: whoami-75d5ddd766-kwgj8 Hostname: whoami-75d5ddd766-kwgj8 Hostname: whoami-75d5ddd766-xp7pz Hostname: whoami-75d5ddd766-xp7pz Hostname: whoami-75d5ddd766-xp7pz Hostname: whoami-75d5ddd766-xlvtb kube-proxy(iptables) 将请求分发到 3 个后端 Pod注意轮转不是严格 RR而是 iptables 的随机/概率均衡——这与kube-proxy的statistic模式有关但宏观上 3 个 Pod 都被命中。[B] 自愈Self-Healing删除 Pod: whoami-75d5ddd766-kwgj8 pod whoami-75d5ddd766-kwgj8 deleted 7 秒后ReplicaSet 控制器自动拉起新 Pod whoami-75d5ddd766-h6wwb (Running) 副本数始终维持在期望值声明式/自愈删掉一个 PodReplicaSet 控制器在7 秒内重建出whoami-75d5ddd766-h6wwb。这就是声明式系统的本质你描述终态控制器负责把现状拉回终态。[C] 弹性扩容 3 → 6跨节点均衡kubectl scale deploy/whoami --replicas6 副本在各节点分布 2 ecs-71b9-0001 2 ecs-71b9-0003 2 ecs-71b9-0004 topologySpreadConstraints 保证 3 节点各 2 副本反亲和/均衡调度topologySpreadConstraints生效6 个副本被精确均摊到 3 个节点各 2 个。[D] 滚动更新零停机kubectl set env deploy/whoami APP_VERSIONv2 (变更 Pod 模板触发) Waiting ... 0/6 - 2/6 - 4/6 - 5/6 new updated 2 old replicas pending termination - 1 - 0 deployment whoami successfully rolled out 新 ReplicaSet: whoami-5cf6df9944 (6/6 Running) rollout history: REVISION CHANGE-CAUSE 1 none 2 none maxSurge/maxUnavailable 控制的渐进式替换服务不中断可 rollout undo 回滚通过kubectl set env改变 Pod 模板触发更新新旧 ReplicaSet 渐进替换全程零停机。回滚只需kubectl rollout undo deploy/whoami。深度解读四大能力背后的机制[A] 负载均衡不是 K8s 自己实现的「负载均衡器」而是kube-proxy在每台节点写了一套 iptables或 IPVS规则。Service 的 ClusterIP 是一个虚拟 IP请求到达后按规则随机跳到某个 EndpointPod IP。这带来一个工程结论K8s Service 默认是 L4TCP/UDP负载均衡没有会话保持、没有权重要做七层路由得靠 IngressTraefik/NGINX。[B] 自愈是控制器模式的集中体现。K8s 里几乎所有资源都由对应的 Controller 通过informers 控制循环reconcile loop维持终态。Pod 被删 → ReplicaSet 的期望值3与实际值2出现偏差 → 控制循环补一个。这个「偏差检测」周期通常在秒级我们实测 7 秒。[C] 弹性伸缩这里用的是手动scale但底层调度策略才是重点。topologySpreadConstraints是 K8s 1.18 的成熟特性比老的podAntiAffinity更轻、更可控maxSkew给调度器留出「可接受的倾斜度」避免硬反亲和导致 Pending。[D] 滚动更新由 Deployment 的strategy控制默认maxSurge25%、maxUnavailable25%。也就是说 6 副本时最多同时多起 2 个新 Pod、最多杀 2 个旧 Pod始终保持可用副本数 ≥ 期望的 75%。踩坑与排障重点这一节是全文最值钱的部分——K3s 默认镜像源在国内的致命坑。K3s 内置的 containerd 默认走docker.io拉镜像。在大陆网络下连pause这种基础镜像都拉不到表现为Failed to create pod sandbox: ... rpc error: code Unknown desc failed to pull image docker.io/.../pause:...: net/http: request canceled while waiting for connection (Client.Timeout exceeded while awaiting headers) # 或 i/o timeout连whoami-demo.yaml里traefik/whoami:v1.10.2都拉不下来集群等于瘫痪。解决方案在所有节点配置/etc/rancher/k3s/registries.yaml把docker.io和registry.k8s.io指到国内镜像加速完整内容见文末引用mirrors:docker.io:endpoint:-https://docker.m.daocloud.io-https://docker.1ms.run-https://hub.rat.devregistry.k8s.io:endpoint:-https://k8s.m.daocloud.io然后重启 K3s注意要每个节点都配、都重启# 所有节点sudosystemctl restart k3s# 控制平面sudosystemctl restart k3s-agent# 工作节点重启后镜像拉取恢复正常。这个坑我建议在装完 K3s 之后、部署任何应用之前就先配好能省下大把排障时间。生产建议与成本思考控制平面高可用本文是单控制平面有单点风险。生产建议至少 3 个 server 节点 外部数据库etcd 或外部 MySQL/PostgresK3s 支持--cluster-init与--server多活。镜像源生产务必自建 Harbor 或接华为云 SWR把registries.yaml指向私有 Registry避免依赖第三方公共加速的稳定性。资源预留8v16G 的节点控制平面建议单独占用不为业务 Pod 调度用 taint 隔离避免 kubelet/etcd 被业务挤爆。成本3 台 FlexusX 跑 K3s控制面开销极低K3s server 常驻内存约 300~500MiB几乎把算力全让给业务——这对中小团队是实打实的省钱。小结我们用 K3s 在华为云 FlexusX 上十几分钟拉起一个 3 节点 K8s 集群并实测验证了Service 负载均衡——请求轮流转到 3 个 Pod自愈——删 Pod 后 7 秒自动重建弹性伸缩——6 副本精确均摊到 3 节点滚动更新——版本 1→2 渐进替换、零停机。最关键的工程经验是先把registries.yaml配好再部署否则 containerd 拉不到镜像会让整个集群动弹不得。下一篇我们把一个 scikit-learn 模型封装成容器部署到这个集群上做在线推理——云原生与 AI 的交汇点才是 PaaS 真正的用武之地。配置与实测引用集群实测../results/14_k8s_cluster.txt部署清单../k8s/whoami-demo.yaml镜像加速../k8s/registries.yaml
09 | 容器编排实战:用 K3s 在华为云 FlexusX 搭建多节点 Kubernetes 集群
09 | 容器编排实战用 K3s 在华为云 FlexusX 搭建多节点 Kubernetes 集群系列目录《基于华为云 FlexusX 四节点集群的云计算全栈实操》PaaS 篇本篇对应课程模块容器 / 容器编排 / 云原生引子前面八篇我们把计算、网络、存储、数据库、对象存储、负载均衡、监控告警都过了一遍应用的形态始终是「在云主机上跑进程」。但当你手里有三台 FlexusX、要同时跑十几个服务、还要保证挂一台不影响业务时人肉ssh上去起进程的方式就彻底崩了。这一篇我们进入云原生的核心——Kubernetes。我不打算用 kubeadm 在裸机上折腾一整天的证书和 etcd而是用K3s这个轻量发行版在 1 控制平面 2 工作节点上十几分钟拉起一个生产可用的 K8s 集群并逐一带你验证它的四大核心能力负载均衡、自愈、弹性伸缩、滚动更新。所有输出均来自真实集群的实测结果文件命令和 YAML 可原样复现。背景与理论为什么是 K3s而不是 kubeadm《深入浅出云计算》里把云计算的演进概括为「物理机 → 虚拟化 → 容器 → 编排」。容器解决了「环境一致」的问题但谁来决定容器跑在哪台机器、挂了谁来重启、流量怎么分发答案就是编排系统而 Kubernetes 已经是事实标准。但在真正动手前先回答一个关键选型问题完整 K8skubeadmvs K3s。维度kubeadm标准 K8sK3s轻量发行版二进制体积数百 MB组件分散单二进制 ~100MB内置 containerd/flannel最低内存控制平面建议 ≥2GiB512MiB 即可跑官方称可跑在树莓派安装复杂度需手动处理证书、etcd、CNI一条脚本装好默认就带可用网络适合场景大规模、需深度定制的生产集群边缘、中小集群、学习、CI与我们 FlexusX 的契合度偏重8vCPU/16G 能跑但冗余正合适资源留给业务而不是控制面K3s 不是「玩具版 K8s」——它是 CNCF 认证的合规发行版把 kube-apiserver、scheduler、controller-manager 全打包进一个进程默认用 containerd 作运行时、Flannel 作网络插件。对我们这种 3~5 节点的中小集群K3s 是性价比最高的解法。等规模上去了换 kubeadm 或托管版 CCE 也只是工作负载平移的事。架构我们要搭的集群拓扑如下ASCII 表达┌──────────────────────────────────────┐ 公网访问 (EIP) │ K3s Kubernetes Cluster │ 113.47.6.41 ───────▶ │ │ │ ┌──────────────────────────────┐ │ │ │ node1 (control-plane) │ │ │ │ 192.168.0.252 8vCPU/16GiB │ │ │ │ apiserver/scheduler/ctrler │ │ │ │ 3 whoami Pod均衡调度 │ │ │ └──────────────────────────────┘ │ │ ┌──────────────────────────────┐ │ │ │ node3 (worker) │ │ │ │ 192.168.0.241 8vCPU/16GiB │ │ │ │ 3 whoami Pod │ │ │ └──────────────────────────────┘ │ │ ┌──────────────────────────────┐ │ │ │ node4 (worker) │ │ │ │ 192.168.0.150 8vCPU/16GiB │ │ │ │ 3 whoami Pod │ │ │ └──────────────────────────────┘ │ │ kube-proxy(iptables) 负责 │ │ Service - Pod 流量转发 │ └──────────────────────────────────────┘ 外部请求 ──▶ NodePort 30080 ──▶ kube-proxy ──▶ 轮询到 3 个 Pod几类核心对象的关系先建立心智模型Deployment声明「我要 3 个 whoami 副本」是面向开发者的主要接口。ReplicaSetDeployment 真正管副本数的下层对象负责「始终保持 3 个 Pod 在跑」。Pod最小调度单位这里是 whoami 容器实例。ServiceNodePort给一组 Pod 一个稳定访问入口并通过 kube-proxy 做负载均衡。kube-scheduler决定新 Pod 落到哪台节点配合topologySpreadConstraints实现跨节点均衡。kube-proxy在每节点上写 iptables 规则把 Service 的 ClusterIP/NodePort 流量转发到后端 Pod。环境与准备节点弹性公网IP私有IP规格系统K8s角色node1113.47.6.41192.168.0.2528vCPU/16GiBUbuntu 24.04.4control-planenode31.94.220.182192.168.0.2418vCPU/16GiBUbuntu 24.04.4workernode4124.70.102.139192.168.0.1508vCPU/16GiBUbuntu 24.04.4worker集群版本K3s v1.36.2k3s1运行时containerd 2.3.2。node2 因pam_faillock账户锁定未纳入集群——这反而成为后文镜像交付的一个现实约束见踩坑章节。三节点需放行 6443API、8472Flannel VXLAN、10250kubelet、30000-32767NodePort等端口华为云安全组已放开内网互访。实操步骤1. 安装控制平面node1K3s 官方脚本支持INSTALL_K3S_MIRRORcn走国内镜像源避免拉取安装包超时# node1 上执行安装为 server控制平面curl-sfLhttps://get.k3s.io|\INSTALL_K3S_MIRRORcn\K3S_TOKENSECRET_TOKEN_HERE\sh-s- server\--node-taint node-role.kubernetes.io/control-plane:NoSchedule# 安装完成后查看节点加入令牌worker 要用sudocat/var/lib/rancher/k3s/server/node-token2. 加入工作节点node3 / node4# node3 / node4 上执行作为 agent 加入curl-sfLhttps://get.k3s.io|\INSTALL_K3S_MIRRORcn\K3S_URLhttps://192.168.0.252:6443\K3S_TOKEN上一步拿到的 node-token\sh-s- agent3. 验证集群状态# 在 node1 上sudokubectl get nodes-owide4. 部署 whoami 演示应用用whoami-demo.yaml详见文末引用部署 3 副本并暴露 NodePort 30080sudokubectl apply-fwhoami-demo.yamlsudokubectl get pods-owidewhoami-demo.yaml的关键片段apiVersion:apps/v1kind:Deploymentmetadata:name:whoamispec:replicas:3selector:matchLabels:app:whoamitemplate:metadata:labels:app:whoamispec:containers:-name:whoamiimage:traefik/whoami:v1.10.2ports:-containerPort:80resources:requests:cpu:50mmemory:32Milimits:cpu:200mmemory:128MireadinessProbe:httpGet:path:/port:80initialDelaySeconds:2periodSeconds:5livenessProbe:httpGet:path:/port:80initialDelaySeconds:3periodSeconds:10topologySpreadConstraints:-maxSkew:1topologyKey:kubernetes.io/hostnamewhenUnsatisfiable:ScheduleAnywaylabelSelector:matchLabels:app:whoami---apiVersion:v1kind:Servicemetadata:name:whoami-svcspec:type:NodePortselector:app:whoamiports:-port:80targetPort:80nodePort:30080topologySpreadConstraints是本篇的调度精髓maxSkew: 1表示各节点副本数之差最多为 1topologyKey: kubernetes.io/hostname让调度器以「主机」为域做均衡。配合whenUnsatisfiable: ScheduleAnyway在资源允许时优先打散。真实输出实测以下为集群实测结果results/14_k8s_cluster.txt。集群拓扑NAME STATUS ROLES VERSION INTERNAL-IP ecs-71b9-0001 Ready control-plane v1.36.2k3s1 192.168.0.252 ecs-71b9-0003 Ready none v1.36.2k3s1 192.168.0.241 ecs-71b9-0004 Ready none v1.36.2k3s1 192.168.0.1503 节点全部Ready1 控制平面 2 工作节点版本统一为v1.36.2k3s1。[A] Service 负载均衡Hostname 轮转对 NodePort 30080 连续curl请求被 kube-proxy 分发到不同后端 PodHostname: whoami-75d5ddd766-kwgj8 Hostname: whoami-75d5ddd766-kwgj8 Hostname: whoami-75d5ddd766-xp7pz Hostname: whoami-75d5ddd766-xp7pz Hostname: whoami-75d5ddd766-xp7pz Hostname: whoami-75d5ddd766-xlvtb kube-proxy(iptables) 将请求分发到 3 个后端 Pod注意轮转不是严格 RR而是 iptables 的随机/概率均衡——这与kube-proxy的statistic模式有关但宏观上 3 个 Pod 都被命中。[B] 自愈Self-Healing删除 Pod: whoami-75d5ddd766-kwgj8 pod whoami-75d5ddd766-kwgj8 deleted 7 秒后ReplicaSet 控制器自动拉起新 Pod whoami-75d5ddd766-h6wwb (Running) 副本数始终维持在期望值声明式/自愈删掉一个 PodReplicaSet 控制器在7 秒内重建出whoami-75d5ddd766-h6wwb。这就是声明式系统的本质你描述终态控制器负责把现状拉回终态。[C] 弹性扩容 3 → 6跨节点均衡kubectl scale deploy/whoami --replicas6 副本在各节点分布 2 ecs-71b9-0001 2 ecs-71b9-0003 2 ecs-71b9-0004 topologySpreadConstraints 保证 3 节点各 2 副本反亲和/均衡调度topologySpreadConstraints生效6 个副本被精确均摊到 3 个节点各 2 个。[D] 滚动更新零停机kubectl set env deploy/whoami APP_VERSIONv2 (变更 Pod 模板触发) Waiting ... 0/6 - 2/6 - 4/6 - 5/6 new updated 2 old replicas pending termination - 1 - 0 deployment whoami successfully rolled out 新 ReplicaSet: whoami-5cf6df9944 (6/6 Running) rollout history: REVISION CHANGE-CAUSE 1 none 2 none maxSurge/maxUnavailable 控制的渐进式替换服务不中断可 rollout undo 回滚通过kubectl set env改变 Pod 模板触发更新新旧 ReplicaSet 渐进替换全程零停机。回滚只需kubectl rollout undo deploy/whoami。深度解读四大能力背后的机制[A] 负载均衡不是 K8s 自己实现的「负载均衡器」而是kube-proxy在每台节点写了一套 iptables或 IPVS规则。Service 的 ClusterIP 是一个虚拟 IP请求到达后按规则随机跳到某个 EndpointPod IP。这带来一个工程结论K8s Service 默认是 L4TCP/UDP负载均衡没有会话保持、没有权重要做七层路由得靠 IngressTraefik/NGINX。[B] 自愈是控制器模式的集中体现。K8s 里几乎所有资源都由对应的 Controller 通过informers 控制循环reconcile loop维持终态。Pod 被删 → ReplicaSet 的期望值3与实际值2出现偏差 → 控制循环补一个。这个「偏差检测」周期通常在秒级我们实测 7 秒。[C] 弹性伸缩这里用的是手动scale但底层调度策略才是重点。topologySpreadConstraints是 K8s 1.18 的成熟特性比老的podAntiAffinity更轻、更可控maxSkew给调度器留出「可接受的倾斜度」避免硬反亲和导致 Pending。[D] 滚动更新由 Deployment 的strategy控制默认maxSurge25%、maxUnavailable25%。也就是说 6 副本时最多同时多起 2 个新 Pod、最多杀 2 个旧 Pod始终保持可用副本数 ≥ 期望的 75%。踩坑与排障重点这一节是全文最值钱的部分——K3s 默认镜像源在国内的致命坑。K3s 内置的 containerd 默认走docker.io拉镜像。在大陆网络下连pause这种基础镜像都拉不到表现为Failed to create pod sandbox: ... rpc error: code Unknown desc failed to pull image docker.io/.../pause:...: net/http: request canceled while waiting for connection (Client.Timeout exceeded while awaiting headers) # 或 i/o timeout连whoami-demo.yaml里traefik/whoami:v1.10.2都拉不下来集群等于瘫痪。解决方案在所有节点配置/etc/rancher/k3s/registries.yaml把docker.io和registry.k8s.io指到国内镜像加速完整内容见文末引用mirrors:docker.io:endpoint:-https://docker.m.daocloud.io-https://docker.1ms.run-https://hub.rat.devregistry.k8s.io:endpoint:-https://k8s.m.daocloud.io然后重启 K3s注意要每个节点都配、都重启# 所有节点sudosystemctl restart k3s# 控制平面sudosystemctl restart k3s-agent# 工作节点重启后镜像拉取恢复正常。这个坑我建议在装完 K3s 之后、部署任何应用之前就先配好能省下大把排障时间。生产建议与成本思考控制平面高可用本文是单控制平面有单点风险。生产建议至少 3 个 server 节点 外部数据库etcd 或外部 MySQL/PostgresK3s 支持--cluster-init与--server多活。镜像源生产务必自建 Harbor 或接华为云 SWR把registries.yaml指向私有 Registry避免依赖第三方公共加速的稳定性。资源预留8v16G 的节点控制平面建议单独占用不为业务 Pod 调度用 taint 隔离避免 kubelet/etcd 被业务挤爆。成本3 台 FlexusX 跑 K3s控制面开销极低K3s server 常驻内存约 300~500MiB几乎把算力全让给业务——这对中小团队是实打实的省钱。小结我们用 K3s 在华为云 FlexusX 上十几分钟拉起一个 3 节点 K8s 集群并实测验证了Service 负载均衡——请求轮流转到 3 个 Pod自愈——删 Pod 后 7 秒自动重建弹性伸缩——6 副本精确均摊到 3 节点滚动更新——版本 1→2 渐进替换、零停机。最关键的工程经验是先把registries.yaml配好再部署否则 containerd 拉不到镜像会让整个集群动弹不得。下一篇我们把一个 scikit-learn 模型封装成容器部署到这个集群上做在线推理——云原生与 AI 的交汇点才是 PaaS 真正的用武之地。配置与实测引用集群实测../results/14_k8s_cluster.txt部署清单../k8s/whoami-demo.yaml镜像加速../k8s/registries.yaml