分享
  1. 首页
  2. 文章

kubernetes实战与源码剖析「完结无密」

124544 · · 28 次点击 · · 开始浏览

获课:999it.top/15769/ Kubernetes进阶实战:源码视角下的调优与故障排查思维构建 当我第一次通过Kubernetes源码来调试一个看似诡异的调度问题时,我意识到真正的系统理解不是来自文档或教程,而是来自与代码的直接对话。作为开发者,我们常把Kubernetes当作黑盒使用,但当你需要优化生产集群性能或排查深层次故障时,源码视角能给你完全不同的洞察力。这不是关于背诵代码行数,而是关于建立一种与系统深度对话的思维方式。 一、调度器:从现象到源码的逆向工程 有一次,我们生产环境中几个关键Pod总被调度到同一节点,即使其他节点资源充足。文档和常规排查都指向节点亲和性配置,但检查后一无所获。 突破来自源码视角:我直接定位到Kubernetes调度器源码的优选阶段(priority functions)。在pkg/scheduler/framework/plugins/目录下,我发现除了常见的NodeAffinity、InterPodAffinity,还有一个不太被注意的NodeResourcesBalancedAllocation插件。它的目标是平衡各节点的资源使用率,防止某些节点过早填满。 但这里有个关键细节:该插件主要平衡CPU和内存,但对GPU这类扩展资源处理不同。我们的Pod恰好请求了GPU。源码中的这段逻辑解释了现象: text 复制 下载 实际上,调度器对扩展资源的平衡考虑有限,这导致了一个隐性的调度偏好——一旦某个节点被标记为"有GPU",后续请求GPU的Pod会更倾向于它,即使从全局看这不平衡。 解决方法不是修改Kubernetes源码,而是通过自定义调度器插件,或者简单调整Pod的资源请求方式。但如果没有源码视角,我可能还在YAML文件里徒劳地检查亲和性规则。 二、控制器模式:理解系统行为的钥匙 Kubernetes的核心设计模式是控制器模式(Controller Pattern),几乎所有的高级功能都基于此。理解这个模式对故障排查至关重要。 最近遇到一个 Deployment 滚动更新卡住的问题。kubectl describe 显示"等待 Pod 就绪"。通常步骤是检查 Pod 事件、探针配置,但这次一切正常。 通过源码,我追踪到 Deployment 控制器在 kkg/controller/deployment/deployment_controller.go 中的 syncDeployment 方法。关键逻辑是: 控制器计算当前状态与期望状态的差异 创建新的 ReplicaSet 逐步缩放新旧 ReplicaSet 但在我们的案例中,问题出现在第3步。深入代码后发现,滚动更新进度不仅取决于Pod就绪,还受maxSurge和maxUnavailable参数影响。我们的配置是maxUnavailable: 0,意味着更新时必须始终有100%的Pod就绪。 而其中一个Pod所在的节点出现了短暂的网络分区(但很快恢复),导致就绪状态更新延迟了几秒。就是这几秒,让整个滚动更新"暂停"了——因为控制器严格遵循maxUnavailable: 0的约束,不敢终止任何旧Pod。 从源码中我理解了这不是bug,而是设计如此。控制器被设计为在不确定时选择安全路径:宁愿等待也不冒险违反用户定义的策略。解决方案是调整更新策略,接受短暂的服务降级(如设置maxUnavailable: 1),或改善节点间网络可靠性。 三、ETCD性能:集群的"记忆体"如何影响一切 我们曾有一个集群,随着资源对象数量增长,API服务器响应明显变慢。监控显示etcd磁盘I/O持续高企。 表面看是etcd需要优化或扩容。但通过研究kube-apiserver源码,特别是与etcd交互的部分,我发现了更微妙的关联。 在 staging/src/k8s.io/apiserver/pkg/storage/etcd3/store.go 中,每个资源对象的读写都会转换为对etcd的操作。但重要的是 List操作:当客户端(包括控制器)列出资源时,默认会从etcd获取完整对象。 随着集群中Pod数量突破5000,一个简单的kubectl get pods -A(或任何控制器的全量List)都会成为性能杀手。更糟的是,许多控制器定期执行全量List来同步状态。 解决方案来自源码的两个启示: 使用资源版本(ResourceVersion)进行增量同步:聪明的控制器会记录最后看到的资源版本,只请求此后的变化 优化客户端筛选:在List时使用字段选择器减少传输数据量 我们审计了集群中所有自定义控制器,将其中三个从全量List改为增量Watch后,etcd负载下降了40%。这个优化不需要修改Kubernetes本身,但需要对API服务器如何与etcd交互有深入理解——而这理解最直接的来源就是源码。 四、网络疑难杂症:穿越CNI的迷雾 网络问题可能是Kubernetes中最棘手的。有一次,某些Pod间通信延迟异常高,但跨节点通信反而正常。 通常的网络排查会检查CNI插件配置、iptables规则、节点路由。但当我们进入kube-proxy源码,特别是iptables模式下的数据包流向时,发现了有趣的设计。 在pkg/proxy/iptables/proxier.go中,syncProxyRules方法生成所有iptables规则。重要的是服务访问路径: 同一节点上的Pod访问Service,经过LOCALOUTPUT链 跨节点访问,经过FORWARD链 我们的延迟问题出现在第一种情况。进一步追踪LOCALOUTPUT链的规则,发现当Pod通过Service域名访问同一节点的另一个Pod时,数据包会经过完整的DNAT、conntrack记录和Kube-Proxy过滤。 关键在于:iptables的conntrack模块在连接数多时有性能开销。虽然我们的连接数不算极高,但Pod生命周期短(频繁创建销毁),导致conntrack表中有大量"僵死"条目。 源码没有直接给出解决方案,但理解了数据路径后,我们可以做出针对性优化: 为短生命周期Pod使用HostNetwork模式(不总是可行) 调整conntrack超时参数 考虑使用IPVS模式替代iptables 最终,我们结合了2和3,延迟问题得到显著改善。

有疑问加站长微信联系(非本文作者))

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

关注微信
28 次点击
暂无回复
添加一条新回复 (您需要 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传

用户登录

没有账号?注册
(追記) (追記ここまで)

今日阅读排行

    加载中
(追記) (追記ここまで)

一周阅读排行

    加载中

关注我

  • 扫码关注领全套学习资料 关注微信公众号
  • 加入 QQ 群:
    • 192706294(已满)
    • 731990104(已满)
    • 798786647(已满)
    • 729884609(已满)
    • 977810755(已满)
    • 815126783(已满)
    • 812540095(已满)
    • 1006366459(已满)
    • 692541889

  • 关注微信公众号
  • 加入微信群:liuxiaoyan-s,备注入群
  • 也欢迎加入知识星球 Go粉丝们(免费)

给该专栏投稿 写篇新文章

每篇文章有总共有 5 次投稿机会

收入到我管理的专栏 新建专栏