这篇文章已超过一年。较旧的文章可能包含过时内容。请检查页面信息自发布以来是否已失效。

ShareThis:在生产环境中使用 Kubernetes

ShareThis 自其最初作为一个小型部件,允许你分享到喜爱的社交服务以来,已经取得了巨大发展。现在它每月服务超过 450 万个域名,帮助发布商创造更真实的数字体验。

快速增长伴随着代价。我们利用技术债务来快速扩展并发展产品,尤其是在基础设施方面。随着公司扩张,基础设施成本也随之上升——既有低效利用的问题,也有人力成本的问题。大约一年前,很明显需要做出改变。

TL;DR(太长不看):Kubernetes 一直是我们减少基础设施技术债务的关键组成部分,通过以下方式:

  • 促进 Docker 的采用
  • 简化容器管理
  • 引导开发者熟悉基础设施
  • 解锁持续集成和交付 我们通过彻底采用 Kubernetes 并将我们的 DevOps 团队转变为一个以容器和微服务为基础工作的云平台团队来实现这一点。这包括创建了一些工具来解决我们自身的遗留技术债务。

问题

唉,那时云是新鲜事物,我们也还年轻。我们以传统的机房思维起步。 我们管理着所有的服务:MySQL、Cassandra、Aerospike、Memcache,你能想到的都有。 我们像设置传统服务器一样设置虚拟机,在其上安装应用,并在 Nagios 或 Ganglia 中进行管理。

不幸的是,这种思维方式与以云为中心的方法背道而驰。我们思考的是服务器,而不是服务。我们思考的是脚本化设置、服务器部署和避免供应商锁定,而不是使用自动扩缩容、微服务或甚至托管虚拟机等现代云方法。

这些思维方式本身并非不好,只是效率低下。它们没有利用云正在发生的快速变化。这也意味着当需要进行更改时,我们将其视为对数据中心的重大缓慢更改,而不是对云的小而快速的更改。

解决方案

Kubernetes 作为促进 Docker 采用的工具

随着 Docker 在我们行业中变得越来越有影响力,ShareThis 的工程师们也开始进行试验,并取得了良好效果。很快我们就意识到,我们需要为公司中的每个应用提供一个可工作的容器,这样我们就可以简化开发环境中的测试。

有些应用因为简单、依赖少而迅速迁移到 Docker。 对于那些依赖较少的应用,我们能够使用 Fig(Fig 是 Docker Compose 的原名)进行管理。然而,我们的许多数据管道或相互依赖的应用过于复杂,无法直接 Docker 化。我们仍然想这样做,但仅仅依靠 Docker 是不够的。

在 2015 年底,我们对遗留基础设施的沮丧达到了顶峰,最终痛下决心。我们评估了 Docker 工具、ECS、Kubernetes 和 Mesosphere。很快显而易见的是,对于我们的基础设施而言,Kubernetes 比其竞争对手更稳定、更用户友好。作为一家公司,我们可以通过简单地设定将所有基础设施都部署在 Kubernetes 上的目标来巩固我们在 Docker 上的基础。

工程师们起初持怀疑态度。然而,一旦他们看到应用可以轻松地扩展到每个应用数百个实例时,他们就着迷了。现在,不仅有推动我们迈向 Docker 以及随后的 Kubernetes 的痛点,还有对这项技术产生的真正兴趣吸引着我们。这使得我们能够相当快速地完成一次极其困难的迁移。我们现在在多个区域运行 Kubernetes,部署在大约 65 个大型虚拟机上,并计划在未来几个月内增加到 100 多个。我们的 Kubernetes 集群目前每天处理 8 亿个请求,并计划在未来几个月内处理超过 20 亿个请求。

Kubernetes 作为容器管理工具

我们最初使用 Docker 在开发方面很有前景,但在生产方面则不然。最大的障碍在于无法大规模管理 Docker 组件。知道哪些容器在哪里运行、部署的版本是什么、应用处于什么状态、如何管理子网和 VPC 等等问题,困扰着其在生产环境中部署的任何可能性。所需的工具将是庞大的。

当你审视 Kubernetes 时,有一些关键特性立即吸引了我们

  • 它很容易安装在 AWS 上(我们的所有应用都在 AWS 上运行)
  • 可以通过一个 yaml/json 文件直接从 Dockerfile 创建一个 Replication Controller
  • Pod 的数量可以轻松扩展
  • 我们可以轻松扩展在 Kubernetes 集群中运行的 AWS 虚拟机数量
  • 滚动部署和回滚功能内置于工具中
  • 每个 Pod 都通过健康检查进行监控
  • Service 端点由工具管理
  • 拥有一个活跃且充满活力的社区

不幸的是,最大的痛点之一在于这些工具并不能解决我们现有的遗留基础设施问题,它只是提供了一个可以迁移到的新基础设施。仍然存在各种网络怪癖,阻止我们直接将应用迁移到新的 VPC。 此外,重构如此多的应用需要开发者去解决那些传统上由系统管理员和运维团队解决的问题。

Kubernetes 作为引导开发者熟悉基础设施的工具

当我们决定从本质上是 Chef 运行的设置切换到 Kubernetes 时,我认为我们并没有完全理解会遇到的所有痛点。 我们在各种不同的网络配置中以多种方式运行我们的服务器,这些配置与你在全新的 Kubernetes VPC 上看到的干净设置截然不同。 

在生产环境中,我们在多个区域同时使用 AWS VPC 和 AWS 经典网络。这意味着我们管理着多个子网,不同应用具有不同的访问控制。我们最新的应用也非常安全,没有公共端点。这意味着我们运行着各种配置的 VPC 对等连接、网络地址转换 (NAT) 和代理组合。

在 Kubernetes 世界中,只有 VPC。 理论上,所有 Pod 都可以相互通信,并且服务端口是明确定义的。开发者很容易忽略一些细节,而且(很大程度上)消除了运维的必要。 

我们决定将所有基础设施/DevOps 开发者转变为应用开发者(真的!)。反正我们招聘他们时已经基于他们的开发技能而非运维技能了,所以这听起来可能没有那么惊人。

然后我们决定将整个工程组织引入运维。开发者灵活,喜欢挑战,喜欢学习。这真是了不起。 仅仅 1 个月后,我们的组织就从只有少数 DevOps 人员,转变为每个工程师都能够修改我们的架构。

将 Kubernetes 大规模投入生产,成为了网络、生产化、问题解决、根本原因分析等方面的实践训练场。第一个月后,我紧张得咬指甲,担心我们的选择。两个月后,看起来或许有朝一日可行。三个月后,我们每周部署 10 次。四个月后,每周 40 个应用。虽然只有 30% 的应用完成迁移,但收获不仅显著,更是惊人。Kubernetes 使我们从一个“基础设施拖慢了我们,烦死了!”的组织,转变为一个“基础设施加速了我们,太棒了!”的组织。

Kubernetes 作为解锁持续集成和交付的手段

我们是如何做到每周 40 多次部署的?简单来说,持续集成和部署 (CI/CD) 是我们迁移的副产品。我们在 Kubernetes 中的第一个应用是 Jenkins,随后迁移进去的每个应用也都添加到了 Jenkins。随着我们向前推进,我们让 Jenkins 变得更加自动化,直到 Pod 在 Kubernetes 中创建和删除的速度超出了我们的跟踪能力。 

有趣的是,我们现在关于扩展的问题变成了希望一次性推送太多更改,导致人们不得不排队等待。我们的目标是通过新基础设施实现每周 100 次部署。如果我们能在迁移上持续执行,并在 Kubernetes 和 Jenkins 上坚持 CI/CD 流程,这是可以实现的。

下一步

我们需要完成迁移。目前大部分问题都已解决,最大的困难在于当前任务的繁琐性。将事物从遗留基础设施中移出意味着需要更改网络配置,以便允许从 Kubernetes VPC 访问以及跨区域访问。这仍然是一个非常真实的痛点,我们仍在持续解决。 

有些服务在 Kubernetes 中运行得不太好——比如有状态的分布式数据库。幸运的是,我们通常可以将这些服务迁移给第三方托管。在本次迁移结束时,我们将只在 Kubernetes 上运行 Pod。我们的基础设施将变得简单得多。

所有这些改变并非没有代价;将我们整个基础设施承诺给 Kubernetes 意味着我们需要拥有 Kubernetes 专家。 我们的团队在基础设施方面已不再受阻,他们正忙于通过应用开发增加业务价值(这是他们应该做的)。然而,我们还没有(或者说暂时还没有)专门的工程师来跟踪 Kubernetes 和云计算的变化。 

因此,我们已经将一名工程师调到新的“云平台团队”,并将招聘其他几名工程师(我有没有提到我们正在招聘!)。他们将负责开发与 Kubernetes 良好交互并管理所有云资源的工具。此外,他们还将在 Kubernetes 源代码中工作,参与 Kubernetes SIGs,理想情况下,还会向开源项目贡献代码。

总结

总而言之,虽然迁移到 Kubernetes 最初看起来令人望而生畏,但它远没有我们想象的那么复杂和具有破坏性。最终的收获是公司能够以客户期望的速度做出响应。编者注:在最近的一次 Kubernetes 见面会上,ShareThis 团队分享了他们在生产环境中使用 Kubernetes 的经验。视频嵌入在下方。