Kubernetes集群安装部署:生产级K8S集群构建核心原则与实操指南
1. 这不是“装个软件”,而是一场基础设施的系统性重建
你点开这篇标题,心里想的可能是:“K8S集群安装部署?不就是跑几条命令、改几个配置的事?”——我干了十多年运维和平台工程,亲手搭过从3节点测试环境到200+节点金融级生产集群的全部类型,可以很确定地告诉你:kubeadm init 那一行命令,只是整场战役打响前的号角,不是胜利宣言。真正决定成败的,藏在它之前那72小时的准备里,和之后连续3周的调优验证中。
核心关键词“K8S”“集群”“安装部署”,表面看是技术动作,实则指向三个深层需求:第一,可复现性——今天能装出来,下周换台机器、换个人,还能一模一样装出来;第二,可验证性——不是“kubectl get nodes 显示 Ready 就完事”,而是每个组件(etcd、kube-apiserver、CNI、CoreDNS)都必须有明确的健康断言;第三,可演进性——这次装的是v1.28,但半年后要无缝升级到v1.32,架构设计必须预留弹性。这三点,恰恰是90%的“手把手教程”集体失语的地方——它们只教你怎么按图索骥,不告诉你每一步背后的约束条件和失败阈值。
我见过太多团队踩坑:用CentOS 7.9装完集群,发现内核4.19对cgroup v2支持不全,导致Pod调度异常;用默认kubeadm配置上线,结果etcd数据目录落在根分区,某天日志打爆磁盘,整个控制面雪崩;更常见的是网络插件选错——Calico用BGP模式却没配上游路由器,集群内跨节点通信全断,排查三天才发现是物理网络策略没放开。这些都不是“命令写错了”,而是对Kubernetes作为分布式系统的核心约束缺乏敬畏。
所以这篇内容,不会给你一份“复制粘贴就能跑”的脚本。我会带你回到安装前的决策现场:为什么选kubeadm而不是kOps或Rancher?为什么容器运行时必须锁定containerd 1.7.x而非最新版?为什么etcd集群必须奇数节点且跨故障域部署?每一个选择背后,都有真实生产环境用磁盘空间、CPU中断、网络延迟甚至业务停机时间换来的答案。你不需要记住所有参数,但必须理解每个参数存在的理由——这才是“手把手”真正的含义:不是牵着你走,而是让你看清脚下每一块砖的承重能力。
2. 安装前的七十二小时:比执行命令更重要的准备清单
2.1 环境基线:操作系统与内核的硬性门槛
很多人忽略一个残酷事实:Kubernetes不是在操作系统上运行,而是在操作系统提供的抽象层上运行。当你执行kubeadm init时,它实际在调用内核的cgroup、namespace、seccomp等接口。这意味着OS版本不是“能用就行”,而是“必须精确匹配”。以当前主流稳定版Kubernetes v1.28为例,我们实测验证过的最小可行基线如下:
| 组件 | 最低要求 | 推荐配置 | 关键原因 |
|---|---|---|---|
| Linux内核 | 4.18+ | 5.10 LTS 或 6.1 LTS | 4.18是cgroup v2稳定支持起点,但5.10修复了大量netfilter并发bug,6.1对eBPF verifier性能提升37%(实测kube-proxy iptables规则加载速度) |
| SELinux | enforcing模式 | disabled | Kubernetes组件(如kubelet)大量使用文件挂载和进程注入,enforcing模式下需手动编写数百条策略,极易遗漏导致Pod启动失败 |
| swap分区 | 必须关闭 | swapoff -a && sed -i '/ swap / s/^/#/' /etc/fstab | kubelet默认拒绝启动,即使强制启用也会导致OOM Killer误杀关键组件(我们曾因此丢失etcd leader) |
| 时间同步 | NTP/chrony必须启用 | 所有节点指向同一NTP源 | etcd Raft协议要求节点间时钟偏差<500ms,超时将触发leader重选举,造成API服务抖动 |
提示:不要相信“CentOS 7.9自带内核4.19就足够”。我们实测发现,CentOS 7.9默认内核存在一个TCP timestamp处理缺陷(CVE-2023-4585),在高并发Service访问场景下会导致连接重置率上升12%。解决方案是升级内核至4.19.290+,或直接切换到Rocky Linux 8.8(内核4.18.0-477.27.1.el8_8)。
2.2 网络规划:别让IP地址成为集群的阿喀琉斯之踵
Kubernetes网络模型有三张独立IP平面,必须提前规划互不冲突:
- Node IP:物理机/虚拟机真实IP,用于SSH登录和节点管理;
- Pod CIDR:分配给所有Pod的IP段,由kube-controller-manager管理,必须全局唯一且不与任何物理网络重叠;
- Service CIDR:分配给ClusterIP Service的虚拟IP段,仅在集群内部路由。
我们曾在一个客户环境栽跟头:客户坚持用10.96.0.0/12作为Service CIDR(Kubernetes默认值),但其IDC物理网络恰好使用10.96.0.0/16。结果所有Service DNS解析失败,因为CoreDNS的cluster.local域名查询被物理网络设备劫持。最终方案是将Service CIDR改为172.30.0.0/16,并确保所有节点防火墙放行该网段。
Pod CIDR规划更需谨慎。假设你计划部署500个Pod,按每个Node平均运行20个Pod计算,需要至少25个/24子网(每个/24提供254个IP)。但实际要预留30%冗余——因为StatefulSet的Headless Service、DaemonSet的固定Pod、以及未来扩容都需要额外IP。我们推荐的最小安全配置:
- 单集群:
10.244.0.0/16(65536个IP)→ 可支撑约3000个Pod - 多集群联邦:
10.244.0.0/13(524288个IP)→ 避免跨集群Pod IP冲突
注意:
kubeadm init --pod-network-cidr=10.244.0.0/16这个参数一旦设定,无法在集群运行后修改。如果填错,唯一办法是销毁重建。我们有个血泪教训:某次误填为10.244.0.0/24,结果第257个Pod因IP耗尽无法调度,业务方紧急要求扩容时才发现问题。
2.3 存储与证书:那些被忽略的“隐形依赖”
etcd是Kubernetes的“大脑”,它的存储路径和证书直接决定集群生死线:
- 存储路径:绝对禁止使用
/var/lib/etcd(根分区)。我们强制要求挂载独立SSD盘到/data/etcd,并设置--data-dir=/data/etcd。实测数据显示,当etcd数据目录IO延迟>20ms时,API响应P99延迟飙升至8秒以上。 - 证书有效期:kubeadm默认生成1年有效期证书。但在金融行业,合规要求所有TLS证书必须≤6个月。解决方案是在
kubeadm init前生成自定义证书配置:
# kubeadm-config.yaml kind: ClusterConfiguration apiVersion: kubeadm.k8s.io/v1beta3 certificatesDir: /etc/kubernetes/pki etcd: local: dataDir: /data/etcd serverCertSANs: - "192.168.1.10" # Master节点IP - "k8s-master.internal" peerCertSANs: - "192.168.1.10"然后执行kubeadm init --config kubeadm-config.yaml --certificate-key $(openssl rand -hex 32)。这个--certificate-key参数生成的密钥,必须安全保管——它是所有worker节点加入集群的唯一凭证,丢失即意味着集群不可扩展。
2.4 工具链校验:用真实命令验证而非文档承诺
别轻信“已安装docker”这种说法。执行以下三步验证,缺一不可:
容器运行时兼容性:
# 检查containerd是否启用cgroup v2 sudo ctr version | grep -i cgroup # 输出应包含 "cgroup_version: v2" # 验证kubelet能否与containerd通信 sudo crictl ps -a | head -5 # 若报错"failed to connect",说明kubelet未配置正确的runtime-endpointiptables规则链完整性:
# Kubernetes要求iptables存在KUBE-FORWARD链 sudo iptables -L FORWARD | grep KUBE-FORWARD # 若无输出,需在kubeadm init前执行: sudo iptables -P FORWARD ACCEPThostname与/etc/hosts一致性:
# hostname必须是DNS可解析的短名(不含点) hostname -s # 应输出类似 "master01" # /etc/hosts必须包含本机IP映射 grep "$(hostname -s)" /etc/hosts # 正确格式:192.168.1.10 master01
实操心得:我们曾遇到一个诡异问题——所有节点hostname都是
k8s-node-01,但/etc/hosts里写的是192.168.1.11 k8s-node-01.local。结果kubelet启动后反复注册又注销,因为Node对象的spec.providerID字段包含.local后缀,与云厂商元数据服务返回的主机名不匹配。最终用hostnamectl set-hostname k8s-node-01修正才解决。
3. 核心部署流程:从kubeadm init到生产就绪的12个关键步骤
3.1 初始化控制平面:不只是执行init命令
kubeadm init看似简单,但参数组合决定集群基因。以下是我们在200+节点生产环境验证的最小安全配置:
sudo kubeadm init \ --kubernetes-version=v1.28.11 \ --pod-network-cidr=10.244.0.0/16 \ --service-cidr=172.30.0.0/16 \ --cri-socket=unix:///run/containerd/containerd.sock \ --upload-certs \ --control-plane-endpoint="k8s-api.internal:6443" \ --ignore-preflight-errors=NumCPU,Mem \ --node-name=$(hostname -s) \ --certificate-key=$(openssl rand -hex 32)逐参数解析其不可替代性:
--kubernetes-version:必须指定精确小版本。Kubernetes主版本升级需严格遵循v1.27→v1.28→v1.29路径,跳版本将导致API弃用(如v1.27移除batch/v1beta1 CronJob)。--control-plane-endpoint:这是高可用集群的生命线。它指向一个DNS名称(如k8s-api.internal),该名称必须解析到所有Master节点的VIP或负载均衡器。我们用Keepalived实现VIP,但更推荐云厂商的NLB/ALB。--upload-certs:启用证书分发。当新增Master节点时,kubeadm会自动从etcd拉取证书,避免手动拷贝私钥的风险。--ignore-preflight-errors:仅忽略非致命错误。绝不能忽略Swap或CGroup错误,否则集群将不稳定。
执行后,你会得到三段关键输出:
kubeadm join命令:用于worker节点加入;mkdir -p $HOME/.kube && sudo cp ...:配置kubectl访问权限;kubeadm certs check-expiration:证书有效期检查入口。
注意:
kubeadm init成功后,不要立即执行kubectl get nodes。先验证etcd健康状态:# 进入etcd容器(containerd环境) sudo crictl exec -it $(sudo crictl ps -q --label io.kubernetes.container.name=etcd) sh # 在etcd容器内执行 ETCDCTL_API=3 etcdctl --endpoints=https://127.0.0.1:2379 --cacert=/etc/kubernetes/pki/etcd/ca.crt --cert=/etc/kubernetes/pki/etcd/server.crt --key=/etc/kubernetes/pki/etcd/server.key endpoint health # 正常输出:"https://127.0.0.1:2379 is healthy: successfully committed proposal"
3.2 网络插件选型与部署:Calico的BGP模式实战
Kubernetes没有内置网络,CNI插件是集群的“神经系统”。我们放弃Flannel(UDP封装性能损耗15%)和Weave(调试复杂度高),选择Calico v3.27,因其原生BGP支持和精细网络策略。
部署Calico需两个关键操作:
修改Calico manifest适配你的网络:
下载官方manifest后,编辑calico.yaml,定位kind: Installation部分:# 修改BGP ASN(自治系统号),避免与IDC网络冲突 - name: CALICO_ROUTER_ID value: "1.1.1.1" # 改为你的IDC ASN,如65001 # 强制使用host-local IPAM(避免与云厂商IPAM冲突) - name: CALICO_IPV4POOL_IPIP value: "Never" # 禁用IPIP隧道,纯BGP直连 # 设置Node-to-Node Mesh为false(大规模集群必须关闭) - name: CALICO_NETWORKING_BACKEND value: "bird"应用并验证BGP邻居状态:
kubectl apply -f calico.yaml # 等待Calico Pod就绪后,检查BGP连接 kubectl exec -it -n kube-system calico-node-xxxxx -- bash -c " export ETCD_ENDPOINTS=https://127.0.0.1:2379; export ETCD_CA_CERT_FILE=/calico-secrets/etcd-ca; export ETCD_CERT_FILE=/calico-secrets/etcd-cert; export ETCD_KEY_FILE=/calico-secrets/etcd-key; calicoctl node status " # 正常输出应显示所有Node为"Established"状态
实操心得:BGP模式下,Calico会自动在每个Node上创建BGP Speaker。若发现邻居状态为"Idle",90%概率是物理网络ACL未开放TCP 179端口。我们曾因此花费8小时排查——最后发现是IDC交换机默认阻断BGP端口。
3.3 CoreDNS与Metrics Server:让集群真正“活起来”
kubectl get nodes显示Ready,只是控制面存活;kubectl get pods -A看到所有Pod Running,才是集群功能完整。必须部署的两个基础组件:
CoreDNS(已随kubeadm默认部署,但需验证):
# 检查CoreDNS是否正常提供DNS解析 kubectl run dns-test --image=busybox:1.36 --rm -it --restart=Never -- nslookup kubernetes.default # 正常输出应包含"Name: kubernetes.default.svc.cluster.local"和对应IP # 若失败,检查CoreDNS日志中的典型错误: kubectl logs -n kube-system -l k8s-app=kube-dns # 常见错误"plugin/errors: 2 10.96.0.10:53: read udp 10.244.0.1:53123->10.96.0.10:53: i/o timeout" # 表明CoreDNS Pod无法访问Service IP,需检查iptables FORWARD链Metrics Server(Kubernetes资源监控基石):
# 部署Metrics Server(v0.7.2适配K8S v1.28) kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/download/v0.7.2/components.yaml # 验证指标采集 kubectl top nodes # 正常输出应显示各节点CPU/MEM使用率 # 若报错"unable to fetch metrics",检查metrics-server日志: kubectl logs -n kube-system -l k8s-app=metrics-server # 典型错误"unable to fully scrape metrics from source"通常因kubelet未开启--read-only-port=10255注意:Metrics Server的
--kubelet-insecure-tls参数在生产环境必须禁用。正确做法是在kubelet配置中启用client cert认证,并将metrics-server的ServiceAccount绑定到system:kubelet-api-adminClusterRole。
3.4 高可用集群构建:三Master节点的容灾设计
单Master节点是开发玩具,生产环境必须≥3节点。我们采用“堆叠(stacked)etcd”模式(控制面与etcd共存),因其部署简单且资源利用率高。
新增Master节点的完整流程:
- 在新节点执行预检(同初始Master);
- 从任意现有Master节点获取join命令:
# 在Master01上执行 kubeadm token create --print-join-command --ttl=2h # 输出类似:kubeadm join k8s-api.internal:6443 --token abcdef.0123456789abcdef --discovery-token-ca-cert-hash sha256:... - 在新节点执行join命令,并添加
--control-plane参数:sudo kubeadm join k8s-api.internal:6443 \ --token abcdef.0123456789abcdef \ --discovery-token-ca-cert-hash sha256:... \ --control-plane \ --certificate-key $(cat /root/cert-key.txt) # 该文件需从Master01安全传输
关键验证点:
kubectl get nodes应显示3个Master节点,且ROLES列为control-plane,etcd;kubectl get pods -n kube-system | grep etcd应显示3个etcd Pod;- 模拟故障:
sudo systemctl stop kubelet在Master01上,等待30秒后执行kubectl get nodes,其余节点状态应保持Ready,且API服务不间断。
实操心得:etcd集群脑裂是最高危故障。我们强制要求所有Master节点的
--initial-cluster参数必须显式列出全部节点。例如Master01的kubeadm-config.yaml中:etcd: local: initial-cluster: "master01=https://192.168.1.10:2380,master02=https://192.168.1.11:2380,master03=https://192.168.1.12:2380"若遗漏某个节点,新节点加入后可能形成独立etcd集群,导致数据不一致。
4. 生产就绪检查清单:15项必须通过的验收标准
4.1 控制面健康度验证
Kubernetes控制面由多个组件协同工作,单一组件故障即可导致集群瘫痪。我们制定以下硬性检查项:
| 检查项 | 验证命令 | 合格标准 | 失败后果 |
|---|---|---|---|
| API Server可用性 | curl -k https://127.0.0.1:6443/healthz | 返回"ok" | 所有kubectl命令失效 |
| etcd集群健康 | ETCDCTL_API=3 etcdctl --endpoints=https://127.0.0.1:2379 ... endpoint health | 所有endpoint返回"healthy" | 数据持久化中断,Pod状态丢失 |
| Scheduler健康 | `kubectl get componentstatuses | grep scheduler` | STATUS为"Healthy" |
| Controller Manager健康 | `kubectl get componentstatuses | grep controller-manager` | STATUS为"Healthy" |
| CoreDNS解析 | kubectl exec -it dns-test -- nslookup kubernetes.default | 解析出10.96.x.x IP | Service DNS发现失败,跨服务调用中断 |
提示:
componentstatuses已被标记为deprecated,但仍是快速检查控制面组件存活性的最直接方式。生产环境建议用Prometheus监控kube_controller_manager_up等指标。
4.2 网络连通性深度测试
网络是Kubernetes的命脉,必须验证四层连通性:
Pod到Pod(同节点):
kubectl run test-pod1 --image=nginx:1.25 --restart=Never kubectl run test-pod2 --image=busybox:1.36 --restart=Never -- sleep 3600 kubectl exec test-pod2 -- wget -qO- http://$(kubectl get pod test-pod1 -o jsonpath='{.status.podIP}') # 应返回nginx欢迎页HTMLPod到Pod(跨节点):
# 先确认两Pod在不同节点 kubectl get pod -o wide | grep test-pod # 然后执行跨节点访问 kubectl exec test-pod2 -- wget -qO- http://$(kubectl get pod test-pod1 -o jsonpath='{.status.podIP}')Pod到Service(ClusterIP):
kubectl expose pod test-pod1 --port=80 --name=test-svc kubectl exec test-pod2 -- wget -qO- http://test-svcPod到外部网络:
kubectl exec test-pod2 -- ping -c 3 8.8.8.8 kubectl exec test-pod2 -- curl -I https://www.baidu.com
实操心得:若跨节点Pod访问失败,但同节点成功,95%概率是CNI插件BGP邻居未建立。此时执行
kubectl exec -n kube-system calico-node-xxxxx -- calicoctl node status,重点查看"Global Summary"中"Number of BGP peers"是否等于节点总数减一。
4.3 存储与调度策略验证
Stateful应用依赖稳定的存储和调度,必须验证:
PersistentVolume动态供给:
# 创建StorageClass(以local-path为例) kubectl apply -f https://raw.githubusercontent.com/rancher/local-path-provisioner/v0.0.24/deploy/local-path-storage.yaml # 创建PVC并验证PV自动创建 cat <<EOF | kubectl apply -f - apiVersion: v1 kind: PersistentVolumeClaim metadata: name: test-pvc spec: accessModes: - ReadWriteOnce resources: requests: storage: 1Gi storageClassName: local-path EOF kubectl get pv # 应出现Bound状态的PV污点与容忍度调度:
# 给Node01添加污点 kubectl taint nodes $(kubectl get nodes -o jsonpath='{.items[0].metadata.name}') dedicated=GPU:NoSchedule # 创建带容忍度的Pod cat <<EOF | kubectl apply -f - apiVersion: v1 kind: Pod metadata: name: gpu-pod spec: containers: - name: nginx image: nginx:1.25 tolerations: - key: "dedicated" operator: "Equal" value: "GPU" effect: "NoSchedule" EOF kubectl get pod gpu-pod -o wide # 应调度到Node01
4.4 安全基线扫描
生产集群必须满足最低安全要求:
Pod安全策略:
# 检查是否启用PodSecurity准入控制器 kubectl get mutatingwebhookconfiguration | grep security # 应存在名为"psa-mutating-webhook-configuration"的资源 # 创建测试Pod验证默认策略 cat <<EOF | kubectl apply -f - apiVersion: v1 kind: Pod metadata: name: insecure-pod labels: app: insecure spec: containers: - name: nginx image: nginx:1.25 securityContext: privileged: true # 违反baseline策略 EOF # 应被拒绝并返回"admission webhook \"validation.gatekeeper.sh\" denied the request"Secret加密:
# 检查etcd中Secret是否加密存储 kubectl get secrets -n default test-secret -o yaml > /tmp/test-secret.yaml # 查看etcd中原始数据(需进入etcd容器) ETCDCTL_API=3 etcdctl --endpoints=https://127.0.0.1:2379 ... get /registry/secrets/default/test-secret | hexdump -C # 加密后数据应呈现随机字节流,而非明文base64
5. 常见问题与排障技巧实录:来自200+集群的故障库
5.1 “kubectl get nodes”卡住或超时
现象:执行kubectl get nodes长时间无响应,或报错Unable to connect to the server: dial tcp 192.168.1.10:6443: i/o timeout。
排查路径:
检查API Server进程:
sudo systemctl status kubelet # 若显示active (running),继续检查 sudo ss -tlnp | grep :6443 # 应看到kube-apiserver监听验证kubeconfig有效性:
kubectl config view --minify --raw | grep -E "(certificate-authority-data|server)" # 检查server地址是否为节点IP而非localhost # 检查certificate-authority-data是否为空(空则证书损坏)检查防火墙规则:
sudo iptables -L INPUT | grep 6443 # 若无输出,添加规则: sudo iptables -A INPUT -p tcp --dport 6443 -j ACCEPT sudo iptables-save > /etc/sysconfig/iptables
根本原因:在CentOS 7上,firewalld默认阻止6443端口。我们已在初始化脚本中加入firewall-cmd --permanent --add-port=6443/tcp && firewall-cmd --reload。
5.2 Pod始终处于ContainerCreating状态
现象:kubectl describe pod xxx显示Warning FailedCreatePodSandBox,事件中出现failed to "CreatePodSandbox"。
典型原因与解法:
| 原因 | 诊断命令 | 解决方案 |
|---|---|---|
| containerd未运行 | sudo systemctl status containerd | sudo systemctl start containerd && sudo systemctl enable containerd |
| 镜像拉取失败 | sudo crictl pull nginx:1.25 | 检查/etc/containerd/config.toml中registry.mirrors配置,添加国内镜像源 |
| CNI插件未就绪 | ls /opt/cni/bin/ | 确认Calico manifest已正确kubectl apply,且/opt/cni/bin/calico存在 |
| 磁盘空间不足 | df -h /var/lib/containerd | 清理/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/旧快照 |
实操心得:我们曾遇到一个隐蔽问题——
/var/lib/containerd所在分区inode耗尽(df -i显示100%)。原因是containerd未清理临时快照,导致数百万个空目录。解决方案是定期执行sudo ctr -n k8s.io content ls \| wc -l监控内容对象数量,超过5000时触发sudo ctr -n k8s.io content gc。
5.3 etcd集群成员异常
现象:etcdctl member list显示某个Member状态为unstarted或down,且etcdctl endpoint health报告该节点不健康。
恢复步骤:
- 确认故障节点物理状态:SSH登录该节点,检查
systemctl status etcd; - 若etcd进程崩溃,尝试重启:
sudo systemctl restart etcd sudo journalctl -u etcd -n 100 --no-pager # 查看最近日志 - 若重启失败,需移除并重建成员:
# 在健康节点上执行(如master01) ETCDCTL_API=3 etcdctl --endpoints=https://127.0.0.1:2379 ... member remove <faulty-member-id> # 然后在故障节点重新执行kubeadm join --control-plane
关键预防措施:etcd数据目录必须使用SSD,且--quota-backend-bytes=8589934592(8GB)参数必须显式设置。我们曾因未设配额,导致etcd WAL日志无限增长,最终填满磁盘。
5.4 Calico BGP邻居频繁断连
现象:calicoctl node status中BGP状态在Established和Idle间跳变,kubectl get bgppeers显示lastTransitionTime频繁更新。
根因分析:
- 物理网络MTU不匹配:Calico默认MTU为1500,若IDC网络MTU为9000(jumbo frame),BGP Keepalive包被分片丢弃;
- BGP Hold Timer过短:默认hold time 90秒,在高延迟网络中易超时。
解决方案:
# 修改Calico配置,增大Hold Timer kubectl patch bgpconfiguration default --type=merge -p '{"spec":{"bgpHoldTime":"30s"}}' # 调整Node MTU(需重启Calico Pod) kubectl set env daemonset/calico-node -n kube-system FELIX_IPINIPMTU=1440注意:MTU调整必须全集群统一。我们采用自动化脚本,在节点加入时自动探测物理网络MTU并配置Calico。
5.5 Metrics Server无法获取指标
现象:kubectl top nodes报错error: Metrics API not available,或返回No resources found。
深度排查:
检查Metrics Server日志中的TLS错误:
kubectl logs -n kube-system -l k8s-app=metrics-server | grep -i "x509" # 若出现"x509: certificate signed by unknown authority",说明kubelet客户端证书未被Metrics Server信任验证kubelet配置:
# 检查kubelet是否启用--client-ca-file ps aux | grep kubelet | grep client-ca-file # 若无,需在/var/lib/kubelet/config.yaml中添加: # authentication: # x509: # clientCAFile: "/etc/kubernetes/pki/ca.crt"重建Metrics Server证书:
# 删除旧证书 kubectl delete secret -n kube-system metrics-server-certs # 重新部署(会自动生成新证书) kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/download/v0.7.2/components.yaml
6. 后续演进路线:从单集群到多集群治理的必经之路
当你完成第一个生产就绪集群,真正的挑战才开始。我们服务的客户中,90%在6个月内会面临以下演进需求:
6.1 集群生命周期管理:告别手工升级
Kubernetes版本迭代快(每季度大版本),手工升级风险极高。我们采用GitOps驱动的自动化升级:
- 工具链:Argo CD + Kustomize + kubeadm upgrade;
- 流程:
- 在Git仓库中维护
kubeadm-config.yaml,版本号作为参数; - Argo CD监听该文件变更,触发CI流水线;
- 流水线执行
kubeadm upgrade plan验证兼容性; - 分批次升级Master节点(每次1台),再升级Worker节点。
- 在Git仓库中维护
实操心得:升级前必须备份etcd。我们用
etcdctl snapshot save生成快照,并上传至S3。某次v1.27→v1.28升级中,因API变更导致CustomResourceDefinition失效,正是靠3小时前的快照快速回滚。
6.2 多集群统一观测:用Thanos聚合指标
单集群Metrics Server只能看本集群,多集群需全局视图。我们部署Thanos Sidecar:
- 每个集群的Prometheus配置
--storage.tsdb.retention.time=24h(本地短期存储); - Thanos Sidecar将指标推送到中心化对象存储(如Min
