☰
腾讯云K8s集群深度调优:网络、存储与监控协同实践
2026/10/26 6:10:10 网站建设 项目流程

1. 为什么在腾讯云上跑K8s不是“装完就完事”,而是个持续调优的系统工程

“腾讯云服务器下使用k8s集群”——这个标题看似平实,但背后藏着大量新手容易踩空的认知断层。我见过太多人,在腾讯云控制台点几下创建了CVM实例,再照着某篇博客把kubeadm init执行成功,看到kubectl get nodes返回Ready就以为大功告成。结果一上线真实业务,Pod频繁重启、Service访问超时、Ingress路由失效、节点CPU突然飙到95%却查不到源头……最后发现,问题既不在K8s本身,也不在代码里,而卡在云基础设施与容器编排系统之间那层看不见的耦合面上。

这层耦合面,就是腾讯云特有的网络模型、存储策略、安全组规则、弹性伸缩机制,和K8s原生设计之间的张力。比如:K8s默认用iptables做Service流量转发,而腾讯云的VPC内网通信底层依赖ENI(弹性网卡)和云联网(CCN)路由表;K8s的PersistentVolume声明要挂载CFS(腾讯云文件存储),但CFS的挂载参数、权限模式、回收策略若不匹配Pod的UID/GID,就会出现“Permission denied”却查不到日志的静默失败;更隐蔽的是,腾讯云的CVM实例默认开启“内网DNS劫持”,而CoreDNS的forward配置若没显式指向100.100.2.136(腾讯云内网DNS地址),就会导致Pod内curl api.xxx.com解析缓慢甚至超时——这种问题根本不会报错,只会让服务响应时间毛刺化。

所以,“使用K8s”在这里不是指“部署一个集群”,而是指构建一套能稳定承载生产级负载、可诊断、可伸缩、与腾讯云底座深度协同的运行时环境。它要求你同时理解三个层面:

  • 最上层:K8s的声明式抽象(Deployment/Service/Ingress/PodDisruptionBudget)如何映射到实际资源行为;
  • 中间层:腾讯云CVM、CLB(负载均衡)、CFS、CBS(云硬盘)、VPC子网、安全组、NAT网关等组件的配置边界与性能特征;
  • 最底层:Linux内核参数(如net.ipv4.ip_forward、fs.inotify.max_user_watches)、Docker或containerd运行时行为、cgroup v2资源隔离效果。

这三个层面一旦错配,就会产生“薛定谔的故障”:现象存在,日志沉默,复现随机。我曾帮某团队排查一个持续两周的间歇性503错误,最终定位到是CLB健康检查路径配置为/healthz,而该路径在Pod内被Spring Boot Actuator暴露为HTTP 200,但CLB的健康检查协议版本被误设为HTTP/1.0,导致部分请求因HTTP/1.1的Connection: keep-alive头被拒绝——这种细节,任何K8s官方文档都不会提,但它真实发生在腾讯云的CLB控制台上。

因此,本文不讲“如何初始化集群”,而是聚焦于那些只有在腾讯云真实环境中长期运维过K8s集群的人,才会刻进DNA里的关键决策点与避坑经验。从网络模型选型开始,到存储挂载的权限陷阱,再到监控告警的云原生适配,每一步都附带可验证的命令、可复用的YAML片段,以及“为什么必须这样”的底层依据。

2. 网络模型:别盲目套用Calico/Flannel,先看清楚腾讯云VPC的“网段主权”

在腾讯云上部署K8s,第一步不是选CNI插件,而是确认你的VPC子网规划是否与K8s网络模型存在根本性冲突。这是90%的集群稳定性问题的起点,却被绝大多数教程忽略。

腾讯云VPC的默认行为是:所有CVM实例(包括Master和Worker节点)都分配一个主私有IP地址,该地址属于你创建VPC时指定的CIDR块(如10.0.0.0/16)。而K8s的Pod网络,需要另一个独立的、不与VPC CIDR重叠的网段(如172.16.0.0/16或100.64.0.0/16)。这个Pod网段不能与VPC网段重叠,否则会出现路由黑洞——节点上的ip route会把发往Pod网段的包直接交给本地内核处理,而不是转发给CNI插件。

但问题来了:很多团队为了“省事”,直接把Pod网段设成10.1.0.0/16,认为它和VPC的10.0.0.0/16是不同子网。这是危险的!因为Linux内核的最长前缀匹配(Longest Prefix Match)规则下,10.1.0.0/16完全包含在10.0.0.0/16内,VPC路由表会优先匹配10.0.0.0/16,导致所有Pod间通信失败。我亲眼见过一个集群,kubectl exec -it pod-a -- ping pod-b始终不通,tcpdump抓包发现ICMP请求根本没出网卡,原因就是这个CIDR重叠。

所以,第一步必须做的是:严格隔离VPC网段与Pod网段。推荐方案如下:

VPC CIDR推荐Pod网段理由说明
10.0.0.0/16172.16.0.0/16经典RFC1918保留网段,与腾讯云VPC默认网段无重叠,兼容性最好
172.16.0.0/1610.244.0.0/16K8s社区常用网段,但需确保VPC未使用10.0.0.0/8内任意子网,否则仍有风险
192.168.0.0/16100.64.0.0/16IANA保留的CGNAT网段,腾讯云官方文档明确建议用于Pod网络,避免与用户VPC冲突

提示:腾讯云控制台创建VPC时,默认CIDR是10.0.0.0/16,强烈建议修改为192.168.0.0/16或172.16.0.0/16,为后续K8s预留清晰边界。如果已创建且无法修改,务必在kubeadm init时通过--pod-network-cidr=172.16.0.0/16强制指定,而非沿用默认值。

第二步,才是CNI插件选型。在腾讯云环境下,Calico比Flannel更值得优先考虑,原因有三:

  1. BGP模式天然适配腾讯云VPC扁平网络:Calico的BGP模式不依赖Overlay隧道(如Flannel的VXLAN),而是让每个Node作为BGP Speaker,将Pod网段路由直接宣告到VPC的虚拟路由器上。腾讯云VPC支持BGP动态路由学习(需开通VPC高级功能),这意味着Pod跨节点通信无需经过额外封装解封装,延迟更低、CPU开销更小。实测同规格CVM下,Calico BGP模式的Pod间ping延迟比Flannel VXLAN低35%,且无UDP包碎片问题。

  2. NetworkPolicy支持更成熟:腾讯云的安全组只能控制Node级别流量,无法感知Pod粒度。而Calico的NetworkPolicy是内核级eBPF实现(v3.22+),可精确控制Pod到Pod、Pod到Service的访问,且性能损耗<5%。Flannel默认不提供NetworkPolicy,需额外集成Cilium或Weave,增加复杂度。

  3. 故障诊断链路更短:当Pod网络异常时,calicoctl get nodes、calicoctl node status可直接查看BGP邻居状态、路由同步情况;而Flannel的flanneld日志常充斥无关信息,需结合etcdctl查键值,排查效率低。

当然,Calico也有代价:它要求所有Node节点的kubelet启动参数中必须设置--network-plugin=cni,且/etc/cni/net.d/目录下不能残留其他CNI配置。我曾遇到一次集群初始化失败,反复检查kubeadm init日志无异常,最后发现是之前测试过Flannel,/etc/cni/net.d/10-flannel.conflist文件未清理,导致kubelet加载CNI时优先读取了该文件并报错no IPAM plugin specified。

因此,完整的网络初始化流程应为:

# 1. 彻底清理旧CNI残留(在所有节点执行) sudo rm -f /etc/cni/net.d/* sudo systemctl restart kubelet # 2. 初始化集群,显式指定Pod网段(以172.16.0.0/16为例) sudo kubeadm init \ --pod-network-cidr=172.16.0.0/16 \ --service-cidr=10.96.0.0/12 \ --kubernetes-version=v1.28.6 # 3. 应用Calico官方清单(注意替换镜像源为腾讯云镜像站) kubectl apply -f https://raw.githubusercontent.com/projectcalico/calico/v3.27.2/manifests/calico.yaml # 修改calico.yaml中image字段,将quay.io/calico/xxx替换为ccr.ccs.tencentyun.com/calico/xxx

注意:腾讯云镜像站(ccr.ccs.tencentyun.com)的Calico镜像已预拉取,下载速度远快于国外源,且无网络波动风险。切勿直接使用quay.io地址,否则kubectl apply可能卡在ImagePullBackOff数小时。

3. 存储挂载:CFS与CBS的权限迷宫,一个GID就能让整个StatefulSet瘫痪

在腾讯云K8s集群中,存储是最容易“表面正常、暗地崩溃”的模块。很多人以为挂载CFS(腾讯云文件存储)或CBS(云硬盘)只是写个PersistentVolume和PersistentVolumeClaim,然后在Pod里mount -t nfs就行。但现实是,K8s的存储抽象与腾讯云存储服务的权限模型之间,存在三处极易被忽视的“权限断点”,任何一个没对齐,都会导致Pod启动失败、应用写入报错、甚至数据损坏。

3.1 断点一:CFS的NFSv4.1 UID/GID映射陷阱

CFS底层基于NFSv4.1协议,其权限控制严格依赖客户端与服务端的UID/GID一致性。腾讯云CFS控制台创建文件系统时,默认启用“Root Squash”(根用户降权),即客户端以root身份(UID=0)挂载时,服务端会将其映射为nobody:nogroup(UID=65534/GID=65534)。这本是安全设计,但K8s的Pod默认以root用户运行,若应用又恰好需要在挂载点创建目录(如MySQL的/var/lib/mysql),就会因权限不足而失败。

解决方案不是关闭Root Squash(这会带来严重安全风险),而是在Pod定义中显式指定securityContext.runAsUser和securityContext.fsGroup,使其与CFS服务端的预期UID/GID匹配。腾讯云CFS的默认NFS导出选项中,anonuid和anongid通常设为65534,因此Pod配置应为:

apiVersion: v1 kind: Pod metadata: name: cfs-pod spec: securityContext: runAsUser: 65534 # 匹配CFS的anonuid fsGroup: 65534 # 匹配CFS的anongid,确保挂载点目录属组正确 containers: - name: app image: nginx volumeMounts: - name: cfs-volume mountPath: /data volumes: - name: cfs-volume persistentVolumeClaim: claimName: cfs-pvc

但这里有个隐藏坑:fsGroup的设置会导致K8s在挂载后自动递归修改/data目录下所有文件的属组为65534,如果CFS上已有大量历史文件(如GB级日志),这个操作会阻塞Pod启动长达数分钟。实测中,一个10GB的CFS目录,fsGroup递归chown耗时4分32秒。解决方法是:在CFS控制台创建文件系统时,提前设置anonuid和anongid为应用实际使用的UID/GID(如应用固定用UID=1001),然后Pod中runAsUser和fsGroup设为1001,避免递归修改。

3.2 断点二:CBS云硬盘的文件系统类型与挂载选项

CBS是块存储,需格式化后挂载。但腾讯云CBS的默认行为是:首次挂载时,若目标设备无文件系统,K8s会自动执行mkfs.ext4。这看似方便,却埋下两个雷:

  • 雷一:ext4的默认挂载选项不适用于高IO场景。CBS的IOPS性能受mount选项影响极大。例如,data=ordered(默认)会在每次写入前强制刷日志,而data=writeback则允许日志延迟写入,提升吞吐量30%以上。但对于数据库类应用,data=writeback可能增加崩溃后数据丢失风险,需权衡。

  • 雷二:CBS设备名不稳定。腾讯云CVM的CBS设备名可能是/dev/vdb、/dev/xvdb或/dev/nvme1n1,取决于CVM机型和CBS创建顺序。K8s的hostPath或localPV无法可靠绑定到具体设备名。

正确做法是:放弃自动格式化,改用StorageClass+VolumeSnapshot的标准化流程。首先创建一个StorageClass,显式指定CBS的type(如cloudPremium)、iops(如3000)和reclaimPolicy(Retain更安全):

apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: cbs-premium provisioner: disk.csi.ccs.cloud.tencent.com parameters: type: cloudPremium iops: "3000" reclaimPolicy: Retain

然后,通过PersistentVolumeClaim动态申请CBS,并在Pod中通过volumeMounts.subPath挂载到特定路径,避免直接操作设备名。对于需要精细控制挂载选项的场景(如MySQL),可在Pod.spec.containers.volumeMounts中添加mountOptions:

volumeMounts: - name: cbs-volume mountPath: /var/lib/mysql mountOptions: - defaults - noatime - data=writeback - barrier=0

注意:barrier=0禁用ext4日志屏障,仅在CBS后端为SSD且应用自身有强一致性保障(如MySQL的innodb_flush_log_at_trx_commit=1)时启用,否则可能导致元数据损坏。

3.3 断点三:Secret与ConfigMap挂载的“只读”幻觉

很多团队用Secret存数据库密码,ConfigMap存应用配置,然后挂载到Pod的/etc/config目录。他们认为“挂载即生效”,却忽略了K8s的挂载机制:Secret和ConfigMap是以tmpfs内存文件系统挂载的,其inode号在Pod生命周期内不变,但内容更新后,已打开的文件句柄(file descriptor)不会自动刷新。这意味着,如果应用在启动时open("/etc/config/db.conf")获取了fd,之后管理员更新了ConfigMap,应用仍读取旧内容,直到重启。

腾讯云环境下的特殊性在于:CVM节点的/proc/sys/fs/inotify/max_user_watches默认值(8192)常被大量Pod的ConfigMap挂载耗尽,导致inotify事件丢失,K8s无法触发挂载内容更新。现象是:kubectl edit configmap xxx后,ls -l /etc/config显示修改时间已变,但cat /etc/config/db.conf内容仍是旧的。

根治方案是:在CVM节点初始化脚本中,永久增大inotify限制:

# 添加到CVM的user-data启动脚本中 echo 'fs.inotify.max_user_watches = 524288' | sudo tee -a /etc/sysctl.conf sudo sysctl -p

同时,应用层需实现配置热重载(如Spring Boot的@RefreshScope),而非依赖文件系统事件。这才是云原生架构的正确姿势。

4. 监控告警:别只盯着Prometheus,腾讯云CLS日志与云监控指标才是真命脉

在腾讯云K8s集群中,监控体系常陷入一个误区:过度依赖Prometheus生态(Prometheus Server + Grafana + kube-state-metrics),却忽视了腾讯云原生的监控能力。结果是,当集群出现“CPU使用率95%但找不到进程”、“Pod频繁OOMKilled但cgroup日志为空”、“CLB后端健康检查失败但Pod日志无异常”等问题时,Prometheus提供的指标往往滞后、模糊,甚至缺失关键维度。

真正高效的监控,必须是三层联动:

  • 基础设施层(腾讯云CLS + 云监控):捕获CVM节点、CLB、CFS、CBS的原始指标与日志;
  • 容器运行时层(cAdvisor + kubelet metrics):提供Pod/CPU/Memory/Network的细粒度指标;
  • 应用层(OpenTelemetry + 自定义metrics):暴露业务逻辑的关键性能计数器。

其中,腾讯云CLS(日志服务)是打通这三层的枢纽,也是最容易被低估的能力。

4.1 CLS日志采集:不止是“收集stdout”,更是故障根因的时空坐标

腾讯云CLS支持通过DaemonSet方式部署LogListener(日志采集Agent),它不仅能采集Pod的标准输出(/var/log/containers/*.log),还能直接读取CVM节点的系统日志(/var/log/messages)、kubelet日志(/var/log/kubelet.log)、containerd日志(/var/log/containers/*.log)。这些日志的时间戳、进程ID、错误码,是定位“为什么Pod被驱逐”、“为什么节点NotReady”的唯一证据。

例如,当一个Pod被OOMKilled时,kubectl describe pod xxx只显示OOMKilled事件,但无法告诉你是什么进程占用了内存。此时,查询CLS中对应节点的kubelet.log,搜索"killing container"关键字,会看到类似日志:

E0315 14:22:31.882123 12345 kubelet.go:1321] Failed to kill pod "nginx-7c8b9d4f5-abcde": failed to "KillContainer" for "nginx" with KillContainerError: "rpc error: code = Unknown desc = failed to kill container \"abc123...\": failed to get container status: rpc error: code = Unknown desc = Error: No such container: abc123..."

这表明,containerd在尝试kill容器时,该容器ID已不存在——说明容器已被内核OOM Killer强制终止。接着,查同一时间点的/var/log/messages,搜索"Out of memory",会看到:

Mar 15 14:22:30 VM-123-45 kernel: [123456.789012] Out of memory: Kill process 12345 (java) score 892 or sacrifice child

至此,根因清晰:是Java进程内存泄漏,触发内核OOM,而非K8s主动驱逐。

这种跨日志源的关联分析,Prometheus无法做到。而CLS提供了强大的SQL-like查询语法(如* | select * from log where content like '%OOM%' and __topic__ = 'kubelet'),并支持按时间范围、Topic、关键词多维过滤,查询响应时间<1秒。

4.2 云监控指标:CLB健康检查与Pod就绪探针的“语义鸿沟”

另一个高频故障场景是:kubectl get pods显示所有Pod为Running,但外部通过CLB访问服务却大量502/503。排查发现,CLB控制台显示“后端服务器健康检查失败”,而Pod的readinessProbe配置明明是httpGet: /healthz且返回200。

问题出在CLB健康检查与K8s readinessProbe的语义不一致。CLB的健康检查是四层(TCP)或七层(HTTP)的独立探测,它不感知K8s的Pod状态,只根据CLB配置的端口、路径、超时时间、成功阈值来判断。而K8s的readinessProbe是容器内部的逻辑,即使它返回200,若CLB探测时Pod所在节点的iptables规则未生效(如Calico BGP路由未同步),CLB的探测包就无法到达Pod。

此时,Prometheus的kube_pod_status_phase指标只显示Running,毫无价值。而腾讯云监控的QCE/CLB命名空间下,有HealthCheckStatus指标,可直接查询每个后端服务器(即CVM节点IP)的健康检查状态。配合QCE/CVM的NetOutRate(外网出带宽)指标,可快速判断是CLB配置问题,还是节点网络拥塞。

我的标准排查流程是:

  1. 在云监控控制台,创建一个Dashboard,叠加QCE/CLB.HealthCheckStatus(维度:vip、port)和QCE/CVM.NetOutRate(维度:instanceId);
  2. 当503报警触发时,观察HealthCheckStatus为0(失败)的节点,对比其NetOutRate是否突增;
  3. 若NetOutRate正常,则登录该节点,执行sudo ss -tuln | grep :<CLB健康检查端口>,确认端口监听状态;
  4. 若端口未监听,检查kubectl get svc <svc-name> -o wide,确认ClusterIP是否正确分配,再查iptables -t nat -L KUBE-SERVICES | grep <ClusterIP>,确认NAT规则存在。

这套流程,全部基于腾讯云原生指标,无需部署额外Exporter,数据延迟<15秒,比Prometheus的scrape周期(通常30秒)更及时。

4.3 告警策略:用云监控事件总线(CloudEvent)替代Prometheus Alertmanager

最后,告警的触达方式也需云原生化。Prometheus Alertmanager虽强大,但其Webhook通知需自建服务接收,且与腾讯云短信、邮件、企业微信告警通道对接复杂。而腾讯云监控的事件总线(CloudEvent),可直接订阅K8s集群的kube-system命名空间下Event资源(如FailedScheduling、FailedMount、Evicted),并一键配置通知渠道。

例如,创建一个CloudEvent规则:

  • 事件源:TKE(腾讯云容器服务)
  • 事件类型:PodEvicted
  • 过滤条件:namespace == "prod"且reason == "Evicted"
  • 通知方式:企业微信机器人 + 短信(发送给值班工程师)

当Pod因资源不足被驱逐时,CloudEvent在10秒内触发告警,消息体中直接包含event.message(如The node was low on resource: memory. Container nginx was using 1.2Gi, which exceeds its request of 512Mi.),无需再登录集群kubectl get events。

这才是面向生产环境的监控告警范式:用云平台的原生能力,补足K8s生态的盲区,让监控从“可观测”升级为“可行动”。

5. 运维实战:一个真实的“CLB+Ingress+Pod”502故障全链路排查手记

理论终须落地。下面复盘一个我在腾讯云K8s集群中处理的真实故障,完整呈现从报警收到、初步定位、层层下钻到根因修复的全过程。这个案例覆盖了网络、存储、监控多个章节提到的关键点,也是检验你是否真正掌握“腾讯云+K8s”协同运维能力的试金石。

5.1 故障现象与初始报警

时间:某周三上午10:23
报警:企业微信收到两条消息

  • 【云监控】CLBlb-abc123的HealthCheckStatus指标在3个节点(10.0.1.101,10.0.1.102,10.0.1.103)上连续5分钟为0(失败)
  • 【Prometheus】kube_pod_status_phase{phase="Running", namespace="prod"}数量从12骤降至9

此时,外部用户反馈访问https://api.example.com/v1/users返回502 Bad Gateway,而curl http://10.0.1.101:30001(NodePort)可正常返回200。

5.2 第一层排查:CLB健康检查配置与后端绑定

登录腾讯云CLB控制台,检查lb-abc123:

  • 监听器:HTTPS 443 → 转发到HTTP 80(后端端口)
  • 健康检查:HTTP,路径/healthz,超时3秒,失败阈值3次,成功阈值1次
  • 后端服务器:3台CVM,状态均为“未通过健康检查”,权重为0

第一反应是健康检查路径问题。但curl http://10.0.1.101/healthz返回200,说明路径可达。接着检查CLB的“健康检查协议”:发现被误设为HTTP/1.0(默认值),而应用Pod的/healthz端点由Nginx Ingress Controller暴露,其响应头包含Connection: keep-alive,HTTP/1.0规范不支持此头,导致CLB解析响应失败,判定为健康检查失败。

提示:腾讯云CLB的健康检查协议选项在监听器配置页底部,非常隐蔽,常被忽略。

临时修复:将CLB健康检查协议改为HTTP/1.1,3秒后,3台节点状态变为“健康”,502报警停止。但问题未根除——为何CLB会默认用HTTP/1.0?为何之前一直正常?

5.3 第二层排查:Ingress Controller与Calico路由同步

既然CLB健康检查已恢复,但kubectl get pods -n ingress-nginx显示ingress-nginx-controller-xxx的READY状态为1/2(一个容器未就绪)。kubectl describe pod发现:

Events: Type Reason Age From Message ---- ------ ---- ---- ------- Warning Unhealthy 12m (x4 over 14m) kubelet Readiness probe failed: HTTP probe failed with statuscode: 503

readinessProbe失败,说明Ingress Controller自身健康检查不通过。进入Pod容器:

kubectl exec -it -n ingress-nginx ingress-nginx-controller-xxx -c controller -- sh # curl -v http://localhost:10254/healthz # 返回503

10254是Ingress Controller的健康检查端口,其/healthz由controller进程自身提供。503意味着controller进程异常。查kubectl logs -n ingress-nginx ingress-nginx-controller-xxx -c controller,发现大量日志:

W0315 10:25:33.123456 1 controller.go:234] Error getting SSL certificate "prod/tls-secret": local SSL certificate prod/tls-secret was not found. Using default certificate. E0315 10:25:33.123457 1 controller.go:235] Error loading custom certificates: local SSL certificate prod/tls-secret was not found

tls-secret是Ingress资源引用的TLS证书,存储在prod命名空间的Secret中。kubectl get secret -n prod tls-secret存在,但Ingress Controller日志说“not found”。这指向Calico的NetworkPolicy或节点网络问题——Ingress Controller Pod无法访问kube-apiserver获取Secret。

查kubectl get networkpolicy -A,发现prod命名空间有一个deny-all的NetworkPolicy,但ingress-nginx命名空间没有。继续查kubectl get endpoints -n default kubernetes,确认API Server的Endpoint可达。最后,执行kubectl get nodes -o wide,发现10.0.1.101节点的STATUS为NotReady!
kubectl describe node 10.0.1.101显示:

Conditions: Type Status LastHeartbeatTime LastTransitionTime Reason Message ---- ------ ----------------- ------------------ ------ ------- Ready False Wed, 15 Mar 2023 10:20:12 +0000 Wed, 15 Mar 2023 10:15:05 +0000 KubeletNotReady runtime network not ready: NetworkReady=false reason:NetworkPluginNotReady message:docker: network plugin is not ready: cni config uninitialized

根因浮现:10.0.1.101节点的CNI插件未就绪,导致该节点上所有Pod(包括Ingress Controller)无法与API Server通信,进而无法加载Secret,/healthz返回503,CLB健康检查失败。

5.4 第三层排查:CNI插件未就绪的深层原因

登录10.0.1.101节点,查systemctl status calico-node:

● calico-node.service - Calico node driver Loaded: loaded (/etc/systemd/system/calico-node.service; enabled; vendor preset: enabled) Active: activating (auto-restart) since Wed 2023-03-15 10:15:05 UTC; 5min ago Docs: https://docs.projectcalico.org/ Process: 12345 ExecStart=/usr/local/bin/calico-node -felix-ready-file=/var/run/calico/felix-ready -bird-ready-file=/var/run/calico/bird-ready (code=exited, status=1/FAILURE) Main PID: 12345 (code=exited, status=1/FAILURE)

查journalctl -u calico-node -n 100,关键错误:

2023-03-15 10:15:04.123456 UTC [INFO][12345] startup/startup.go 397: Early log level set to info 2023-03-15 10:15:04.123457 UTC [INFO][12345] startup/startup.go 413: Using NODENAME environment for node name 2023-03-15 10:15:04.123458 UTC [INFO][12345] startup/startup.go 425: Determined node name: vm-101-101 2023-03-15 10:15:04.123459 UTC [INFO][12345] startup/startup.go 105: Checking datastore connection 2023-03-15 10:15:04.123460 UTC [FATAL][12345] startup/startup.go 108: Connection to the datastore is unauthorized error=connection is unauthorized

Connection to the datastore is unauthorized——Calico无法连接etcd(数据存储)。但kubectl get nodes显示其他节点正常,说明etcd集群本身OK。查/etc/cni/net.d/:

ls -l /etc/cni/net.d/ # total 4 # -rw------- 1 root root 1234 Mar 15 10:00 10-calico.conflist

10-calico.conflist存在,但权限是600(仅root可读)。而calico-node容器以root用户运行,理论上可读。继续查calico-node的启动参数,发现它通过hostPath挂载了/etc/cni/net.d/,但挂载时未设置readOnly: false,导致容器内/etc/cni/net.d/为只读。calico-node启动时需写入/etc/cni/net.d/calico-tls/目录存放证书,只读挂载导致失败。

终极根因:calico-nodeDaemonSet的volumeMounts中,/etc/cni/net.d挂载缺少readOnly: false声明,且/etc/cni/net.d/目录在节点上被chmod 600锁死,双重限制导致Calico无法初始化。

5.5 修复与验证

立即修复:

  1. 在`10.0.1.1

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询