在2015年,我们Lumins Technolgoies在亚马逊的EC2上面运行配置很多年之后,我所在的团队接到任务,负责为Lumins Technolgoies所有其他开发团队的配置创建一个新的配置平台。过去这么多年,AWS的设置运行得很好。但是配置设置,定制脚本,和自动配置的工具这些东西,对于操作团队以外的工程师来说十分难用——特别是对没有资源来学习所有关于这些脚本和工具的团队来讲。主要的问题就是没有配置单元,因为没有,所以在开发和操作之间有一个鸿沟。显然,容器化趋势将会改变这个状况。
如果你还没有了解Docker和Kubernetes能够带给产品什么,那么来读一读我们团队是如何成为早期使用者的。我们目前已经在生产过程中使用Kubernetes超过一年了。
从容器和容器编排工具开始
现在我相信容器是未来的配置编排格式。他们使得用需要的基础设施来打包应用程序变得更加容易。虽然像Docker这样的工具提供真实的容器,但是我们也需要工具来处理例如像replication,failover以及API来自动化部署到多个机器。
在2015年初的时候,像Kubernetes和Docker Swarm这样的集群工具还不成熟,只有一个早期的alpha版本。我们仍然尝试使用它们,最开始的时候使用的是Docker Swarm。
首先,我们使用Swarm来处理我们自己的网络连接,以及ambassador模式和一堆自动化部署的脚本。这些有多难呢?这就是我们面临的第一个难题:容器集群、网络连接、自动化部署,这些都是要解决的非常大的难题。
我们很快意识到了这些难点,并且决定押注在当时另一个可用的工具上面:Kubernetes似乎才是最好的选择,因为它有谷歌,Red Hat,CoreOS,以及其它一些了解运行大规模部署的公司团队作为支持。
用Kubernetes来进行负载均衡
当操作Kubernetes的时候,你就必须要对这些概念很熟悉,比如:pods,services和replication controllers。如果你对这些概念还不熟悉,这里有一些优秀的资源可以快速了解。Kubernetes文档是一个很好的起点,它对新手很有指导意义。
一旦有了Kubernetes集群,并且运行起来,我们就可以使用kubectl(Kubernetes CLI)来部署一个应用程序,但是我们很快就发现当我们想要自动化部署的时候,kubectl还不够。但在这之前,我们还有另一个问题要先解决:如何从网络上访问已经部署好的应用程序?
Service在部署之前是一个IP地址,但是这个地址只存在于Kubernetes集群之内。这也就意味着service对于网络来说根本不可用!当运行在谷歌GCE上的时候(像我们一样),Kubernetes能够自动配置一个负载均衡器来访问应用程序。如果你不是在谷歌GCE上面的话,你就需要做些额外的工作来使负载均衡运行起来。
将service直接暴露到一个主机端口也可以,这就是很多人开始的方式,但是我们发现这会令很多Kubernetes的好处都无效。如果我们依赖我们主机上的端口,那么当部署多个应用程序的时候,我们就会陷入端口冲突。这也使得调度集群或者替代主机变得更加困难。
两步完成负载均衡设置
我们发现了一个更好的解决方法,那就是在Kubernetes集群前部署一个像HAProxy或者NGINX的负载均衡器。我们在AWS上的VPN里面开启运行我们的Kubernetes集群,并且使用AWS弹性负载均衡器来路由外部网络流量到一个内部HAProxy集群上。HAProxy由“后端”配置,这个“后端”是为每个Kubernetes service服务的,为pods代理流量。
简单两步完成负载均衡器主要回答了AWS弹性负载均衡器相当有限的配置选项。限制之一就是,它无法处理多个虚拟主机。这也就是我们也使用HAProxy 的原因。只使用HAProxy(没有弹性负载均衡器)也可以运行,但是你不得不在DNS水平上处理动态AWS IP。
在任意情况下,当创建新的Kubernetes services的时候,我们需要一个机制来动态地重新部署负载均衡器(HAProxy,在我们这个情况下)。
Kubernetes社区目前运行在一个叫做ingress的功能上。它将使得直接从Kubernetes上部署一个外部负载均衡器成为可能。目前,这个功能还不是很有用,因为它还没有完成。去年,我们使用API和一个小的开源工具来配置负载均衡器来替代。
配置负载均衡器
首先,我们需要一个地方来存储负载均衡器配置。它们可以被存储在任意地方,但是由于我们已经有了etcd,所以我们决定将负载均衡器配置存储在别的地方。我们用一个叫做confd的工具来检测配置在etcd内的修改,并且基于一个模版生成一个新的HAProxy配置文件。当一个新的服务添加到Kubernetes的时候,我们添加一个新的配置到etcd,这也就为HAProxy生成了一个新的配置。
Kubernetes:正确的方法慢慢成熟
虽然Kubernetes还存在很多没有解决的问题,如同在负载均衡中的一样。很多这样的问题被社区组织起来,也有很多设计文档在讨论针对这些问题的新功能。但是为每个具体需求找出标准化解决办法是需要时间的,新功能发布会需要时间。这是一件好事,新功能的设计到最终标准化功能的发布,并没有捷径可走。
这也并不意味着Kubernetes现在就是被限制的。如果你想今天就开始使用它的话,使用API就有能让Kubernetes做很多你想要它去做的事。一旦Kubernetes添加了更多功能,我们就可以用标准版本来定制解决方案。
在我们为负载均衡开发我们的定制解决方案的时候,我们面临的下一个挑战就是为我们实施一个必要的部署技术:蓝绿(Blue-green)部署。
Kubernetes中的Blue-green部署
Blue-green部署不会有宕机时间。相比于滚动更新,blue-green部署通过开启运行新版本的副本集群来工作,同时所有的旧副本仍然会服务实时请求。只有当新的副本集合完全上线并运行时,负载均衡器配置才会修改来转换负载到新的版本。这个解决方案的好处就是,总会有应用程序的版本在运行的,同时减少处理多个并发版本的复杂性。当副本的数量相对较小的时候,Blue-green部署同时也会运行得比原先好。
上图展示的是组件“Deployer”在编排部署。这个组件可以轻松地由你自己的团队来创建,因为我们将我们自己的实施开源在Apache License下面,Apache License作为Amdatu大型项目的一部分。它同时也伴随着一个用来配置部署的网页UI。
这种机制的一个重要层面就是健康检查,在重新配置负载均衡器之前它是在pods上面运行的。我们想要将每个配置好的组件来提供健康检查。现在我们通常在每个应用程序组件上添加在HTTP上面可用的健康检查。
部署自动化
Deployer放好位置,我们就能够安装部署来构建管道。我们创建的服务器,在创建成果之后,可以push一个新的Docker镜像到例如像DockerHub一样的代码库。然后创建的服务器就可以调用Deployer自动化部署的新版本到测试环境。同样的镜像可以触发在生产环境中被运用到生产过程中。
了解你的资源限制
当我们开始使用Kubernetes的时候,了解我们的资源限制十分关键。你可以在每个pod中配置资源请求和CPU/内存限制。你也可以控制资源保障和爆发限制。
这些设置对于同时有效运行多个容器来说十分重要。如果我们没有正确地设置这些,那么容器可能会因为无法分配足够的内存而崩溃。
早点把资源限制的设置和测试做起来。如果没有限制,所有一切也该是运行得很好,但是当你有一个大负载在容器中跑的时候,你会得到一个“大”surprise!
如何监控Kubernetes
我们把Kubernetes设置得差不多的时候,我们很快意识到监控和登录在这个新动态环境中是很重要的。当你处理大量副本和节点时,登录到服务器来查看日志文件已经不work了。一旦你开始使用Kubernetes,你就应该有创建集中日志和监控的计划。
日志记录
对于日志记录来说,有很多开源工具可以用。我们决定使用Graylog——一个优秀的日志记录工具——以及Apache Kafka(一个信息系统)来收集和消化容器的日志。容器发送日志给Kafka,然后Kafka将他们交给Graylog来进行索引。我们选择应用程序组件来发送日志给kafka,这样的话,我们就可以用容易索引的格式来对日志进行分流。然而,有很多工具可以从容器外面检索日志,并且转发他们到一个日志记录解决方案。
监控
当有错误的时候,Kubernetes做了出色的恢复。当pods由于一些原因崩溃的时候,Kubernetes就会重启它们。当Kubernetes重启运行的时候,终端用户可能根本不会注意到这个问题。Kubernetes很好地恢复工作,以至于出现过这样的情况,就是我们的容器由于内存泄漏一天内多次崩溃的场景,这个情况却没有任何人注意到(包括我们自己)。
虽然从Kubernetes角度来说这很棒,你可能仍然想要随时了解什么时候出了问题。我们使用定制健康检查dashboard,可以用来监控Kubernetes节点,单个pod——使用特定应用程序健康检查——以及其它诸如像数据存储的服务。为了做这样一个dashboard界面,Kubernetes API再次被证明了它很有价值。
我们也知道测量负载、吞吐量、应用程序错误和其他一些数据是十分重要的。再次证明,开源空间有很多可以提供的。我们的应用程序组件将参数发送到InfluxDB时间序列存储。我们也使用Heapster来收集Kubernetes参数。存储在InfluxDB中的参数可以在Grafana上查看,Grafana是一个开源仪表盘工具。除了InfluxDB/Grafana栈,还有很多其他方案,这些方案中的任意一个对于如何跟踪运行都能够提供很多价值。
数据存储和Kubernetes
很多Kubernetes用户要问的一个问题就是“我要如何用Kubernetes来处理我的数据存储?”
当运行像MongoDB或者MySQL的数据存储的时候,你很可能希望数据是持久性的。当容器重启的时候,会失去他们的数据。这对于无状态组件来说没什么关系,但是对于持久数据存储来说就有关系了。Kubernetes有“数据卷”这个概念来处理持久性数据。
数据卷可以通过各种方式来实现,包括在主机上的文件,AWS弹性块存储(EBS)和nfs。当我们研究持久性数据的问题的时候,这些提供了较好的答案,但这并不是我们现在运行的数据存储的答案。
复制问题
在大多数配置里面,数据存储也会有副本运行。Mongo通常在副本集合中运行,MySQL可以在“主要/复制”模式下运行。这个会引入一些问题。首先,数据存储节点中的每个节点都通过不同的数据卷来备份,这点很重要。写到相同的数据卷上会导致数据损坏。另一个问题就是大多数数据存储需要精确的配置来调动集群并使之运行;自动发现和配置节点都是不常见的。
同时,运行在数据存储上的机器通常为那种类型的工作负载调优。更高的IOPS就是一个例子。扩容,包括添加/删除节点,对于大多数数据存储来说是一个昂贵的操作。
决定在生产过程中不使用Kubernetes来运行数据存储
我们发现在Kubernetes中运行一个数据存储的好处是有限的。设置也比大多数Kubernetes配置要复杂得多。
由于这个,我们没有在Kubernetes中运行我们的产品数据存储。相反,我们在不同主机上手动设置这些集群,同时做所有必要的调整来优化数据存储的问题。我们的应用程序运行在Kubernetes内,正常连接到数据存储集群。重要的经验是,有了Kubernetes,你就不需要在Kubernetes上运行所有的东西。除
了数据存储和我们的HAProxy服务器,所有其它的东西也都运行在Kubernetes中,同时,也包括我们的监测和日志记录解决方案。
明年继续使用Kubernetes,我们充满期待
看一下我们现在的配置,Kubernetes绝对是极好的!当涉及到自动化部署流水线的时候,Kubernetes API是一个很棒的工具。配置不仅更加可靠,而且更快,因为我们不再通过使用虚拟机来处理。我们创建和配置都变得更加可靠,因为测试和打包容器变的更加容易了。
我们现在可以看到这个配置的新方法是多么的有必要跟其他的配置团队保持同步且降低开销,并且对于在行业内其他开发团队经常部署来说是有必要来进行同步和推广的。
成本核算
成本,这个事情可以从两个方面来看。为了运行Kubernetes,就需要etcd集群,同样也需要master节点。虽然这些不是必要的要运行的昂贵组件,这个开销涉及到非常小的配置的时候相对来说就比较贵。对于这些配置类型来说,使用主机解决方案是最好的方法,比如谷歌的容器服务。
对于较大的配置来说,在服务器上节省成本就十分容易了。运行etcd和master节点的开销在这些配置中并没有效果。Kubernetes使得在同一个主机上运行很多个容器非常轻松容易,也最大化地利用可得资源。这就减少了需要的服务器数量,也直接节省了你的成本。运行Kubernetes的确不错,但对于运维来说有相当工作量,因为有很多主机服务要查看,包括Cloud RTI,这也是我们团队正在做的。
Kubernetes的光明未来
在pre-released的版本中运行Kubernetes过程是充满挑战的,Kubernetes在过去一年里的光速发展,这个社区已经成长为一个开发人才的权威团体,在短短一年内有这样的进展让人难以置信。
(如果需要转载,请联系我们哦,尊重知识产权人人有责:)