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

rktnetes 将 rkt 容器引擎带到 Kubernetes

编者注:本文是关于 Kubernetes 1.3 新特性系列深度文章的一部分。

作为Kubernetes 1.3 的一部分,我们很高兴地报告,我们将可互换的容器引擎引入 Kubernetes 的工作已初见成效。我们亲切地称之为“rktnetes”的项目已包含在 Kubernetes 1.3 版本发布中,并已可用于开发。rktnetes 将对 CoreOS rkt 的支持集成到 Kubernetes 中,作为集群节点上的容器运行时,并且现已成为 Kubernetes 主线源代码的一部分。对于那些考虑容器可移植性的开发人员和运维专业人员来说,今天尝试使用不同的容器引擎运行 Kubernetes 比以往任何时候都更容易。

“我们发现 CoreOS 的 rkt 是 Kubernetes 中一个引人注目的容器引擎,因为它与底层 systemd 集成的方式,”PayPal 服务 Xoom 的高级 MTS 和架构师 Mark Petrovic 说。“rkt 运行时只承担其所需的职责,然后在适当时将其他任务委托给其他系统服务。这种关注点分离对我们来说很重要。”

rktnetes 是什么?

rktnetes 是用于代码的昵称,这些代码使 Kubernetes 节点能够使用 rkt 容器引擎而不是 Docker 来执行应用程序容器。这一更改为 Kubernetes 添加了新功能,例如在灵活的隔离级别下运行容器。rkt 探索了一种不同的容器运行时架构方法,旨在反映 Unix “清晰分离、模块化工具” 的哲学。为支持 rktnetes 所做的工作也为 Kubernetes 的未来开辟了新的可能性,例如支持多种容器镜像格式,以及集成针对特定用例或平台定制的其他容器运行时。

为什么 Kubernetes 需要 rktnetes?

rktnetes 不仅仅是关于 rkt。它还关乎改进和实践 Kubernetes 接口,并为未来其他模块化运行时铺平道路。虽然 Docker 容器引擎众所周知,并且目前是 Kubernetes 的默认容器运行时,但可插拔容器环境带来了许多优势。例如,某些集群可能需要非常特定的容器引擎实现,确保 Kubernetes 设计足够灵活以支持备选运行时(从 rkt 开始)有助于保持组件之间的接口清晰简单。

关注点分离:分解单体容器守护进程

Kubernetes 当前使用的容器运行时施加了许多设计决策。在这个快速发展的领域,尝试其他容器执行架构是值得的。如今,当 Kubernetes 发送请求给节点启动一个 Pod 时,它通过每个节点上的 kubelet 与默认容器运行时的中心守护进程通信,该守护进程负责管理节点上的所有容器。

rkt 不实现单体容器管理守护进程。(值得注意的是,默认容器运行时正在重构其原始的单体架构。)rkt 的设计从第一天起就尝试充分应用模块化原则,包括重用经过充分测试的系统组件,而不是重新实现它们。

在 rkt 中,构建容器镜像的任务与容器运行时核心抽象分离,并由独立的实用工具实现。同样的方法也适用于持续的容器生命周期管理。一个单一的二进制文件 rkt 配置环境并准备容器镜像以供执行,然后启动容器应用程序及其隔离环境。此时,rkt 程序完成了它的“一项工作”,容器隔离器接管。

用于查询容器引擎和 Pod 状态的 API(Kubernetes 用它来跟踪每个节点上的集群工作)在一个独立的服务中实现,将协调和编排功能与核心容器运行时隔离。虽然 API 服务并未完全实现当前默认容器引擎的所有 API 功能,但它已经有助于将容器与核心运行时的故障和升级隔离开来,并提供了预期的 API 的只读部分,用于查询容器元数据。

模块化容器隔离级别

通过 rkt 管理容器执行,Kubernetes 可以利用 CoreOS 容器引擎的模块化 stage1 隔离机制。典型的容器在 rkt 下运行在一个软件隔离的环境中,该环境由 Linux 内核命名空间 (namespaces)、cgroup 和其他设施构建。尽管以这种常见方式隔离,容器仍然与系统上的所有其他容器共享同一个内核,从而实现了运行中应用的轻量级隔离。

然而,rkt 具有可插拔的隔离环境(称为 stage1),可以改变容器的执行和隔离方式。例如,rkt fly stage1 在主机命名空间(PID、挂载点、网络等)中运行容器,赋予容器在主机系统上更大的权限。Fly 用于容器化较低级别的系统和网络软件,例如 kubelet 本身。在隔离的另一端,KVM stage1 将标准应用容器作为独立的虚拟机运行,每个虚拟机都有自己的 Linux 内核,由 KVM hypervisor 管理。这种隔离级别对于高安全性和多租户集群工作负载非常有用。

目前,rktnetes 可以通过设置 kubelet 的 --rkt-stage1-image 选项,使用 KVM stage1 在节点上以 VM 隔离方式执行所有容器。已有一些实验性工作,旨在通过 Kubernetes 注解来声明 Pod 适当的 stage1,从而基于每个 Pod 选择 stage1 隔离方案。KVM 容器和标准 Linux 容器可以在同一个集群中混合使用。

rkt 如何与 Kubernetes 协同工作

今天的 Kubernetes 通过 Docker 守护进程提供的 API 与默认容器引擎通信。rktnetes 与 rkt 的通信方式略有不同。首先,Kubernetes 如何改变节点容器状态(例如启动和停止 Pod,或将其重新调度以进行故障转移或扩缩容)与编排器如何查询 Pod 元数据以进行常规的只读簿记之间存在区别。有两个不同的设施来实现这两种不同的情况。

管理微服务生命周期

每个集群节点上的 kubelet 与 rkt 通信以将容器及其环境准备成 Pod,并与 systemd(Linux 服务管理框架)通信以调用和管理 Pod 进程。然后将 Pod 作为 systemd 服务进行管理,kubelet 通过 dbus 发送 systemd 命令来操作它们。生命周期管理,例如重启失败的 Pod 和杀死已完成的进程,由 systemd 在 kubelet 的指示下处理。

读取 Pod 数据的 API 服务

一个独立的rkt api-service 实现了 Kubernetes 所期望的 Pod 内省机制。虽然每个节点的 kubelet 使用 systemd 来启动、停止和重启 Pod 作为服务,但它联系 API 服务来读取容器运行时元数据。这包括基本的编排信息,例如节点上运行的 Pod 数量、这些 Pod 的名称和网络,以及 Pod 配置、资源限制和存储卷的详细信息(可以想象一下 kubectl describe 子命令显示的信息)。

Pod 日志(已写入 journal 文件)也由 API 服务提供给 kubectl logs 和其他取证子命令使用,API 服务从日志文件中读取数据,并将 Pod 日志数据提供给 kubelet 以响应控制平面请求。

容器环境的这种双重接口是一个非常活跃的开发领域,计划是将 API 服务扩展,以提供用于 Pod 操作命令的方法。底层机制将继续牢记关注点分离原则,但会向 kubelet 隐藏更多细节。随着时间的推移,kubelet 用来控制 rktnetes 容器引擎的方法将与默认容器运行时接口越来越相似。

尝试 rktnetes

那么今天您可以用 rktnetes 做什么呢?目前,rktnetes 通过了所有适用的 Kubernetes “端到端”(aka “e2e”)测试,向 cAdvisor 提供标准指标,使用 CNI 管理网络,处理每个容器/Pod 的日志,并自动回收旧容器和镜像。运行在 rkt 上的 Kubernetes 已经提供了一个模块化、灵活的 Kubernetes 集群容器运行时的基础功能,并且它已经是 CoreOS 开发环境的功能性组成部分。

开发人员和早期采用者可以关注rktnetes 说明中的已知问题,了解测试人员可能会遇到的曲折和障碍。这个列表总结了使 rktnetes 与现有容器运行时和 API 达到功能对等所需的高级组件。我们希望您也能在您的 Kubernetes 集群中尝试 rktnetes。

今天就在 Kubernetes 中使用 rkt

入门指南在 rkt 上运行 Kubernetes 逐步介绍了启动 rktnetes 集群的步骤,包括从 kubelet --container-runtime=rkt 到网络配置和启动 Pod。本指南还概述了使用 Kubernetes kube-up.sh 脚本在 GCE 上启动集群所需的配置。

最近的工作也致力于使 rktnetes 集群创建更加容易。虽然尚未合并,但一个进行中的 拉取请求创建了一个单一的 rktnetes 配置开关,用于在使用 coreos-kubernetes 配置工具部署 Kubernetes 集群时选择 rkt 作为容器引擎。您还可以查看 rktnetes workshop 项目,该项目只需一个 vagrant up 命令即可在几乎任何开发人员工作站上启动一个单节点 rktnetes 集群。

我们很高兴看到更广泛的 Kubernetes 和 CoreOS 社区为测试 rktnetes 设计的实验,我们欢迎您的反馈——以及拉取请求!