Kubernetes中的一切是一个控制循环
想象一个非常必要的 "集群操作系统" , 就像上面描述的那样 , 它暴露了 "分配5个CPU的计算量 " 或 "创建一个新的虚拟网络 "这样的基元 , 这些基元反过来又支持系统内部抽象的配置变化或对EC2 API(或其他基础云提供商)的调用 。
但Kubernetes并非是这样进行工作的 , 相反 , Kubernetes的核心设计决定了所有的配置都是声明性的 , 并且都是通过作为控制循环"操作者 "的方式实现 。 他们不断地将期望的配置与现实的状态进行比较 , 并修改现实状态 , 达到与期望状态一致 。
【K8s 为什么这么复杂?】这是一个非常慎重且理由充分的设计抉择 。 一般来说 , 任何没有被设计成控制循环的系统都将不可避免地偏离期望配置 , 因此 , 需要有人来编写控制循环并通过内部化来进行控制 。 Kubernetes希望能让大多数核心控制环路只写一次 , 而且是由领域专家来写 , 从而使在其上构建可靠的系统变得更加容易 。 这也是一个系统的自然选择 , 因为它的本质是分布式的 , 而且是为构建分布式系统而设计的 。 分布式系统的决定性性质是排除部分可能性的故障 , 这就要求超过一定规模的系统能够自我修复 , 并收敛于正确的状态 , 而不考虑局部故障 。
然而 , 这种设计也带来了系统的复杂性和一定几率的混乱 。 挑两个具体的例子 。
第一:错误延迟 ,在Kubernetes中创建一个对象(例如一个pod) , 这只是在配置存储中创建一个对象 , 断言该对象的预期存在 。 如果由于资源限制(集群的容量) , 或者由于对象在某些方面内部不一致(比如引用的容器镜像不存在) , 系统在实际分配上不可能满足该请求 , 但用户在创建时无法看到系统的实际情况 。 事实上 , 只有当开发者要修改创建对象时 , 系统才会产生错误提示 。
这种情况使得一切都更难调试和推理 , 因为你不能用"创建成功 "作为 "结果对象存在 "的一个速记 。 这也意味着 , 与失败有关的日志信息或调试输出信息不会出现在创建对象的进程中 。 一个代码完整 , 功能强大的控制器 , 系统会解释正在发生的事情 , 或以其他方式注释有问题的对象;但对于较差的控制器 , 控制器的日志中只能找到日志垃圾 。 而且有些变化可能涉及到多个控制器 , 它们有时独立行动 , 有时联合行动 , 这就很难去追踪发生故障的代码 。
声明式的控制循环模式提供了一个隐含的承诺:用户不需要担心如何从状态A到状态B , 只需要把状态B写进配置数据库 , 然后等待 。 当它的代码运行良好时 , 从状态A自然就进入到状态B了 。 这是一个巨大的简化 。
但有时也会失误 , 无法或需要等待很长时间从状态A到状态B , 即使状态B本身可以实现 。 这是一个罕见的例子 , 控制器的作者可能忘记实现它了 。 Kubernetes中的核心内置基元经过很多测试和使用 , 以此来一直保持正常工作 。 但当用户开始添加第三方资源 , 比如以管理TLS证书、云负载均衡器、托管数据库或外部DNS名称等去运行系统时 , 程序就会偏离轨道 , 变得不能清楚的知道路径是怎么经过测试的 。 这个故障模式和延迟错误一样微妙 。 很难区分“变化被接受”和“变化永远不会被接受”的区别
以上就是来自Hacker News的博主分享的他对Kubernetes为什么这么复杂的看法 。 该博主认为 , 对Kubernetes本身、其复杂性以及对其服务的目标有个很好地理解 , 是一件非常有意义的事 。 希望这篇文章对刚开始使用Kubernetes的人能有一定帮助 。
参考链接:
https://buttondown.email/nelhage/archive/two-reasons-kubernetes-is-so-complex/
特别声明:本站内容均来自网友提供或互联网,仅供参考,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
