在现代云原生环境中,Kubernetes(简称 K8s)是自动部署、扩缩和管理容器化应用程序的开源系统,也是实现云原生的重要工具。这篇文章会从开发工程师的角度去介绍云原生、微服务和 K8s 等内容。不会特别深入,但是掌握它足以提高你的日常开发的效率和架构设计能力。

基本概念

下面首先对云原生的关键概念进行解释,然后进行简单的总结,最后梳理这些概念之间的关系。

云原生

通俗地理解“云原生”就是你在开发和部署应用时,不再把程序固定在某一台服务器或特定的环境上,而是让应用能够充分利用云平台和相关部署工具提供的各种便利,如自动扩展、灵活部署、和高可用性。云原生让你的应用像住在“云”里一样,无论需要多少计算资源,或者哪里出问题,它都能自动调整,始终保持稳定运行。

云原生的核心特点是容器化、动态管理、微服务、持续集成和交付(CI/CD)。

容器

容器是云原生应用程序中的最小计算单元,计算单元可以简单理解为一个虚拟机。Docker 是常用的容器化技术之一。Docker 就像一个“容器”,你把应用和它需要的所有东西(比如库、环境配置)都打包到这个“容器”里。这样,这个应用就能在任何地方运行,而不会因为环境不同而出问题。Docker 让微服务更容易部署和运行,因为每个服务都可以打包成独立的“容器”,在不同的环境中保持一致。

微服务

微服务就是,把你的应用拆分成很多“小块”或者“小服务”,每个小服务负责一个特定的功能,比如认证服务、支付服务等。每个小服务可以独立开发、更新、和部署,不会因为其他部分的变化而被影响。在开发者对应用程序进行微调时,可聚焦单个微服务进行处理,更为高效;而在微服务发生故障时,应用程序仍具有连续性。

K8s

K8s 是容器编排工具,帮助管理大量容器,确保你的微服务能够在云原生环境中自动扩展、负载均衡、并实现高可用性。

通俗理解,如果 Docker 容器 是集装箱,那 Kubernetes 就是管理这些集装箱的大脑。它负责自动安排集装箱的“船位”,确保它们有足够的资源来运行,并且如果有一个集装箱出问题了,Kubernetes 会自动启动新的集装箱替补上去,确保应用不会停摆。

CI/CD

通俗地理解,“CI/CD” 就是自动化流水线,让代码从开发到上线变得快速且可靠。CI(持续集成)就像一个自动检测工具,每当你提交代码时,它会自动测试和集成,确保代码没有问题。CD(持续交付/部署)则是把通过测试的代码自动部署到服务器上,或者随时准备好上线。这样,你可以频繁地更新应用,而不用手动处理每个环节,大大减少了出错的可能性。

理解关系

作为一名开发工程师,可以简单理解:

  • 云原生 是一种在云上构建和管理应用的方式,强调自动扩展和灵活性。
  • 微服务 是一种架构,将应用拆分成多个小服务,每个服务独立运行和管理,更适合在云原生环境中使用。
  • 容器 是一个独立的环境,把应用和所有依赖打包在一起,确保它能在任何地方一致运行,常用于运行微服务。
  • Kubernetes (K8s) 是管理容器的工具,它自动处理容器的部署、扩展和故障恢复,确保微服务在云原生环境中平稳运行。
  • CI/CD 是自动化代码管理的流程,CI(持续集成)自动测试和合并代码,CD(持续交付/部署)自动将通过测试的代码部署到生产环境,支持快速和可靠的发布。

它们之间的关系,可以这样理解:

  • 云原生 利用 容器Kubernetes 来实现灵活、自动化的应用管理。
  • 微服务 是一种架构方法,通常与 容器Kubernetes 配合使用。
  • CI/CD 支持 云原生微服务 的快速、自动化发布过程,确保代码的持续集成和自动部署。

K8s 架构

下图展示了 K8s 的基本架构。Kubernetes 是一个用于管理和编排容器化应用的开源平台,整个系统由多个组件组成,分为 控制平面 (Control Plane) 和 工作节点 (Nodes)。

控制平面是 Kubernetes 的大脑,负责管理集群的整体状态,包括调度、决策、和集群控制。主要组件包括:

  • kube-api-server:Kubernetes API 服务器,是控制平面的核心组件。它接收和处理所有外部请求,如集群管理、调度、配置等,并与 etcd 交互来存储集群的状态数据。所有的控制操作都通过 kube-api-server 进行。它是是集群内各个功能模块之间数据交互和通信的中心枢纽。
  • etcd:一个分布式键值存储系统,用来保存集群的所有状态数据,比如 Pod 信息、节点状态等。etcd 被 kube-api-server 用来持久化集群状态。
  • kube-scheduler:负责根据资源的可用性和约束条件,将新创建的 Pod 分配到合适的节点上。Scheduler 会考虑多种因素,如节点的资源使用情况、负载均衡等。
  • kube-controller-manager:Kubernetes 的控制器管理器,负责控制循环(control loops),持续检查集群的状态,并采取行动以达到所期望的状态。它包括多种控制器,比如节点控制器、复制控制器等。
  • cloud-controller-manager:与云服务提供商集成的控制器,负责管理与底层云基础设施相关的任务,比如负载均衡、存储卷管理等。这是 Kubernetes 云原生能力的体现。云控制器管理器 (cloud-controller-manager) 通过与云提供商的 API 交互,管理 Kubernetes 资源与云服务之间的关系,例如动态创建负载均衡器,自动挂载存储卷等。

工作节点是运行实际应用负载的地方。每个节点都运行容器化的应用,即 Pod。节点上的主要组件包括:

  • kubelet:运行在每个节点上的代理,它负责管理该节点上的 Pod。kubelet 接受 kube-api-server 的指令,确保指定的容器在节点上运行,并监控它们的状态。
  • kube-proxy:一个网络代理,运行在每个节点上,负责维护网络规则和流量路由。kube-proxy 确保集群内部和外部的网络流量能正确地转发到相应的 Pod。
  • Pods:是 Kubernetes 中的最小计算单元,一个 Pod 包含一个或多个容器(通常是 Docker 容器)。Pod 是直接在节点上运行的实际应用工作负载。

通过这些组件的协同工作,Kubernetes 能够有效地管理大规模分布式应用,实现自动化部署、扩展和运维。

Kubernetes 架构(图片来自K8s官网)

也许通过上面的描述,还是不太容易理解 K8s 的运行原理,下面我们通过自问自答的方式,来解决困惑。

1. Control Plane 和 Node 是如何通信的?

在 Kubernetes 中,Control Plane 是集群的大脑,负责管理整个集群的状态和行为。而 Node 是集群中实际运行应用的工作节点。两者之间的通信通过以下关键组件实现:

  • kube-apiserver:这是 Control Plane 的核心组件,提供了集群管理的 API 接口。kube-apiserver 是整个集群中各个模块之间数据交互和通信的中心枢纽。它不仅负责处理和转发来自其他组件的请求,还提供了集群的安全机制,确保数据传输的安全性。
  • kubelet:每个 Node 上都会运行一个称为 kubelet 的进程。kubelet 是负责 Node 与 Control Plane 之间通信的关键组件。它向 Control Plane 汇报节点的运行状态,包括节点的注册、终止以及定时的健康检查。同时,kubelet 还接收来自 Control Plane 的命令,负责在该节点上创建和管理 Pod。

在 Kubernetes 中,Pod 是最基本的操作单元,与 Docker 中的容器有一些不同。一个 Pod 可能包含一个或多个容器,这些容器共享同一个网络命名空间和存储卷。Pod 内的容器可以通过 localhost 直接互相通信和共享网络资源。

当一个 Pod 启动时,首先会启动一个 Pause 容器。这个容器的主要作用是为 Pod 创建一个独立的网络命名空间,Pod 内的其他容器通过加入这个命名空间来共享网络配置。这种设计使得 Pod 内的所有容器能够在同一个网络环境下协同工作。

2. Control Plane 如何将 Pod 调度到指定的 Node 上的?

在 Kubernetes 中,Pod 的调度是由 kube-scheduler 负责的。kube-scheduler 是 Kubernetes 中的一个关键组件,它的主要任务是根据集群的当前状态,决定每个新创建的 Pod 应该运行在哪个 Node 上。整个调度过程涉及一系列复杂的算法,这些算法会根据资源需求、节点负载、网络延迟等多个因素,为每个 Pod 选择一个最佳的目标 Node。

如果你希望将 Pod 调度到某个特定的 Node 上,这可以通过 节点标签(Label)Pod 的 NodeSelector 属性 来实现。节点标签是一些键值对,用于标识和分类 Node。通过在 Pod 的定义中设置 NodeSelector,你可以指定 Pod 只能被调度到带有特定标签的节点上。这样,kube-scheduler 就会根据标签匹配来选择合适的节点,从而将 Pod 调度到你指定的 Node 上。

3. 各个 Node、Pod 的信息存放在哪里?

在 Kubernetes 中,为了实现 Pod 的调度,需要了解每个 Node 的资源使用情况、健康状态,以及每个 Pod 的基本信息。那么这些信息是存放在哪里的呢?

Kubernetes 使用一个名为 etcd 的组件作为高可用和强一致性的分布式存储库。etcd 是一个键值存储系统,它保存了集群中的所有配置信息和状态数据。etcd 可以内置在 Kubernetes 集群中,也可以作为外部服务独立部署。

所有关于集群的信息,包括节点的资源状况、Pod 的状态等,都会被存储在 etcd 中。为了保证各个组件的独立性和集群的易维护性,所有对这些数据的增、删、改、查操作都统一通过 kube-apiserver 来进行。kube-apiserver 是 Kubernetes 的核心组件,它负责管理集群的所有 API 请求,既为内部组件提供服务,也对外部用户提供访问接口。

外部用户可以通过 REST API 或者 kubectl 命令行工具来管理集群。无论是通过 REST API 还是 kubectl,这些请求最终都会与 kube-apiserver 进行通信。kube-apiserver 会从 etcd 中读取或写入集群信息,并与其他组件交互。可以说,kube-apiserver 是整个集群中各个功能模块之间数据交互和通信的中心枢纽。

4. 外部的用户如何访问集群内运行的 Pod?

首先,让我们回顾一下 Docker 容器是如何对外提供访问的。在 Docker 的 bridge 网络模式下,每个容器都会分配一个虚拟 IP 地址,这个 IP 地址在宿主机之外是无法直接访问的。为了让外部能够访问容器内部的服务,我们通常会设置端口映射,将容器内部的端口绑定到宿主机的端口上。这样,外部用户可以通过访问宿主机的指定端口,来访问容器内部的服务。

在 Kubernetes 中,外部访问会稍微复杂一些。这是因为 Docker 的端口映射通常只适用于单机环境,而 Kubernetes 是一个分布式集群,通常一个服务是由多个相同的 Pod 提供的,以分担访问压力。这些 Pod 可能分布在不同的节点上,因此还涉及到跨节点的通信问题。

为了解决这个问题,Kubernetes 引入了 Service 的概念。Service 是一个抽象,它将多个相同的 Pod 组合在一起,并对外提供一个统一的访问入口。当创建一个 Pod 时,会为其设置一些标签(labels),而 Service 使用 选择器(Selector) 根据这些标签来识别属于同一个服务的所有 Pod,并将它们作为一个整体对外提供服务。

当 Service 被创建时,Kubernetes 会将这个服务的配置信息通过 kube-apiserver 存储到 etcd 中,管理这个过程的是 Service Controller,它是 kube-controller-manager 内部的一个控制器。此外,为了确保服务能够跨节点访问,Kubernetes 在每个节点上都会运行一个 kube-proxy 进程。kube-proxy 负责将对 Service 的请求代理到对应的 Pod 上,并且实现负载均衡,将流量分发给多个 Pod,从而确保服务的高可用性。

总结来说,Kubernetes 通过 Service 将分布在集群中的多个 Pod 统一为一个对外的服务,并通过 kube-proxy 实现跨节点的通信和负载均衡,使外部用户可以方便地访问集群内的应用。

5. Pod 如何实现动态扩容和缩放?

如前所述,一个服务通常由多个 Pod 提供支持,因此,服务的扩容实际上就是增加 Pod 的数量,而在负载减小时则减少 Pod 的数量,以保持合适的副本数。

在 Kubernetes 中,这个过程主要由 Deployment 来管理。Deployment 是一个 Kubernetes 资源定义,它定义了应用的期望状态,包括要运行的 Pod 副本数量。当实际运行的 Pod 数量与定义的副本数不符时,Deployment 会通过 ReplicaSet 控制器 自动调整 Pod 的数量,确保实际副本数与期望值一致。

这个期望的副本数可以由我们手动设置,也可以通过 Horizontal Pod Autoscaler (HPA) 这种自动扩容机制来动态调整。HPA 会根据应用的实际负载(如 CPU 和内存使用情况)自动调整 Deployment 中 Pod 的副本数。当负载增加时,HPA 会增加 Pod 的数量;当负载减小时,则减少 Pod 的数量。

总的来说,Kubernetes 通过 定义 Deployment 管理 Pod 的副本数,并结合 HPA 实现根据实际负载的自动扩容和缩放,以适应不同的资源需求。

6. 各个组件之间是如何协作的?

我们已经了解到,etcd 是 Kubernetes 集群中用来存储所有数据的分布式数据库,它作为集群的“数据中心”保存了集群的所有状态信息。kube-apiserver 是管理这个数据中心的核心组件,负责处理所有与数据相关的请求,同时充当其他组件与 etcd 之间的“桥梁”。

在 Kubernetes 中,kube-controller-manager 是一个重要的守护进程,它管理了集群中的所有控制器(Controller)。控制器是一种持续运行的逻辑,每个控制器都会不断地监视集群的状态,确保集群的实际状态与期望状态一致。如果发现差异,控制器会尝试做出调整。

Service Controller 负责管理 Service 对象,确保服务与其背后的 Pod 正常通信;ReplicaSet 确保每个应用运行的 Pod 副本数量保持在预期的范围内。除了这些,kube-controller-manager 还包括了许多其他控制器,例如:

  • Node Controller:管理节点(Node)的状态,监控节点的健康状况,并在节点故障时采取相应措施。
  • ResourceQuota Controller:管理集群中命名空间(Namespace)内的资源配额,确保资源使用不会超过限制。
  • Namespace Controller:管理命名空间的生命周期,确保命名空间的创建和删除正确执行。

通过 kube-controller-manager,Kubernetes 能够自动化地管理集群中的各种资源,确保系统始终处于预期状态。

7. Control Plane 和 Node 在运行时是如何分布的?

在 Kubernetes 中,Control PlaneNode 的分布方式是高度灵活且可配置的。

Control Plane 是 Kubernetes 集群的“大脑”,负责管理和控制整个集群的状态和行为。它由多个核心组件组成,包括 kube-apiserver、etcd、kube-scheduler、kube-controller-manager 和 cloud-controller-manager 等。

  • 单节点模式:在开发或测试环境中,Control Plane 的所有组件通常会部署在一台机器上。这种方式设置简单,便于管理,但不具备高可用性。
  • 高可用模式:在生产环境中,为了确保高可用性,Control Plane 通常会部署在多台机器上(通常是奇数个,如 3 台或 5 台),每台机器上运行完整的一套 Control Plane 组件。这种配置确保即使部分 Control Plane 节点发生故障,集群依然能够正常运行。

Node(也称为工作节点)是 Kubernetes 集群中实际运行应用程序的地方。每个 Node 都运行关键组件,如 kubelet、kube-proxy 和容器运行时(如 Docker 或 containerd)。

  • 每个 Node 通常部署在一台独立的机器上,可以是物理服务器、虚拟机或云上的实例。Node 负责运行 Pod,并执行来自 Control Plane 的指令。
  • Kubernetes 集群可以包含多个 Node,Pod 会根据调度策略分布在不同的 Node 上,从而实现应用的高可用性和负载均衡。

Control Plane 中的组件在运行时的分布方式如下:

  • kube-apiserver:通常每个 Control Plane 节点都会运行一个 kube-apiserver 实例,用于处理所有 API 请求。由于 kube-apiserver 是无状态的,可以在多个节点上运行,并通过负载均衡器进行请求分发。
  • etcd:etcd 是一个分布式键值存储系统,负责存储 Kubernetes 集群的所有状态信息。为了确保数据的高可用性和一致性,etcd 通常以集群的形式运行在多个 Control Plane 节点上。
  • kube-scheduler 和 kube-controller-manager:这些组件通常在每个 Control Plane 节点上都运行,但通过 leader 选举机制确保只有一个实例在执行调度和控制任务,其他实例作为备份。
  • cloud-controller-manager(如果集群部署在云上时有):通常也部署在 Control Plane 节点上,负责与底层云提供商的 API 进行交互。

Node 中的组件在运行时的分布方式如下:

  • kubelet:每个 Node 上都会运行一个 kubelet 进程,负责与 Control Plane 进行通信,并管理该节点上的 Pod 和容器。
  • kube-proxy:每个 Node 上也会运行一个 kube-proxy 进程,负责实现 Service 的网络代理和负载均衡功能。
  • 容器运行时:每个 Node 上还会运行容器运行时(如 Docker 或 containerd),用于实际启动和管理容器。

总结

本文首先介绍了云原生中的一些基本概念,并介绍了这些概念之间的关系。然后还介绍了 K8s 的架构,并通过自问自答的方式来理解这个架构是如何运行的。需要注意的是,我们介绍的是整体的原理,了解这些足够帮助我们理解如何使用 K8s,对开发工程师会所帮助。

参考

阿里云云原生架构白皮书2022版
AWS 对云原生的定义
K8s 官方文档
Kubernetes 指南
关于 Kubernetes 架构原理,这是我看过最清晰明了的一篇
一文读懂 K8s 工作原理

Logo

K8S/Kubernetes社区为您提供最前沿的新闻资讯和知识内容

更多推荐