你们中的许多人可能都熟悉《布莱恩的生活》中的那一刻,约翰-克莱斯列举了罗马帝国给犹太地区带来的所有改进,然后问道:"罗马人为我们做了什么?"我提到这一点是因为,最近有一天,我在翻阅twitter时偶然发现了一个用户的宝库,他们指责Kubernetes的复杂性,声称在它出现之前事情就已经好了。所以,为了公平起见,我决定写一点关于辉煌的过去和我们平庸的现在,并对两者进行比较。
工程师们喜欢发现建筑中的问题,并指责技术使事情过于复杂化。是的,我们绝对是这样做的;不要费力地否认。只是,有时我们忘记了这些适应性的存在是为了解决什么问题,以及为什么还是值得在不同的平台上投资的努力。
这篇文章主要是关于在几家公司管理基础设施和做DevOps/SRE工作的(糟糕)经验。当然,这些轶事可能并不适用于今天的基础设施,但我相信你们中的很多人都有长期压抑的类似记忆,这篇博文将有助于唤醒你们。
每个系统都从基本的基础设施开始。你需要知道你在哪里有机器,有什么样的机器。不管这个架构是物理的还是虚拟的,或者是你桌子上的笔记本电脑(我见过的生产服务比你相信的更多,它们都是通过笔记本运行的),都没有关系。你需要关于这个基础设施的其他基本信息,我不是指监控,这是后话。只是一些简单的事情:它们在哪里?它们在运行吗?它们正在运行什么样的进程?这可能看起来微不足道,但在我们有一个平台之前,我们有无数的定制工具来做这件事。
在你的基础设施中达到一定数量的机器后,你可能开始使用基础设施自动化工具,如Ansible、Salt和Chef。这些工具都有自己的操作方式。它们保持着最新的库存,并提供了一个与机器互动的界面,而不需要手动登录到机器上。你甚至可以编写(至少我们是这样做的)自定义集成来扩展云中的工作负载或检查系统的完整性。一段时间后,其中一些机器从这种自动化中解脱出来(这就是牛逼的服务模式开始流行的地方)。他们有一个固定版本的软件。它们变得如此专业和微妙,以至于在一定的时间过去后,没有人敢于升级或重启它们(去过那里,见过)。
在Kubernetes中,一切都在不断提醒你,你的所有资源都是一次性的。你永远不必因为一台机器的功能而把自己固定在它上面。你用它们来获取原始动力,仅此而已。检查库存是一个永远在你指尖上的选项。
$ kubectl get nodes
NAME STATUS ROLES AGE VERSION
ip-10-0-0-103.us-east-2.compute.internal Ready 8d v1.17.7-eks-bffbac
ip-10-0-1-225.us-east-2.compute.internal Ready 8d v1.17.7-eks-bffbac
ip-10-0-2-145.us-east-2.compute.internal Ready 8d v1.17.7-eks-bffbac
这可能看起来微不足道,但我记得,早在容器化世界的全盛时期,所有的部件都必须设置成完美的排列,以便应用程序能够正常运行。不同的SDK,定制的库,都是整个文化对无缝升级的反叛的一部分。我们不得不花大量的时间来仔细规划,利用各种沙盒环境来检查潜在的失败情况(我们仍然错过了一些)。现在把这与构建和测试一个容器相比较,之后只需使用一个命令就能更新它。仅仅这一点就值得我们在Kubernetes上花费时间。部署和Replicaset的概念诞生于以标准化的方式处理升级和回滚的需要。所有这些的樱桃是,Kubernetes为所有这些资源提供了REST API。
$ kubectl set image deployment nginx nginx=nginx:1.9.1

另一个长期存在的争论点是服务发现和DNS。在裸机基础设施上,我们有自定义的DHCP服务器和DNS(bind、dnsmasq、unbound,甚至一些自定义)实例来管理这个简单而复杂的功能。我们根据应用指标管理公共记录、内部记录和自定义DNS响应,是的,有时我们会花一晚上时间来调试出错的地方。Kubernetes的内置DNS和服务概念解决了大部分问题。我们有有限的但很确定的(如果你认为是轮回确定的)解析规则。此外,改变底层网络驱动现在是微不足道的。你可以选择任何支持CNI接口的供应商。

更妙的是,叠加网络和网络策略为开发者简化了网络堆栈。你不会遇到VLANs、封装、自定义路由规则(除非你负责Kubernetes的操作)。默认的行为是这样的,所有的东西都是连接的。如果你需要把东西分开,你只需要定义网络策略,就可以了。容易理解,更容易审计。
工作和Cronjob是传统基础设施的另一个隐患。通常,有一个节点(或几个节点)来运行作业。它们通常连接到各种网络(也许最初不是,但从长远来看肯定是)。它们在临时资源上运行垃圾收集,或运行备份或其他各种东西。在一个快速发展的环境中,很难跟踪什么在运行,以及在哪里运行。根据我的经验,如果你需要快速的东西,你就不会费心去自动化它。这并不是一个问题,因为我们的工作是保持服务的在线。然而,有时一项重要的工作却停留在灰色地带。有一次,我们在调试分析数据的缺失;一项工作应该是把数据从A地传送到B地。我们扫描了所有的自动化,没有发现任何证据表明这样的过程存在。我们开始怀疑这个东西是如何工作了这么久的。检查时间线,我们发现当数据开始枯竭时,一台不相关的机器已经重启了。进一步调查发现,一个在屏幕命令中运行的shell脚本负责执行这个任务。
Kubernetes有一个处理这些问题的标准方法。它不将作业与节点绑定。你可以像其他资源一样列出创建、删除作业:不再在屏幕内运行阴暗的脚本。
apiVersion: batch/v1beta1
kind: CronJob
metadata:
name: hello
spec:
schedule: "*/1 * * * *"
jobTemplate:
spec:
template:
spec:
containers:
- name: awesomeJob
image: busybox
args:
- /bin/sh do the thing
restartPolicy: OnFailure
像这样的故事有很多。每个人都有这个技术最喜欢或最讨厌的方面。我们可以继续讨论Kubernetes的功能,如配额、安全策略等,但我不想写一个Kubernetes功能博客。我只是想收集一些老故事,如果我们使用Kubernetes,结果会不一样。还有,请记住!你要问自己的是,除了卫生设施、医药、教育、葡萄酒、公共秩序、灌溉、道路、淡水系统和公共卫生,罗马人还为我们做过什么?


