掘金 后端 ( ) • 2024-06-23 15:01

作为一名程序员,我编写了一个博客应用服务,并将其部署在云平台上。然而,由于应用服务太受欢迎,访问量过大,经常会出现宕机的情况。

1711119585064.jpeg

为了解决这个问题,我运用了一些工具,以实现当应用服务出现故障时自动重启。同时,我也将应用服务部署在多台服务器上进行负载均衡,如此一来,我们的应用服务终于能够稳定地应对这高访问量的压力了。

1711119585064.jpeg

后来,你又上线了商城应用服务和语音应用服务。随着应用服务数量的增加,需求也变得千奇百怪。有的应用服务不希望被外网访问,有的则要求部署时内存大于XXGB才能正常运行。

每次更新时,你都需要登录到各个服务器上,手动操作。这不仅容易出错,还浪费了大量时间。原本就没时间找女朋友的你,现在哭得更大声了。

那么问题来了,有没有办法可以解决这些问题? 当然有!没有什么是加一个中间层解决不了的,如果有,那就再加一层。这次我们要加的中间层,叫做 Kubernetes。

1711119585064.jpeg

Kubernetes 是什么?

Kubernetes是一款由Google开源的强大工具。由于名称过长,我们通常将其中间的8个字母省略,简洁地将其称为k8s。

1711119585064.jpeg

Kubernetes位于应用服务和服务器之间,它拥有优秀的协调和管理能力,能够管理多个应用服务。你只需要一个yaml文件配置,预设应用的部署顺序等信息,它就能自动化地将应用部署到各个服务器上。更出色的是,如果应用出现问题需要重启,Kubernetes能够自动执行。同时,它还能自动调整应用的规模,进行扩容或缩容。

你可能会好奇,Kubernetes如何做到这些的呢?

Kubernetes 架构原理

为了实现上述的功能,Kubernetes 将服务器划分为两个部分:一部分是控制平面(Control Plane,以前称为 Master),另一部分是工作节点(Node)。

这两者的关系可以类比为管理者与工作者,或者用现在流行的说法,就像是训练师与宠物小精灵。控制平面的职责是管理和控制各个工作节点,而工作节点则负责实际运行各种应用服务。

1711119585064.jpeg

控制平面内部组件

在以往的情况下,我们需要登录到每一台服务器上,手动执行各种命令。现如今,我们只需通过调用 Kubernetes 提供的 API 接口,就能操作这些应用服务资源,这一切都是由API Server组件所提供的。

在部署应用时,我们过去需要检索哪一台服务器的 CPU 和内存资源充足。现在,这部分决策逻辑由调度器(Scheduler)负责。

找到合适的服务器后,我们过去需要手动创建和关闭服务。现在,这部分功能由控制器管理器(Controller Manager)来负责。

所有这些功能都会产生一些数据,这些数据需要被保存起来,以方便后续的逻辑处理。因此,Kubernetes 还需要一个存储层来存储各种数据信息,目前使用的是 etcd。这部分的源代码实现非常解耦,未来可能会扩展以支持其他类型的中间件。

以上就是控制平面内部组件的简单介绍。

1711119585064.jpeg

Node 内部组件

Node 是实际承担工作负载的节点,它可以是一台裸机服务器,也可以是一台虚拟机。Node 的主要职责是运行应用服务,这些服务会在一台 Node 上共享内存和 CPU 等计算资源。

1711119585064.jpeg

在文章的开头,我们讨论了部署多个应用服务的问题。在引入 k8s 之前,我们需要将代码上传到服务器。然而,有了 k8s,我们只需将服务代码打包成容器镜像,便可以轻松地通过一行命令进行部署。

如果你对容器镜像的概念不甚了解,可以将其简单理解为一个包含了应用代码和其依赖的系统环境的压缩包。只需在任何一台机器上解压这个压缩包,就能成功运行服务。为了下载和部署这些镜像,Node 中会包含一个容器运行时组件。

1711119585064.jpeg

我们可以将每个应用服务视为一个容器。大多数情况下,我们会为每个应用服务配备一个日志收集器容器或监控收集器容器。这些容器共同组成一个单元,我们称之为 Pod,而这些 Pod 则在 Node 上运行。

1711119585064.jpeg

Kubernetes (k8s) 可以将 Pod 从一个 Node 调度到另一个 Node,并且可以以 Pod 为单位进行重启和动态扩缩容操作。因此,Pod 是 Kubernetes 中最小的调度单位。

1711119585064.jpeg

另外,前面提到控制平面会通过 API Server 使用 Controller Manager 控制 Node 的创建和关闭服务,因此 Node 上需要一个组件来接收这些命令并执行相应的操作。这个组件叫做 kubelet,主要负责管理和监控 Pod。

此外,Node 上还有一个组件叫做 Kube Proxy,它负责 Node 的网络通信功能。Kube Proxy 确保外部请求能够被正确转发到 Pod 内。

1711119585064.jpeg

Cluster

控制平面和 Node 共同构成了一个被称为集群(Cluster)的实体。在实际的企业环境中,通常我们会构建多个集群,比如为测试环境和生产环境各自搭建一个集群。同时,为了使集群内的服务可供外部用户访问,我们通常会部署一个入口控制器,例如 Ingress 控制器(如 Nginx)。通过这种方式,外部用户可以通过一个统一的入口访问集群内部的服务。

1711119585064.jpeg

kubectl 是什么

我们可以利用 Kubernetes 提供的 API 来创建服务,但这是否意味着我们需要自己编写代码来调用这些 API?其实并不需要,因为 Kubernetes 为我们提供了一个非常便捷的命令行工具,名为 kubectl。我们只需执行相应的命令,kubectl 就会在内部调用 Kubernetes 的 API,从而使我们能够轻松管理和控制 Kubernetes 集群,而无需直接编写代码调用 API。

1711119585064.jpeg

接下来我们以部署服务为例子,看下 k8s 是怎么工作的。

怎么部署服务?

首先,我们需要编写一个 YAML 文件,其中规定了 Pod 中使用的镜像、内存和 CPU 使用量等信息。然后,我们会借助 kubectl 命令行工具执行 kubectl apply -f xx.yaml 命令。这时,kubectl 会读取并解析 YAML 文件,并将解析后的对象以 API 请求的形式发送至 Kubernetes 控制平面的 API Server。随后,API Server 会根据请求指示,驱动 Scheduler 通过 etcd 提供的数据来寻找适合的 Node。接着,Controller Manager 会通过 API Server 指挥 Node 创建服务。在 Node 内部,kubelet 收到指令后会借助 Container runtime 组件拉取镜像并创建容器,最终完成 Pod 的创建。

至此,服务创建工作就算完成了。

1711119585064.jpeg

整个过程中,我们仅需编写一次 yaml 文件并执行一次 kubectl 命令,相较以往,这无疑大大简化了操作,让人省心不少!完成了服务部署,接下来让我们了解一下服务是如何被调用的。

怎么调用服务?

在过去,外部用户如小明只需在浏览器上发送一个 HTTP 请求,即可直接访问我们的服务器上的 Nginx,然后请求信息便会被转发至我们部署的服务内。然而,自从引入了 k8s,外部的请求会首先到达 k8s 集群的 Ingress 控制器。接着,该请求将被转发至 k8s 集群内的某个 Node 上的 Kube Proxy。在找到相应的 pod 后,请求便会被继续转发至内部的容器服务中进行处理。处理完毕后,结果将按照原路返回。至此,一个服务调用流程就此完成。

1711119585064.jpeg

至此,我们已基本了解了 k8s 的工作原理。它实质上是应用服务和服务器之间的中介层,通过提供一系列 API,使我们的服务部署和运维流程得以简化。

值得一提的是,许多大型公司已经基于这些 API 功能构建了自己的服务管理平台。这样,程序员们就不再需要手动输入 kubectl 命令,而只需在界面上简单操作几下,便可完成服务的部署、扩容等操作。这无疑大大提高了工作效率,并提供了极其便利的用户体验。

总结

k8s 是由 Google 开源的强大工具,专为管理大规模容器服务而设计。k8s 集群主要分为控制平面和 Node 两部分,控制平面起着大脑的作用,负责下达指令,而 Node 则如同身体的手脚,负责执行各项任务。

控制平面包含了 API Server、Scheduler、Controller Manager 以及 etcd 等关键组件,而 Node 中则包括了 Pod,Kubelet, Container runtime 和 Kube Proxy 等元素。控制平面和 Node 一同构建了一个完整的 Cluster。

本文通过解析服务部署和服务调用两个例子,将这些组件有机地串联起来,以帮助大家更深入地理解其工作原理和流程。