Skytap 是全球性公有云提供商,为客户提供保存、克隆复杂环境的性能服务。我们的客户包括在混合云上运行应用的企业,教育机构虚拟培训实验室之类,用户只需要便于管理的开发测试实验室,以及拥有各种各样的开发运维工作的机构。
我们之前以较快的速度拓展我们的业务——我们的用户基础和我们工程机构也在持续增长。令人兴奋!然而,要做到顺利地缩放应用和机构也是十分困难的,我们目前正在朝这个目标努力。当我们第一次开始关注工具设置的时候,发现传统的 OS 虚拟化并不是完成缩放目标的有效方法。我们发现虚拟机的持久性能鼓励工程师创建、维持定制的“pet”虚拟机;这跟我们愿望没太大关系,我们的愿望是用稳定的、可预测的状态来创建可以重复使用运行时间的环境。Docker 和 Kubernetes 社区的增长跟我们的增长密切挂钩,而且目前社区内的爆炸式增长也帮助这些工具走向成熟。
在这篇文章中,我们会探索 Skytap 如何将 Kubernetes 作为服务中的关键组件在 Skytap 云上处理工作。
为了继续维持这种敏捷的速度,继续通过软件开发生命周期来启用组件所有权,我们又新增了工程师成员。这就要求我们程序的关键层面高度模块化,高度一致。以前,我们通过虚拟机和环境模版重新进行系统级别打包,但是随着规模的弹性伸缩,作为打包机制的容器变得越来越重要了,因为它相对轻便、运行环境控制精准。
除了打包灵活这个优点,容器还提高了资源利用率,团队将资源混合入更大、更高性能的虚拟机时,也变得更加复杂;而容器则帮助阻止这种复杂性上升。比如,我们的操作团队为了监控健康和资源利用率安装相应工具,开发团队部署服务,安全团队则安装流量监控;将所有这些都结合到一台单个的虚拟机上,很大程度上就增加了测试负担,而且还会经常造成恐慌。
服务中,用 Docker 将单个组件容器化是相当琐碎的。开始很容易,但是任何创建过分布式系统的人都知道,真正的困难在于部署、弹性扩容、可用性和持久性,以及集群中每个单元之间的交流。
进行容器打包
我们要将 pet 虚拟机换成 cattle。
分布式系统的挑战在于,它不是简单地创建一些容器就可以了的。我们将 Docker Swarm,Mesosphere 和 Kubernetes 进行对比,发现 Mesosphere 用法模型跟我们的需求不匹配,因为我们需要的是管理虚拟机的能力,跟 Mesosphere“分布式操作系统”模型不匹配;Docker Swarm 现在则不是那么成熟。所以,我们最终选择了 Kubernetes。
发布 Kubernetes,创建新的分布式服务相对来说会容易一点。但是,我们需要将容器管理和我们已经存在的平台、基础设施整合到一起。平台的一些组件最好由虚拟机提供,我们需要的就是将这些服务进行迭代更新。
我们将整合问题进行了整理分类,如下所示:
1、服务控制和部署
2、内部 service 交流
3、基础设施整合
4、工程支持和教育
服务控制和部署
我们使用 Capistrano(我们称之为“Skycap”)的定制拓展版本来部署服务,管理执行运行的服务。通过单个的、构建良好的框架来管理容器化、传统的 service。我们同时也需要让 Skycap 摆脱不可避免的内在缺点,这些缺点来自于类似于 Kubernetes 这样的开发工具。
为了处理这个,我们引入封装器到服务中,来帮助控制用于在 Skycap 后隔离 kubectl 的框架,并且处理伪造日志信息被忽略的问题。
Deployment 为我们添加了一层复杂性。打包软件用 Docker 镜像最好,但是有个历史遗留问题,就是我们已经从资源那里部署了,而不是从打包的时候部署。我们的工程团队希望对资源作出有效修改,发布他们的工作;开发人员不希望再有额外的打包步骤了。由于容器化的原因,除了重新创建我们整个的部署和编排框架,还需要为容器化服务使用持续集成管道。我们为每个提交都自动创建了新的 Docker 镜像,然后我们用 Mercurial(Hg)来给提交内容打标签。从 Skycap 角度来说,特定 Hg 版本的部署会拉取 Docker 镜像,这些镜像会被打上一样的版本号。
我们在多个环境上重新使用容器镜像。这就要求特定的环境配置被添加到每个容器实例。直到最近,我们本着类似于基于资源的准则注入这些配置值:每个容器都会从 Hg 通过 cURL-ing raw 文件拷贝相关的配置文件,这些文件来源于运行的 repo。网络可用性和变量能避免就避免,所以我们现在把配置加入到 Kubernetes 的 ConfigMap 功能中。这不仅仅简化了我们的 Docker 镜像,还让 pod 启动速度更快、更可预测(因为容器不再需要从 Hg 下载文件了)。
内部 service 交流
service 交流主要有两种方法。第一种,消息代理——通常用于 Skytap 平台,进程与进程之间的通信。第二种则是直接通过点对点 TCP 连接——通常用于 service 跟外部(比如网页 service)的交流。下一节我们会具体说一下这个 TCP 方法,它其实是整合基础设施的一个组件。
用 service 能够理解的方法来直接管理 pod 之间的连接是比较复杂的。再者,容器化的 service 需要跟典型的基于虚拟机的 service 进行交流。为了降低复杂性,我们主要使用已经存在的消息队列系统。它可以帮助我们在处理 pod 和非 Kubernetes service 之间的流量的时候,避免使用基于 TCP 的 service 发现和负载均衡系统。
这就减少了我们的配置负载——service 只需要了解如何跟信息队列交流就可以了,而不需要跟每一个有联系的 service 都进行联系。对于管理 pod 的运行状态;当节点重启,信息在队列中进行缓冲的时候,我们也有额外灵活性。每次 pod 被添加或者从集群中被移除的时候,我们避免重置 TCP 端点。还有,有了 MQ 模型,我们就可以用 “pull”的方法来管理负载均衡,这种方法更加精准,由接受者决定他们什么时候准备好可以处理一个新消息,而不是用试探的方法(比如最少连接)来简单地利用 open socket 的数量来对负载进行估计。
转移使用复杂的基于 TCP 方法的 service(或者是使用负载均衡连接的 service),还不如转移启用 MQ service 到 Kubernetes 来得简单。还有,由消息代理中间件提供的隔离意味着,从经典的 service 到基于容器的 service 的转换本质上对于其它启用 MQ 的 service 来说是很简单的。
基础设施整合
作为基础设施提供商,我们在配置 Kubernetes 使用我们的平台的时候,面对一些特殊的挑战。AWS 和 GCP 提供即时可用的解决方案,可以简化 Kubernetes 规划,但是关于底层基础设施的假设跟我们的现实不匹配。一些组织者为了特殊的目的还创建了数据中心。这个选项就要求我们禁止已经存在的负载均衡基础设施,除了工具,我们还创建了基于 Puppet 规定的系统,邀请了一些专家。我们无意禁用工具,也无意使用我们以往的经验,我们需要找到一种管理 Kubernetes 的方法,能够跟我们所处的环境相整合的方法,而不是重建。
所以,我们使用 Puppet 来供应、配置虚拟机来运行 Skytap 平台。我们使用定制部署脚本在这些平台上安装 Kubernetes,我们跟操作团队合作,为 Kube-master 和 Kube-node 宿主机做容量规划。
在之前的章节,我们提到,点对点基于 TCP 的交流。对于用户面对的 service,pod 需要一种方法跟 Skytap 的第 3 层网络基础设施进行交互。在 Skytap 的例子包括我们的网页应用,通过 HTTPS 的 API,通过网页 Socket 的远程桌面,FTP,TCP/UDP 端口转接 service,完全公开的 IPs 等等。我们需要小心管理的是外部流量的网络出入口,基本上用的是 F5 负载均衡器。
用内部 service 的 MQ 基础设施来处理这个工作其实不太合适,因为不同客户端使用的协议都比较定制化,而 TCP 则是最低版本的协议。
为了使我们的负载均衡器跟 Kubernetes 的 Pod 进行交流,我们会在每个节点上运行 kube-proxy。负载均衡器路由到节点上,kube-proxy 会切换到合适的 pod。
要记住的一点就是,Kubernetes 需要在 pod 之间路由流量。Calico 插件用于 Kubernetes 网络,当 Kubernetes 发布,或者产生 pod 的时候,我们可以用特定的 service 来重新部署 F5。Calico 使用 BGP 来处理路由公告,这就简化了跟 F5 的整合。
当 pod 加入集群,或者从集群中被移除的时候,F5 自己的 load balancing pool 需要重新配置。F5 设备会保留负载均衡的后端;容器化 service 的入口是直接通过这个 pool 来传输到 service pod 所在的节点的。这对于静态网络配置来说是最直截了当的方法——但是既然我们使用 Kubernetes 来管理 pod replication 和可用性,那么我们的网络状态就变成动态的了。要处理这些修改,我们有一个“负载均衡器”pod,它可以监视 Kubernetes svc 对象的变化;如果 pod 被移除或者添加,“负载均衡器”pod 会通过 svc 对象检测到这个修改,然后通过设备的网页 API 更新 F5 配置。这样的话,Kubernetes 会处理 replication 和 failover/recovery,而动态的负载均衡器配置则会让这个进程对 service(或者用户发起请求)设置不可见。同样的,Calico 虚拟网络和 F5 负载均衡器的结合意味着,TCP 连接应该连贯地运行在传统的 VM 基础设施上,或者是转移到容器上。
有了网络的动态配置,Kubernetes 的 replication 结构使得水平式扩充以及 failover/recovery 非常直截了当。我们还没有完成相应缩放的 milestone,但是我们已经在 Kubernetes 和 Calico 的基础设施上奠定了基础,找出一种可以直接实现的方法。
为 service replication 配置上下层
创建负载分析层和缩放 service(这个还是很容易的)
如果负载模式跟缩放 service 内配置好的 triggers 相匹配(比如,特定边界上的请求速率或者数据卷),issue:kubectl scale——replicas=COUNT rc NAME
这就允许我们在平台层面对自动缩放进行细粒度控制,而不是从应用自身——但是我们也会评估 Kubernetes 中的水平 pod 自动缩放;这就会跟我们的需要相匹配而不需要定制服务。
欢迎关注我们的 Github 账户以及 Skytap 博客;面对技术成熟等问题,我们希望跟大家分享我们在社区中所做的。
工程支持
例如像容器化这样的过渡项目需要工程师,还涉及到管理以及贡献到平台,修改他们的工作,为创建 service 以及排除故障 service 学习新的方法。
因为很多学习模式需要多方面的方法,我们的处理方法有三种:1、用文档,2、直接向外拓展联系到工程师(也就是,通过 brownbag 会议或者指导团队),3、通过提供容易访问的专门支持。
我们也会继续辅助收集提供指导性的文档,从传统的 service 过渡到 Kubernetes,这些文档会提供指导,创建新的 service,操作容器化服务。
文档也不是对每个人都适用的,有时候它会丢失或者不完整(尽管我们已经尽力去完善了),所以我们也需要有一个进行内部 Kube 求助的 Slack 频道,可以进行线上求助,或者进行有深度的在线面对面讨论。
我们还有一个很强大的工具支持:我们自动创建、测试类似于 prod 的环境,包括 Kubernetes 基础设施,这就允许工程师在很大程度上可以自由地进行 Kubernetes 试验。在这篇帖子中,我们更加细节地探索了自动环境交付。
结语
总体上来说,我们在 Kubernetes 和容器化服务上获得了极大的成功,但是我们也发现要跟已经存在的全栈环境进行整合还面临很大的挑战。从企业生命周期立场来看,不存在即插即用的 Kubernetes 平台,但它的灵活性和可配置性对于创建模块化 service 生态系统来说,是十分强的工具。
我们喜欢将应用程序现代化的这个挑战。Skytap 平台非常适合这类迁移工作——我们在 Skytap 适用 Skytap,当然,它在 Kubernetes 整合项目中也起了很大的作用。如果你打算自己尝试将它现代化,请联系我们,我们很乐意提供帮助!
本文转载自才云 Caicloud 公众号。
原文链接:https://mp.weixin.qq.com/s/e7BKOW6x-cYHCim5KQEKKg
评论