本文发布已超过一年。较旧的文章可能包含过时的内容。请确认页面中的信息自发布以来是否已不再准确。
Borg:Kubernetes 的前身
十多年来,Google 一直在生产环境中运行容器化工作负载。无论是像 Web 前端和有状态服务器这样的服务作业,还是像 Bigtable 和 Spanner 这样的基础设施系统,亦或是像 MapReduce 和 Millwheel 这样的批处理框架,Google 内部几乎所有的东西都作为容器运行。今天,我们在学术计算机系统会议 Eurosys 上公布了 Google 内部长期以来备受传闻的面向容器的集群管理系统 Borg 的详细信息。你可以在这里找到这篇论文。
Kubernetes 直接起源于 Borg。许多曾在 Borg 项目工作的 Google 开发者现在都在参与 Kubernetes 的开发。我们将 Borg 的最佳理念融入 Kubernetes,并尝试解决用户多年来在使用 Borg 时发现的一些痛点。
为了让你有所了解,以下是源自我们使用 Borg 经验的四个 Kubernetes 特性:
- Pod。Pod 是 Kubernetes 中调度的最小单元。它是一个资源包络,其中可以运行一个或多个容器。属于同一 Pod 的容器保证被调度到同一机器上,并且可以通过本地存储卷共享状态。
Borg 有一个类似的抽象,称为 alloc(“资源分配”的简称)。Borg 中 alloc 的常见用途包括运行一个生成日志的 Web 服务器,旁边运行一个轻量级日志收集进程,该进程将日志发送到集群文件系统(与 fluentd 或 logstash 类似);运行一个 Web 服务器,该服务器从磁盘目录提供数据,而该目录由一个进程填充,该进程从集群文件系统读取数据并为 Web 服务器准备/暂存数据(与内容管理系统类似);以及在一个存储分片旁边运行用户定义的处理函数。Pod 不仅支持这些用例,还提供了一种类似于在单个 VM 中运行多个进程的环境——Kubernetes 用户可以在一个 Pod 中部署多个共存的、协作的进程,而无需放弃“一个容器一个应用”部署模型的简单性。
Service。尽管 Borg 的主要作用是管理任务和机器的生命周期,但在 Borg 上运行的应用受益于许多其他集群服务,包括命名和负载均衡。Kubernetes 使用 Service 抽象支持命名和负载均衡:一个 Service 有一个名称,并映射到由标签选择器定义的动态 Pod 集合(参见下一节)。集群中的任何容器都可以使用 Service 名称连接到该 Service。在底层,Kubernetes 会自动在匹配标签选择器的 Pod 之间对连接到 Service 的请求进行负载均衡,并跟踪由于故障导致 Pod 随时间被重新调度后的位置。
标签。Borg 中的容器通常是某个 Internet 服务的一个层级(例如 Google 地图的前端)或批处理作业的工作进程(例如 MapReduce)的一组相同或几乎相同的容器集合中的一个副本。该集合称为 Job,每个副本称为 Task。尽管 Job 是一个非常有用的抽象,但它可能有局限性。例如,用户经常希望将整个服务(由许多 Job 组成)作为一个整体来管理,或者统一管理服务的几个相关实例,例如独立的金丝雀发布和稳定版发布轨道。另一方面,用户经常希望对 Job 内 Task 的子集进行推理和控制——最常见的例子是在滚动更新期间,Job 的不同子集需要不同的配置。
Kubernetes 通过使用标签(用户附加到 Pod 以及系统中的任何对象上的任意键值对)来组织 Pod,从而支持比 Borg 更灵活的集合。用户可以通过在其 Pod 上使用“job:<jobname>”标签创建等同于 Borg Job 的分组,但他们也可以使用额外的标签来标记服务名称、服务实例(生产、预发、测试),以及通常情况下 Pod 的任何子集。标签查询(称为“标签选择器”)用于选择应将操作应用于哪些 Pod 集合。总而言之,标签和Replication Controller 允许非常灵活的更新语义,并支持跨越等同于 Borg Job 的操作。
- IP-per-Pod。在 Borg 中,一台机器上的所有 Task 都使用该主机的 IP 地址,因此共享该主机的端口空间。虽然这意味着 Borg 可以使用普通网络,但它给基础设施和应用开发者带来了诸多负担:Borg 必须将端口作为资源进行调度;Task 必须预先声明它们需要多少端口,并将要使用的端口作为启动参数;Borglet(节点代理)必须强制执行端口隔离;命名和 RPC 系统也必须处理端口以及 IP 地址。
由于出现了软件定义的覆盖网络,例如 flannel 或内置于公有云中的网络,Kubernetes 能够为每个 Pod 和 Service 分配自己的 IP 地址。这消除了管理端口的基础设施复杂性,并允许开发者选择他们想要的任何端口,而无需其软件去适应基础设施选择的端口。后一点对于简化在 Kubernetes 上运行现成的开源应用至关重要——Pod 可以被视为与 VM 或物理主机非常相似,拥有完整的端口空间访问权,而无需在意它们可能与其他 Pod 共享同一台物理机器。
随着基于容器的微服务架构日益普及,Google 在内部运行此类系统所获得的经验引起了外部 DevOps 社区日益增长的兴趣。通过揭示我们的集群管理器 Borg 的部分内部工作原理,并将我们的下一代集群管理器构建为一个开源项目 (Kubernetes) 和一个公开可用的托管服务(Google Container Engine),我们希望这些经验能够惠及 Google 之外的更广泛社区,并推动容器调度和集群管理领域的最新技术发展。