首页 > 其他分享 >06-无状态应用:剖析 Kubernete 业务副本及水平扩展底层原理

06-无状态应用:剖析 Kubernete 业务副本及水平扩展底层原理

时间:2024-01-11 13:33:33浏览次数:30  
标签:kubectl 副本 06 demo 5d65f98bd9 nginx deployment Pod Kubernete

在上两节课中,我们已经了解了 Kubernetes 中最关键的对象 Pod,也学习了一些 Pod 的常见用法。

每一个 Pod 都是应用的一个实例,但是通常来说你不会直接在 Kubernetes 中创建和运行单个 Pod。因为 Pod 的生命周期是短暂的,即“用后即焚”。理解这一点很重要,这也是“不可变基础设施”这一理念在 Kubernetes 中的最佳实践。同样,对于你后续进行业务改造和容器化上云也具有指导意义。

当一个 Pod 被创建出来,不管是由你直接创建,还是由其他工作负载控制器(Workload Controller)自动创建,经过调度器调度以后,就永久地“长”在某个节点上了,直到该 Pod 被删除,或者因为资源不够被驱逐,抑或由于对应的节点故障导致宕机等。因此单独地用一个 Pod 来承载业务,是没办法保证高可用、可伸缩、负载均衡等要求,而且 Pod 也无法“自愈”。

这时我们就需要在 Pod 之上做一层抽象,通过多个副本(Replica)来保证可用 Pod 的数量,避免业务不可用。在介绍 Kubernetes 中对这种抽象的实现之前,我们先来看看应用的业务类型。

有状态服务 VS 无状态服务

一般来说,业务的服务类型可分为无状态服务和有状态服务。举个简单的例子,像打网络游戏这类的服务,就是有状态服务,而正常浏览网页这类服务一般都是无状态服务。其实判断两种请求的关键在于,两个来自相同发起者的请求在服务器端是否具备上下文关系。

  • 如果是有状态服务,其请求是状态化的,服务器端需要保存请求的相关信息,这样每个请求都可以默认地使用之前的请求上下文。

  • 而无状态服务就不需要这样,每次请求都包含了需要的所有信息,每次请求都和之前的没有任何关系。

有状态服务和无状态服务分别有各自擅长的业务类型和技术优势,在 Kubernetes 中,分别有不同的工作负载控制器来负责承载这两类服务。

本节课,我们先介绍 Kubernetes 中的无状态工作负载。

Kubernetes 中的无状态工作负载

Kubernetes 中各个对象的 metadata 字段都有 label(标签)和 annotation(注解) 两个对象,可以用来标识一些元数据信息。不论是 label 还是 annotation,都是一组键值对,键值不允许相同。关于各个对象的 API 基本构成,可以参照 04 讲中 API 的定义说明,Kubernetes 的各个对象的 API 都符合这个规范。

  • annotation 主要用来记录一些非识别的信息,并不用于标识和选择对象。

  • label 主要用来标识一些有意义且和对象密切相关的信息,用来支持labelSelector(标签选择器)以及一些查询操作,还有选择对象。

为了让这种抽象的对象可以跟 Pod 关联起来,Kubernetes 使用了labelSelector来跟 label 进行选择匹配,从而达到这种松耦合的关联效果。

$ kubectl get pod -l label1=value1,label2=value2 -n my-namespace

比如,我们就可以通过上述命令,查询出 my-namespace 这个命名空间下面,带有标签label1=value1label2=value2的 pod。label 中的键值对在匹配的时候是“”的关系。

ReplicationController

Kubernetes 中有一系列的工作负载可以用来部署无状态服务。在最初,Kubernetes 中使用了ReplicationController来做 Pod 的副本控制,即确保该服务的 Pod 数量维持在特定的数量。为了简洁并便于使用,ReplicationController通常缩写为“rc”,并作为 kubectl 命令的快捷方式,例如:

$ kubectl get rc -n my-namespace

如果副本数少于预定的值,则创建新的 Pod。如果副本数大于预定的值,就删除多余的副本。因此即使你的业务应用只需要一个 Pod,你也可以使用 rc 来自动帮你维护和创建 Pod。

ReplicaSet

随后社区开发了下一代的 Pod 控制器 ReplicaSet(可简写为 rs) 用来替代 ReplicaController。虽然 ReplicaController 目前依然可以使用,但是社区已经不推荐继续使用了。这两者的功能和目的完全相同,但是 ReplicaSet 具备更强大的基于集合的标签选择器,这样你可以通过一组值来进行标签匹配选择。目前支持三种操作符:innotinexists

例如,你可以用environment in (production, qa)来匹配 label 中带有environment=productionenvironment=qa的 Pod。

同样你也可以使用tier notin (frontend,backend)来匹配 label 中不带有tier=frontendtier=backend的 Pod。

或者你可以用 partition来匹配 label 中带有 partition 这个 key 的 Pod。

了解了标签选择器,我们就可以通过如下的 kubectl 命令查找 Pod:

kubectl get pods -l environment=production,tier=frontend

或者使用:

kubectl get pods -l 'environment in (production),tier in (frontend)'

虽然 Replicaset 可以独立使用,但是为了能够更好地协调 Pod 的创建、删除以及更新等操作,我们都是直接使用更高级的 Deployment来管理 Replicaset,社区也是一直这么定位和推荐的。比如一些业务升级的场景,使用单一的 ReplicaController 或者 Replicaset 是无法实现滚动升级的诉求,至少需要定义两个该对象才能实现,而且这两个对象使用的标签选择器中的 label 至少要有一个不相同。通过不断地对这两个对象的副本进行增减,也可以称为调和(Reconcile),才可以完成滚动升级。这样使用起来不方便,也增加了用户的使用门槛,极大地降低了业务发布的效率。

Deployment

通过 Deployment,我们就不需要再关心和操作 ReplicaSet 了。

image (3).png
https://storage.googleapis.com/cdn.thenewstack.io/media/2017/11/07751442-deployment.png

Deployment、ReplicaSet 和 Pod 这三者之间的关系见上图。通过 Deployment,我们可以管理多个 label 各不相同的 ReplicaSet,每个 ReplicaSet 负责保证对应数目的 Pod 在运行。

我们来看一个定义 Deployment 的例子:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment-demo
  namespace: demo
  labels:
    app: nginx
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
        version: v1
    spec:
      containers:
      - name: nginx
        image: nginx:1.14.2
        ports:
        - containerPort: 80

我们这里定义了副本数spec.replicas为 3,同时在spec.selector.matchLabels中设置了app=nginx的 label,用于匹配spec.template.metadata.labels的 label。我们还增加了version=v1的 label 用于后续滚动升级做比较。

我们将上述内容保存到deploy-demo.yaml文件中。

注意,spec.selector.matchLabels中写的 label 一定要能匹配得了spec.template.metadata.labels中的 label。否则该 Deployment 无法关联创建出来的 ReplicaSet。

然后我们通过下面这些命令,便可以在命名空间 demo 中创建名为 nginx-deployment-demo 的 Deployment。

$ kubectl create ns demo
$ kubectl create -f deploy-demo.yaml
deployment.apps/nginx-deployment-demo created

创建完成后,我们可以查看自动创建出来的 rs。

$ kubectl get rs -n demo
NAME                               DESIRED   CURRENT   READY   AGE
nginx-deployment-demo-5d65f98bd9   3         3         0       5s

接下来,我们可以通过如下的几个命令不断地查询系统,看看对应的 Pod 是否运行成功。

$ kubectl get pod -n demo -l app=nginx,version=v1
NAME                                     READY   STATUS              RESTARTS   AGE
nginx-deployment-demo-5d65f98bd9-7w5gp   0/1     ContainerCreating   0          30s
nginx-deployment-demo-5d65f98bd9-d78fx   0/1     ContainerCreating   0          30s
nginx-deployment-demo-5d65f98bd9-ssstk   0/1     ContainerCreating   0          30s
$ kubectl get pod -n demo -l app=nginx,version=v1
NAME                                     READY   STATUS    RESTARTS   AGE
nginx-deployment-demo-5d65f98bd9-7w5gp   1/1     Running   0          63s
nginx-deployment-demo-5d65f98bd9-d78fx   1/1     Running   0          63s
nginx-deployment-demo-5d65f98bd9-ssstk   1/1     Running   0          63s

我们可以看到,从 Deployment 到这里,最后的 Pod 已经创建成功了。

现在我们试着做下镜像更新看看。更改spec.template.metadata.labels中的version=v1version=v2,同时更新镜像nginx:1.14.2nginx:1.19.2

你可以直接通过下述命令来直接更改:

$ kubectl edit deploy nginx-deployment-demo -n demo 

也可以更改deploy-demo.yaml这个文件:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment-demo
  namespace: demo
  labels:
    app: nginx
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
        version: v2
    spec:
      containers:
      - name: nginx
        image: nginx:1.19.2
        ports:
        - containerPort: 80

然后运行这些命令:

$ kubectl apply -f deploy-demo.yaml
Warning: kubectl apply should be used on resource created by either kubectl create --save-config or kubectl apply
deployment.apps/nginx-deployment-demo configured

这个时候,我们来看看 ReplicaSet 有什么变化:

$ kubectl get rs -n demo
NAME                               DESIRED   CURRENT   READY   AGE
nginx-deployment-demo-5d65f98bd9   3         3         3       4m10s
nginx-deployment-demo-7594578db7   1         1         0       3s

可以看到,这个时候自动创建了一个新的 rs 出来:nginx-deployment-demo-7594578db7。一般 Deployment 的默认更新策略是 RollingUpdate,即先创建一个新的 Pod,并待其成功运行以后,再删除旧的。

还有一个更新策略是Recreate,即先删除现有的 Pod,再创建新的。关于 Deployment,我们还可以设置最大不可用(maxUnavailable)和最大增量(maxSurge),来更精确地控制滚动更新操作,具体配置可参照这个文档

我建议你使用默认的策略来保证可用性。后面 Deployment 控制器会不断对这两个 rs 进行调和,直到新的 rs 副本数为 3,老的 rs 副本数为 0。

我们可以通过如下命令,能够观察到 Deployment 的调和过程。

$ kubectl get pod -n demo -l app=nginx,version=v1
NAME                                     READY   STATUS    RESTARTS   AGE
nginx-deployment-demo-5d65f98bd9-7w5gp   1/1     Running   0          4m15s
nginx-deployment-demo-5d65f98bd9-d78fx   1/1     Running   0          4m15s
nginx-deployment-demo-5d65f98bd9-ssstk   1/1     Running   0          4m15s
$ kubectl get pod -n demo -l app=nginx
NAME                                     READY   STATUS              RESTARTS   AGE
nginx-deployment-demo-5d65f98bd9-7w5gp   1/1     Running             0          4m22s
nginx-deployment-demo-5d65f98bd9-d78fx   1/1     Running             0          4m22s
nginx-deployment-demo-5d65f98bd9-ssstk   1/1     Running             0          4m22s
nginx-deployment-demo-7594578db7-zk8jq   0/1     ContainerCreating   0          15s
$ kubectl get pod -n demo -l app=nginx,version=v2
NAME                                     READY   STATUS              RESTARTS   AGE
nginx-deployment-demo-7594578db7-zk8jq   0/1     ContainerCreating   0          19s
$ kubectl get pod -n demo -l app=nginx,version=v2
NAME                                     READY   STATUS              RESTARTS   AGE
nginx-deployment-demo-7594578db7-4g4fk   0/1     ContainerCreating   0          1s
nginx-deployment-demo-7594578db7-zk8jq   1/1     Running             0          31s
$ kubectl get pod -n demo -l app=nginx,version=v1
NAME                                     READY   STATUS        RESTARTS   AGE
nginx-deployment-demo-5d65f98bd9-7w5gp   1/1     Running       0          4m40s
nginx-deployment-demo-5d65f98bd9-d78fx   1/1     Running       0          4m40s
nginx-deployment-demo-5d65f98bd9-ssstk   1/1     Terminating   0          4m40s
$ kubectl get pod -n demo -l app=nginx,version=v2
NAME                                     READY   STATUS              RESTARTS   AGE
nginx-deployment-demo-7594578db7-4g4fk   1/1     Running             0          5s
nginx-deployment-demo-7594578db7-ftzmf   0/1     ContainerCreating   0          2s
nginx-deployment-demo-7594578db7-zk8jq   1/1     Running             0          35s
$ kubectl get pod -n demo -l app=nginx,version=v1
NAME                                     READY   STATUS        RESTARTS   AGE
nginx-deployment-demo-5d65f98bd9-7w5gp   0/1     Terminating   0          4m52s
nginx-deployment-demo-5d65f98bd9-ssstk   0/1     Terminating   0          4m52s
$ kubectl get pod -n demo -l app=nginx,version=v2
NAME                                     READY   STATUS    RESTARTS   AGE
nginx-deployment-demo-7594578db7-4g4fk   1/1     Running   0          17s
nginx-deployment-demo-7594578db7-ftzmf   1/1     Running   0          14s
nginx-deployment-demo-7594578db7-zk8jq   1/1     Running   0          47s
$ kubectl get rs -n demo
NAME                               DESIRED   CURRENT   READY   AGE
nginx-deployment-demo-5d65f98bd9   0         0         0       5m5s
nginx-deployment-demo-7594578db7   3         3         3       58s
$ kubectl get pod -n demo -l app=nginx,version=v1
No resources found in demo namespace.

或者可以通过 kubectl 的 watch 功能:

$ kubectl get pod -n demo -l app=nginx -w

至此,我们完成了 Deployment 的升级过程。

写在最后

Kubernetes 中这些高阶的抽象对象,都是通过标签选择器来控制 Pod 的,包括我们下一节课要讲的有状态服务控制器。通过这些标签选择器,我们也可以通过 kubectl 命令行方便地查询一些对象。

有了 Deployment 这个高级对象,我们可以很方便地完成无状态服务的发布、更新升级,无须多余的人工参与,就能保证业务的高可用性。这也是 Kubernetes 迷人之处——声明式 API。

如果你对本节课有什么想法或者疑问,欢迎你在留言区留言,我们一起讨论。


标签:kubectl,副本,06,demo,5d65f98bd9,nginx,deployment,Pod,Kubernete
From: https://www.cnblogs.com/huangjiale/p/17958376

相关文章

  • 07-有状态应用:Kubernete 如何通过 StatefulSet 支持有状态应用?
    在上一节课中,我们学习了Kubernetes中的无状态工作负载,并上手实践了Deployment对象,相信现在你已经慢慢喜欢上Kubernetes了。那么本节课,我们来一起看看Kubernetes中的另外一种工作负载StatefulSet。从名字就可以看出,这个工作负载主要用于有状态的服务发布。关于有状态服务......
  • 前世今生:Kubernete 是如何火起来的?
    本课时,我们就开始正式进入Kubernetes的学习,或许你已经听过或简单了解过Kubernetes,它是一款由Google开源的容器编排管理工具,而我们想要深入地掌握Kubernetes框架,就不得不先了解Kubernetes的前世今生,而这一切都要从“云计算”的兴起开始讲起。云计算平台说来也巧,“云计算......
  • MURD1060-ASEMI快恢复TO-252封装二极管MURD1060
    编辑:llMURD1060-ASEMI快恢复TO-252封装二极管MURD1060型号:MURD1060品牌:ASEMI封装:TO-252平均正向整流电流(Id):10A最大反向击穿电压(VRM):600V产品引线数量:3产品内部芯片个数:2产品内部芯片尺寸:72MIL峰值正向漏电流:<10ua恢复时间:>2000ns正向浪涌电流:550A正向压降:1.7V恢复时间:35ns最大正向电......
  • MURD1060-ASEMI快恢复TO-252封装二极管MURD1060
    编辑:llMURD1060-ASEMI快恢复TO-252封装二极管MURD1060型号:MURD1060品牌:ASEMI封装:TO-252平均正向整流电流(Id):10A最大反向击穿电压(VRM):600V产品引线数量:3产品内部芯片个数:2产品内部芯片尺寸:72MIL峰值正向漏电流:<10ua恢复时间:>2000ns正向浪涌电流:550A正向压降:1.7V恢复时间......
  • 24伏升36伏48伏大功率升压芯片WT3206
    24V升36V48V大功率升压芯片WT3206WT3206这货就是一个可以自动升压的控制芯片。它内置了个栅极驱动器,用来驱动外部的N-MOSFET。它的输入电压范围挺宽的,从2.5V到24V都能应付自如,而且还有个非反相误差放大器,输入端连着个0.6V精度的参考电压。这货还有点小特色,就是能编程软启动,启动时间......
  • kubernetes-dashboard crashloopbackoff
    Kubernetes(简称K8S)是现阶段非常热门的容器编排平台,可以用于部署、扩展和管理容器化应用程序。Kubernetes提供了一个称为Dashboard的web界面,用于监视和管理集群中的各种资源。然而,有时我们可能会遇到kubernetes-dashboardcrashloopbackoff的问题,本篇文章将介绍这个问题的原因和解决......
  • kubernetes-dashboard crashloopbackoff
    你好,小白!欢迎来到K8S的世界。K8S,也就是Kubernetes,是当今最流行的开源容器编排平台。你在使用中遇到了【kubernetes-dashboardcrashloopbackoff】的问题,这是一个相对常见的问题。别担心,我会帮助你解决它。一、整体流程在解决问题之前,我们先简单了解一下涉及的步骤和整体流程:确认问......
  • 当创建pvc后,kubernetes组件如何协作
    本文分享自华为云社区《当创建一个pvc后,kubernetes会发生什么?》,作者:可以交个朋友。一、背景   外部存储接入Kubernetes的方式主要有两种:In-Tree和Out-of-Tree:In-Tree 是指存储驱动的源码都在Kubernetes代码库中,与Kubernetes一起发布、迭代、管理,这种方式灵活性较差,且......
  • NX2306 建模- 实体表面印字(平面,圆柱面,曲面表面的阴阳文)
    【写在每个笔记前面:个人学习记录,如有错误,烦请指正,不胜感激。】 1、平面印字step1、【插入】→【曲线】→【文本】,按照图右,进行相关定义   step2、【拉伸】,选择对应的文字为曲线阴文:向下减去对应厚度即可;    阳文:向上拉伸合并即可  2、圆柱面印字方法一:上......
  • 图解Kubernetes的服务(Service)
    pod准备:不要直接使用和管理Pods:当使用ReplicaSet水平扩展scale时,Pods可能被terminated当使用Deployment时,去更新DockerImageVersion,旧Pods会被terminated,然后创建新Pods0啥是服务(Service)Kubernetes中Service是将运行在一个或一组[Pod]上的网络应用程序公开为网络......