近几年,Kubernetes 很火,我也从事与之相关的工做有数年时间。Kubernetes 的价值是什么?它适用于哪些场景?咱们应该使用 Kubernetes 吗?...... 本文试图回答这些问题。数组
我常常从团队——不管是新团队仍是成熟团队——那里听到一个问题:“咱们应该将软件栈托管在 Kubernetes 上吗?”鉴于 Kubernetes 在科技界的名声大噪,不少人都认为应该这么作。我从事 K8s 的相关工做有好几年了——一般是在很是强大而复杂的平台上,我认为实际状况会更加微妙一些。在这篇文章中,我试着弄清楚这个问题。本文主要针对那些负责托管本身产品的初创公司和自给自足的团队,不过对于大型组织传统 IT 部门的人员来讲,可能也有必定的价值。缓存
Kubernetes 不只仅是 2018 年的一个流行词而已,它是一个健壮、高度可伸缩的系统,让你能在原语 (Pod、Service、Ingress 等) 基础上进行应用程序部署,而后尽其所能实现你想要的东西。在应用程序发生崩溃时,它会从新启动它们。若是你正在运行不少服务 (可能采用了微服务架构),而且追求效率、弹性和好的部署方法,那么它能为你作不少事情。安全
想要让你的服务具备基本程度的弹性?那就部署多个副本,而后在它们之间均衡流量。网络
若是你的工做负载具备“爆发”(例如大量的 API 流量) 的特色,能够在此基础上经过设置自动伸缩来增长必要的容量。这能为你节省不少钱,你不须要一直为峰值容量付费,只须要提供一个基本负载来保持平台运行,并在必要时提供更多副本。若是你能够将队列长度导入到系统中,那么自动伸缩功能也适用于基于队列的工做负载。架构
担忧代码会出问题?那就配置就绪探针,在服务发生崩溃时,Kubernetes 会自动重启它们。对于硬件故障也是同样——我看到过一个集群,它有一半节点发生瘫痪,但仍然像什么都没发生同样继续运行。通过精心配置和维护的 Kubernetes 集群能够变得很是健壮。若是你有足够的资源,甚至能够尝试运行相似 Chaos Monkey 这样的工具,确保你的软件栈能容忍常常性的故障。app
Kubernetes 能够与 CI 工做流很好地集成在一块儿。最多见的模式是将镜像推送到 Docker 注册表,而后启动 K8s 集群来加载它 (理想状况下,全部项目都是标准化的)。这能够根据具体状况经过修改部署来拉出新的标记,或者将标记指向新镜像,并触发 K8s 从新加载全部 Pod。在大多数状况下,部署能够是彻底自动化的。若是你对测试颇有信心,那就能够 100% 自动化 (也就是持续交付),若是不是颇有信心,在构建以后进行手动检查仍然能帮你减轻痛苦。不管哪一种方式,开发人员都应该能在没有 Kubernetes 专家帮助的状况下将大多数构建版本发布到集群中。负载均衡
与 CI 相似,它能够帮你对应用程序的日志和监控进行标准化。这些并非 Kubernetes 独有的,但无论怎样,使用一个集群将全部服务的数据收集到一块儿能够极大地减轻调试的痛苦。less
我看到有人用 fluentd 将 JSON 结构的日志从应用程序传输到 AWS CloudWatch,并经过 Insights 进行查询,效果很是好。运维
最后,它能够极大地提升效率——不只在托管层,并且还能够减小开发人员部署软件所需的时间。人力成本高于计算机成本,所以对大多数组织来讲,这是最大的胜利。但 Kubernetes 并不是魔法——我看到过一些漂亮、高效的集群,也看到了一些“纸老虎”。要想让 Kubernetes 为你省钱,必须用对它。ide
首先,分析一下你的工做负载。你须要运行什么类型的应用程序?它们之间以及与外部世界之间是如何通讯的?根据个人经验,我认为能够经过如下这些属性来判断是否可使用 Kubernetes:
你采用的是微服务架构吗?若是你只有一个应用程序,那么使用 Kubernetes 就没有什么价值。你须要容器化应用程序,而后将它们部署到 K8s 上。从项目开始时就这样作有助于你思考服务之间的边界。
你的服务是否经过 HTTP 对外公开?这很适合 K8s 的模型,你能够在服务前面使用 ingress 控制器。
你的应用程序适合进行负载均衡吗?没有本地状态 (使用 PostgreSQL/Redis/ 其余),经过已知端点通讯,能够快速启动 / 关闭。这并非说你不能在集群中保留像 Redis 缓存这样的短寿命状态,在不少状况下,你最好是使用云提供商提供的服务。
Kubernetes 也很是适用于 headless 应用程序,如批处理 (经过做业控制器) 和长时间运行的队列消费者客户端应用程序。
内存 (以及在必定程度上 CPU) 使用状况是可预测的吗?Kubernetes 会尝试在相同的物理机器上托管应用程序,所以,若是其中一台机器出现故障并消耗了全部内存,那么其余工做负载可能会被随机终止。根据个人经验,这是 Kubernetes 集群最大的不稳定性来源。若是了解应用程序的资源使用状况,就能够设置好 resources.requests 和 resources.limits,保证它们总有足够的内存,不会影响其余应用程序。
相反,对于下面这些工做负载,我认为不该该使用 Kubernetes:
静态网站。一般,你会将内容打包成基于 Nginx 的镜像,并经过集群的 ingress 控制器来公开它。这是一种糟糕的托管静态内容的方式:全部的 Nginx 副本都须要维护,效率很低。固然,你也能够把它放在 CDN 后面,但既然你要这么作,为何不托管在云服务上呢?
托管不受信任的代码。它们多是客户提供的应用程序或有安全问题的第三方代码,例如 Wordpress 或来自 NPM 不可靠的库。默认状况下,Kubernetes 提供的用于隔离工做负载的特性并非很好。你能够添加 Calico 之类的东西来控制网络访问,但这很容易出错,并且你的安全模型老是 100% 依赖于容器运行时。默认状况下 (Docker,基于 Linux cgroup),这为应用程序提供了一个巨大的***面:若是你的集群运行的代码被黑,***者就很容易访问集群的其他部分。cgroup 的替代品 (例如 Kata Container) 正在作一些有趣的工做,但它还不够主流,不能推荐给普通用户。
即便 Kubernetes 不太适用于你的工做负载,你仍然能够选择使用它 (例如,可使用卷来保存生命周期较长的状态),只是你要花费大量的时间。无论怎样,其中有不少都是很差的实践,只会进一步伤害你。
Kubernetes 并不是一颗银弹。它有助于将托管应用程序的复杂性转移到本身设计的层中,但不会让它们消失。你必须始终作好保护和维护平台的工做。
要让集群对工做负载发挥效用,须要大量的附加组件。有些几乎人人都在使用,有些则有点小众,好比 Nginx ingress 控制器、cert-manager 和 cluster-autoscaler,在没有足够的容量时可用来添加额外的节点。拥有一组有用的定制工具会让你的集群变得像一片雪花同样,因此须要对其进行管理。
此外,它们须要按期更新,有时可能会发生故障。像 Helm 或 Terraform 这样的配置管理工具几乎是不可缺乏的:手动维护集群存在较大风险,若是没有声明性设置,你将永远没法以彻底相同的方式启动另外一个集群。在维护或替换成更成熟的集群时,这样会致使无穷无尽的问题。
在 Kubernetes 上部署重要的软件栈时,老是须要进行必定程度的管理。任何人均可以为所欲为地部署你的集群,这只会致使混乱。最终,你将看到不少命名不一致的应用程序分散在几十个 (更糟糕的是一个) 名称空间中,而没有人知道它们是如何组合在一块儿的。那么恭喜你,你用“新口味的意大利面基础设施替代了旧口味的意大利面基础设施”,只是换成了更好看的盘子而已。
我见过的最成功的 Kubernetes 实现,是基础设施专家与开发人员一块儿确保工做负载配置良好、标准化、相互保护并定义了通讯模式。他们对部署在基础设施中的应用程序进行初始设置,并集成到构建 / 发布系统中,这样开发团队就能够在没有帮助的状况下发布新版本。在不少方面,这反映了组织文化——若是工程糟糕,沟通混乱,责任不明,那么托管环境也会反映出这些问题。在最好的状况下,这会致使不可靠,在最坏的状况下,这是一种不可靠、不可维护、代价高昂的混乱。
若是你正在大规模运行应用程序,那么 Kubernetes 能为你节省不少钱。能够看看一些特性,好比自动伸缩 (集群和副本集) 和 Spot 实例池 (EC2) 或抢占式 VM(谷歌)。
有一个优秀的工具生态系统能够帮助任何一个工程师搭建出一个玩具集群来测试他们的应用程序。从某种程度上说,这样很好,由于学习曲线变得不那么陡峭,但在你意识到须要多大规模以前,Kubernetes 就已经进入到生产环境中,并成为业务的关键部分。它的故障模式很复杂,要充分利用它须要不少专业技能。让一个没有经验的开发团队匆忙搭建一个集群(使用 Kops 是一种反模式)就是一场灾难:刚开始几个月或许没问题,但若是你须要作出重大变动,从新配置集群或排除故障,你的好日子就到头了。
从头构建 K8s 集群就像是本身编译内核:这是一种很好的学习方式,但对于运行生产应用程序来讲则是很糟糕的方法。相反,你应该使用已有的解决方案,如 AWS EKS 或谷歌的 GKE。比咱们还要聪明的人花了大量时间作出这些东西,即便你每月为此付出几百美圆也是值得的。
即便使用已有的 Kubernetes 解决方案,你也须要专业技能。控制平面是亚马逊提供的,但早晚你会在节点上触发一些错误,一般是在业务最繁忙的时候。你必须准备好资源,并为之支付费用。Kubernetes 的发布周期很短,因此你至少须要每一年更新一次集群,并按期修改它的 API,这是一项很重要的工做。任何一个附加组件都须要维护。若是你是一个轻量级的在线小商店,使用临时资源就能够了,但请相信我,当你全部的容器在凌晨 4 点由于一个线程错误而崩溃时,你不得不向别人求助。
全部这些都让我相信,有效利用 Kubernetes 是有一个规模大小和复杂性的阈值的。若是你运行的是少许 (好比少于 5 个) 简单的服务,那么就不值得这么麻烦了。它真正的亮点在于那些具备高度部署复杂性的环境、动态的工做负载或者经过对工具进行标准化能够大幅下降复杂性 / 成本的场景。
绝不惊喜地说,答案是“视状况而定”。
若是你只有屈指可数的几个服务,不但愿它们成倍增加,那么可能有更简单、更便宜的方式来托管它们。能够看看 AWS 的 ECS(特别是与 Fargate 一块儿使用的 ECS),把你的 API 或批处理做业重构成 Lambdas/Cloud Function,甚至可使用简单的 PaaS 提供商 (如 Heroku) 来托管你的应用程序。尽管听起来彷佛有些过期,但不要小看了这些运行在 Linux 机器上的低流量应用程序所带来的价值和健壮性。
安全性和合规需求可能会影响你的决策。若是必须在本地托管工做负载,则可能会有较大的运维开销,尽管这并不妨碍使用 Kubernetes,但传统的解决方案可能更适合你。若是你须要使用一组附加组件,但为了合规性,你不得不检查它们的每个部分,那么这样作可能不现实。
我见过不少创业公司,他们认为本身须要 Kubernetes,但实际上并不须要,结果他们投入大量资源。仔细考虑一下你是否真的须要这些,以及你是否负担得起成本。若是你的需求和可以从中获得的好处是至关的,那就去作吧。若是不是,那么能够考虑是否在未来采用 Kubernetes,并将其加入到技术决策中。在一开始就用 Docker 打包应用程序 (Docker -compose 对于开发和生产来讲都颇有价值),并仔细考虑是否须要存储本地状态。
另外一方面,评估将来的增加空间也很重要。若是你如今只有几个简单的服务,可能不须要 K8s。可是,它们是否会在将来变成几十个?若是是的话,你的团队是否应该开始学习管理这种复杂性的技能?当双翼飞机能够知足载客量的时候,你不会想要建造一架 747,可是,当 300 名乘客出如今登机口时,“骆驼”战斗机就没有多大用处了。
总而言之,基础设施决策一般与软件架构决策有关。不要让你的基础设施成为过后才去考虑的事情,不要忘了你须要的越多须要付出的成本也就越高。若是你须要的话,在复杂的系统上投入是值得的,但在投入以前要三思!