为什么 Kubernetes 很酷
在我刚开始学习 Kubernetes（大约是一年半以前吧？）时，我真的不明白为什么应该去关注它。

在我使用 Kubernetes 全职工作了三个多月后，我才逐渐明白了为什么我应该使用它。
Kubernetes 容器
在我刚开始学习 Kubernetes（大约是一年半以前吧？）时，我真的不明白为什么应该去关注它。

在我使用 Kubernetes 全职工作了三个多月后，我才逐渐明白了为什么我应该使用它。
![](/data/attachment/album/201802/03/234107htpn7qntr02q6qos.jpg)


在我刚开始学习 Kubernetes（大约是一年半以前吧？）时，我真的不明白为什么应该去关注它。


在我使用 Kubernetes 全职工作了三个多月后，我才逐渐明白了为什么我应该使用它。（我距离成为一个 Kubernetes 专家还很远！）希望这篇文章对你理解 Kubernetes 能做什么会有帮助！


我将尝试去解释我对 Kubernetes 感兴趣的一些原因，而不去使用 “<ruby> 原生云 <rt>  cloud native </rt></ruby>”、“<ruby> 编排系统 <rt>  orchestration </rt></ruby>”、“<ruby> 容器 <rt>  container </rt></ruby>”，或者任何 Kubernetes 专用的术语 :)。我去解释的这些观点主要来自一位 Kubernetes 操作者/基础设施工程师，因为，我现在的工作就是去配置 Kubernetes 和让它工作的更好。


我不会去尝试解决一些如 “你应该在你的生产系统中使用 Kubernetes 吗？”这样的问题。那是非常复杂的问题。（不仅是因为“生产系统”根据你的用途而总是有不同的要求）


### Kubernetes 可以让你无需设置一台新的服务器即可在生产系统中运行代码


我首次被说教使用 Kubernetes 是与我的伙伴 Kamal 的下面的谈话：


大致是这样的：


* Kamal： 使用 Kubernetes 你可以通过一条命令就能设置一台新的服务器。
* Julia： 我觉得不太可能吧。
* Kamal： 像这样，你写一个配置文件，然后应用它，这时候，你就在生产系统中运行了一个 HTTP 服务。
* Julia： 但是，现在我需要去创建一个新的 AWS 实例，明确地写一个 Puppet 清单，设置服务发现，配置负载均衡，配置我们的部署软件，并且确保 DNS 正常工作，如果没有什么问题的话，至少在 4 小时后才能投入使用。
* Kamal: 是的，使用 Kubernetes 你不需要做那么多事情，你可以在 5 分钟内设置一台新的 HTTP 服务，并且它将自动运行。只要你的集群中有空闲的资源它就能正常工作！
* Julia: 这儿一定是一个“坑”。


这里有一种陷阱，设置一个生产用 Kubernetes 集群（在我的经险中）确实并不容易。（查看 [Kubernetes 艰难之旅](https://github.com/kelseyhightower/kubernetes-the-hard-way) 中去开始使用时有哪些复杂的东西）但是，我们现在并不深入讨论它。


因此，Kubernetes 第一个很酷的事情是，它可能使那些想在生产系统中部署新开发的软件的方式变得更容易。那是很酷的事，而且它真的是这样，因此，一旦你使用一个运作中的 Kubernetes 集群，你真的可以仅使用一个配置文件就在生产系统中设置一台 HTTP 服务（在 5 分钟内运行这个应用程序，设置一个负载均衡，给它一个 DNS 名字，等等）。看起来真的很有趣。


### 对于运行在生产系统中的代码，Kubernetes 可以提供更好的可见性和可管理性


在我看来，在理解 etcd 之前，你可能不会理解 Kubernetes 的。因此，让我们先讨论 etcd！


想像一下，如果现在我这样问你，“告诉我你运行在生产系统中的每个应用程序，它运行在哪台主机上？它是否状态很好？是否为它分配了一个 DNS 名字？”我并不知道这些，但是，我可能需要到很多不同的地方去查询来回答这些问题，并且，我需要花很长的时间才能搞定。我现在可以很确定地说不需要查询，仅一个 API 就可以搞定它们。


在 Kubernetes 中，你的集群的所有状态 – 运行中的应用程序 (“pod”)、节点、DNS 名字、 cron 任务、 等等 —— 都保存在一个单一的数据库中（etcd）。每个 Kubernetes 组件是无状态的，并且基本是通过下列方式工作的：


* 从 etcd 中读取状态（比如，“分配给节点 1 的 pod 列表”）
* 产生变化（比如，“在节点 1 上运行 pod A”）
* 更新 etcd 中的状态（比如，“设置 pod A 的状态为 ‘running’”）


这意味着，如果你想去回答诸如 “在那个可用区中有多少台运行着 nginx 的 pod？” 这样的问题时，你可以通过查询一个统一的 API（Kubernetes API）去回答它。并且，你可以在每个其它 Kubernetes 组件上运行那个 API 去进行同样的访问。


这也意味着，你可以很容易地去管理每个运行在 Kubernetes 中的任何东西。比如说，如果你想要：


* 部署实现一个复杂的定制的部署策略（部署一个东西，等待 2 分钟，部署 5 个以上，等待 3.7 分钟，等等）
* 每当推送到 github 上一个分支，自动化 [启动一个新的 web 服务器](https://github.com/kamalmarhubi/kubereview)
* 监视所有你的运行的应用程序，确保它们有一个合理的内存使用限制。


这些你只需要写一个程序与 Kubernetes API（“controller”）通讯就可以了。


另一个关于 Kubernetes API 的令人激动的事情是，你不会局限于 Kubernetes 所提供的现有功能！如果对于你要部署/创建/监视的软件有你自己的方案，那么，你可以使用 Kubernetes API 去写一些代码去达到你的目的！它可以让你做到你想做的任何事情。


### 即便每个 Kubernetes 组件都“挂了”，你的代码将仍然保持运行


关于 Kubernetes 我（在各种博客文章中 :)）承诺的一件事情是，“如果 Kubernetes API 服务和其它组件‘挂了’也没事，你的代码将一直保持运行状态”。我认为理论上这听起来很酷，但是我不确定它是否真是这样的。


到目前为止，这似乎是真的！


我已经断开了一些正在运行的 etcd，发生了这些情况：


1. 所有的代码继续保持运行状态
2. 不能做 *新的* 事情（你不能部署新的代码或者生成变更，cron 作业将停止工作）
3. 当它恢复时，集群将赶上这期间它错过的内容


这样做意味着如果 etcd 宕掉，并且你的应用程序的其中之一崩溃或者发生其它事情，在 etcd 恢复之前，它不能够恢复。


### Kubernetes 的设计对 bug 很有弹性


与任何软件一样，Kubernetes 也会有 bug。例如，到目前为止，我们的集群控制管理器有内存泄漏，并且，调度器经常崩溃。bug 当然不好，但是，我发现 Kubernetes 的设计可以帮助减轻它的许多核心组件中的错误的影响。


如果你重启动任何组件，将会发生：


* 从 etcd 中读取所有的与它相关的状态
* 基于那些状态（调度 pod、回收完成的 pod、调度 cron 作业、按需部署等等），它会去做那些它认为必须要做的事情


因为，所有的组件并不会在内存中保持状态，你在任何时候都可以重启它们，这可以帮助你减轻各种 bug 的影响。


例如，如果在你的控制管理器中有内存泄露。因为，控制管理器是无状态的，你可以每小时定期去重启它，或者，在感觉到可能导致任何不一致的问题发生时重启它。又或者，在调度器中遇到了一个 bug，它有时忘记了某个 pod，从来不去调度它们。你可以每隔 10 分钟来重启调度器来缓减这种情况。（我们并不会这么做，而是去修复这个 bug，但是，你*可以这样做* :））


因此，我觉得即使在它的核心组件中有 bug，我仍然可以信任 Kubernetes 的设计可以让我确保集群状态的一致性。并且，总在来说，随着时间的推移软件质量会提高。唯一你必须去操作的有状态的东西就是 etcd。


不用过多地讨论“状态”这个东西 —— 而我认为在 Kubernetes 中很酷的一件事情是，唯一需要去做备份/恢复计划的东西是 etcd （除非为你的 pod 使用了持久化存储的卷）。我认为这样可以使 Kubernetes 运维比你想的更容易一些。


### 在 Kubernetes 之上实现新的分布式系统是非常容易的


假设你想去实现一个分布式 cron 作业调度系统！从零开始做工作量非常大。但是，在 Kubernetes 里面实现一个分布式 cron 作业调度系统是非常容易的！（仍然没那么简单，毕竟它是一个分布式系统）


我第一次读到 Kubernetes 的 cron 作业控制器的代码时，我对它是如此的简单感到由衷高兴。去读读看，其主要的逻辑大约是 400 行的 Go 代码。去读它吧！ => [cronjob\_controller.go](https://github.com/kubernetes/kubernetes/blob/e4551d50e57c089aab6f67333412d3ca64bc09ae/pkg/controller/cronjob/cronjob_controller.go) <=


cron 作业控制器基本上做的是：


* 每 10 秒钟：
	+ 列出所有已存在的 cron 作业
	+ 检查是否有需要现在去运行的任务
	+ 如果有，创建一个新的作业对象去调度，并通过其它的 Kubernetes 控制器实际运行它
	+ 清理已完成的作业
	+ 重复以上工作


Kubernetes 模型是很受限制的（它有定义在 etcd 中的资源模式，控制器读取这个资源并更新 etcd），我认为这种相关的固有的/受限制的模型，可以使它更容易地在 Kubernetes 框架中开发你自己的分布式系统。


Kamal 给我说的是 “Kubernetes 是一个写你自己的分布式系统的很好的平台” ，而不是“ Kubernetes 是一个你可以使用的分布式系统”，并且，我觉得它真的很有意思。他做了一个 [为你推送到 GitHub 的每个分支运行一个 HTTP 服务的系统](https://github.com/kamalmarhubi/kubereview) 的原型。这花了他一个周末的时间，大约 800 行 Go 代码，我认为它真不可思议！


### Kubernetes 可以使你做一些非常神奇的事情（但并不容易）


我一开始就说 “kubernetes 可以让你做一些很神奇的事情，你可以用一个配置文件来做这么多的基础设施，它太神奇了”。这是真的！


为什么说 “Kubernetes 并不容易”呢？是因为 Kubernetes 有很多部分，学习怎么去成功地运营一个高可用的 Kubernetes 集群要做很多的工作。就像我发现它给我了许多抽象的东西，我需要去理解这些抽象的东西才能调试问题和正确地配置它们。我喜欢学习新东西，因此，它并不会使我发狂或者生气，但是我认为了解这一点很重要 :）


对于 “我不能仅依靠抽象概念” 的一个具体的例子是，我努力学习了许多 [Linux 上网络是如何工作的](https://jvns.ca/blog/2016/12/22/container-networking/)，才让我对设置 Kubernetes 网络稍有信心，这比我以前学过的关于网络的知识要多很多。这种方式很有意思但是非常费时间。在以后的某个时间，我或许写更多的关于设置 Kubernetes 网络的困难/有趣的事情。


或者，为了成功设置我的 Kubernetes CA，我写了一篇 [2000 字的博客文章](https://jvns.ca/blog/2017/08/05/how-kubernetes-certificates-work/)，述及了我不得不学习 Kubernetes 不同方式的 CA 的各种细节。


我觉得，像 GKE （Google 的 Kubernetes 产品) 这样的一些监管的 Kubernetes 的系统可能更简单，因为，他们为你做了许多的决定，但是，我没有尝试过它们。




---


via: <https://jvns.ca/blog/2017/10/05/reasons-kubernetes-is-cool/>


作者：[Julia Evans](https://jvns.ca/about) 译者：[qhwdw](https://github.com/qhwdw) 校对：[wxy](https://github.com/wxy)


本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出

