一个叫木头,一个叫马尾

应用程序是如何在Kubernetes上运行的?

文章译自 HOW DO APPLICATIONS RUN ON KUBERNETES?[1],作者 Janakiram MSV


以下内容节选自 The New Stack 新书《The State of the Kubernetes Ecosystem[2]》。

需要该书的朋友可以访问原网站下载,或加译者微信 youmoolee 索取。

节点(node)是 Kubernetes 集群的主力军,负责运行容器化的工作负载(workloads)、日志、监控和服务发现等附加组件以及可选的插件(add-ons)。其目的是将计算、网络和存储资源暴露给应用程序。

正如我们之前在关于Kubernetes架构的文章中所解释的那样,头节点(head nodes)通常运行控制平面(control plane),负责调度和管理工作负载的生命周期。工作节点(worker nodes)则运行应用程序。头节点和工作节点的集合构成一个集群(cluster)。

每个 Kubernetes 节点都会包括一个容器运行时(container runtime),如 Docker,以及一个与头节点通信的代理(kubelet)。一个节点可以是运行在云环境中的虚拟机(VM),也可以是数据中心(data center)内的裸机服务器(bare metal server)。

Components of the worker nodes. Source: Janakiram MSV.
Components of the worker nodes. Source: Janakiram MSV.

Container Runtime (容器运行时)

容器运行时负责管理节点中运行的每个容器的生命周期。在一个 pod 被调度到某节点后,运行时从注册表(registry)中拉取 pod 中所指定的镜像。当一个 pod 终止时,运行时会杀死属于该 pod 的容器。Kubernetes 可以与任何符合开放容器倡议(Open Container Initiative, OCI)[3]的容器运行时进行通信,包括 Docker 和 CRI-O。

OCI 是一个定义运行时规范和镜像规范的标准,目标是推动容器运行时和镜像格式的标准化。

Kubelet

Kubelet 是 Kubernetes 的代理人(agent),它的职责是与容器运行时交互,以执行启动、停止和维护容器等操作。

每个 kubelet 也会监控 pod 的状态。当一个 pod 没有达到部署(deployment)所定义的期望状态时,它可能会在当前所在节点上被重启。节点的状态每隔几秒就会通过心跳消息传送到头节点。如果头节点检测到节点故障,复制控制器(replication controller)会观察到这种状态变化,并将 pod 调度到其他健康节点上。

Kube-Proxy

kube-proxy 组件是作为网络代理和负载平衡器(load balancer)来实现的,它协调网络并将请求路由到合适的 pod 上。它根据传入请求的服务名称和端口号将流量路由到适当的pod。它还能通过操纵 iptables 定义的策略和规则,使用上操作系统特定的网络功能。kube-proxy 组件可以与Calico[4]Flannel[5]等网络层(network layers)集成。

Logging Layer (日志层)

编排器(orchestrator[6])经常会用到日志,作为收集每个节点上容器的资源使用情况和性能指标的手段,例如CPU、内存、文件和网络使用情况。云原生计算基金会(Cloud Native Computing Foundation)托管了一个提供了统一日志记录的软件,供 Kubernetes 或其他编排器使用,称为 Fluentd。该组件会生成 Kubernetes 头控制器(head controller)所需的指标(metrics),以便跟踪可用的集群资源,以及整个基础设施的健康状况。

Add-Ons (插件)

Kubernetes 支持以插件(add-ons)的形式添加额外服务。这些可选的服务,如仪表盘(dashboard),可以像其他应用一样部署,但会与节点上的其他核心组件(如日志层和 kube-proxy )集成。例如,dashboard 插件会从 kubelet 中提取指标,以对资源利用率进行丰富的可视化。基于 kube-dns 或 CoreDNS 的 DNS 插件,通过名称解析(name resolution)来增强 kube-proxy 的功能。

Workloads are Containerized Applications

工作负载就是容器化的应用。

控制平面和工作节点构成了集群基础设施的核心,而工作负载(workloads)则是部署在 Kubernetes 中的容器化应用。

开发人员在开发和测试完一个微服务后,将其打包成容器,再以 pod 的形式打包为最小部署单元。一组属于同一应用的容器在 Kubernetes 内进行分组、打包、部署和管理。

Kubernetes 暴露了用于部署的原语(primitives),同时不断扩展(scaling)、发现和监控这些微服务的健康状况。命名空间(namespaces)通常用于在逻辑上将一个应用程序与另一个应用程序分开。它们通过为属于应用程序的所有资源和服务提供一个定义良好的边界和范围,充当着逻辑集群的作用。

在一个命名空间内,部署了以下 Kubernetes 原语:

Pods

pod 是一个 Kubernetes 应用的基本执行单元。它是 Kubernetes 对象模型中最小、最简单的单元。pod 也是 Kubernetes 应用中最小的可调度条目。如果 Kubernetes 是一个操作系统,那么一个 pod 代表了一组运行在集群上的进程——其中每个进程可被映射到一个容器上。

pod 作为 Kubernetes 工作负载管理的核心单元,为共享上下文和资源的容器提供逻辑边界。将相关的容器分组到 pod 中,弥补了容器化取代第一代虚拟化时带来的配置上的挑战,使多个依赖的进程一起运行成为可能。(译者注: 这段比较绕,简单理解就是,pod使相互依赖的多个容器运行在一个分组中成为可能,相关配置也大大简化了。)

每个 pod 是一个或多个容器的集合,这些容器使用进程间通信(IPC)进行联络,并且可以共享存储和网络栈。在需要将容器耦合和并置(co-locate)的场景中——例如,一个Web服务容器和一个缓存容器——它们可以很容易地被打包进一个单一的 pod 中。可以对一个 pod 进行手动或自动扩充,后者依赖于一个叫作 Horizontal Pod Autoscaling (HPA,水平自动扩展) 特性。通过这种方法,pod 的数量会根据可用资源按比例增加。

Pod 实现了开发和部署之间的功能分离。当开发人员专注于他们的代码时,运维人员可以专注于更广阔的画面,决定哪些相关的容器可以拼接成一个功能单元。得到的是最佳的可移植性,因为一个 pod 只是一个或多个容器镜像的可一起管理的清单(manifest)。

Controllers (控制器)

在 Kubernetes 中,控制器通过添加额外的功能,如所需的配置状态和运行时特征来增强 pod。

Deployment(部署) 给 pod 带来声明式的更新。它通过跟踪参与部署的 pod 的健康状况,确保其始终保持期望状态。每个 deployment 都会管理一个 ReplicaSet,该 ReplicaSet 会按照定义的期望状态,在任何给定时间内维护一组稳定运行的 pod 副本。

通过扩展(scaling)、历史记录和回滚功能,deployment 为 pod 带来类似 PaaS 的功能。当一个 deployemnt 配置的最小副本数为两个时,Kubernetes 会确保至少有两个 pod 始终在运行,从而带来容错性(fault tolerance)。即使在部署只有一个副本的 pod 时,我们也强烈建议使用部署控制器(deployment controller)而不是直接使用 pod 来定义。

statefulset(有状态集) 类似于部署(deployment),但它是为需要持久化和明确定义的标识符以及保证创建顺序的 pod 而服务的。对于数据库集群等工作负载,statefulset 控制器将按照给定的顺序创建一组高可用的 pod,这些 pod 有一个可预测的命名约定。需要高可用的 stateful 工作负载,如Cassandra、Kafka、ZooKeeper 和 SQL Server,在 Kubernetes 中都被部署为有 statefulset。

当需要要强制一个 pod 运行在集群的每个节点上时,可以使用 DaemonSet 控制器。由于 Kubernetes 会在新配置的工作节点中自动调度 DaemonSet,因此它成为配置和准备工作负载节点的理想选择。例如,如果在部署工作负载之前,必须在节点上挂载现有的网络文件系统(NFS)或 Gluster 文件共享,建议将 pod 打包并部署为 DaemonSet。DaemonSet 也是监控代理的良好选择,可确保每个节点都有运行监控代理。

对于批处理和作业调度,可以将 pod 打包为运行到完成的作业(run-to-completion job) 或 定时作业(cron job)。一个作业会创建一个或多个 pod,并确保指定数量的 pod 成功结束。配置为 "运行到完成 "的 pods 会在执行完成后退出,而定时作业则会根据 crontab 格式中定义的时间表来运行作业。

控制器(controller)会根据工作负载特征及其执行上下文来定义 pod 的生命周期。

现在我们已经了解了 Kubernetes 控制平面的基础知识以及应用程序如何在 Kubernetes 上运行,是时候谈谈服务发现以便更好地了解生产中的工作负载是如何在 Kubernetes 中运行的。


歇一歇,下一篇文章将很快译出。欢迎转发点赞、支持译者。

[1]

HOW DO APPLICATIONS RUN ON KUBERNETES?: https://thenewstack.io/how-do-applications-run-on-kubernetes/

[2]

The State of the Kubernetes Ecosystem: https://thenewstack.io/ebooks/kubernetes/state-of-kubernetes-ecosystem-second-edition-2020/

[3]

Open Container Initiative (OCI): https://opencontainers.org

[4]

Calico: https://github.com/projectcalico/calico

[5]

Flannel: https://github.com/coreos/flannel

[6]

WHAT IS CONTAINER ORCHESTRATION?: https://thenewstack.io/what-is-container-orchestration/