控制器

ReplicaSet

​ 前面我们学习了 Pod,那我们在定义 pod 资源时,可以直接创建一个 kind:Pod 类型的自主式 pod,但是这存在一个问题,假如 pod 被删除了,那这个 pod 就不能自我恢复,就会彻底被删除,线上这种情况非常危险,所以今天就给大家讲解下 pod 的控制器,所谓控制器就是能够管理 pod,监测 pod 运行状况,当 pod 发生故障,可以自动恢复 pod。也就是说能够代我们去管理 pod 中间层,并帮助我们确保每一个 pod 资源始终处于我们所定义或者我们所期望的目标状态,一旦 pod 资源出现故障,那么控制器会尝试重启 pod 或者里面的容器,如果一直重启有问题的话那么它可能会基于某种策略来进行重新布派或者重新编排;如果 pod 副本数量低于用户所定义的目标数量,它也会自动补全;如果多余,也会自动终止pod 资源。

控制器:概念、原理解读

概述

​ ReplicaSet 是 kubernetes 中的一种副本控制器,简称 rs,主要作用是控制由其管理的 pod,使 pod副本的数量始终维持在预设的个数。它的主要作用就是保证一定数量的 Pod 能够在集群中正常运行,它会持续监听这些 Pod 的运行状态,在 Pod 发生故障时重启 pod,pod 数量减少时重新运行新的 Pod 副本。官方推荐不要直接使用 ReplicaSet,用 Deployment 取而代之,Deployments 是比 ReplicaSet 更高级的概念,它会管理 ReplicaSet 并提供很多其它有用的特性,最重要的是 Deployment 支持声明式更新,声明式更新的好处是不会丢失历史变更。所以 Deployment 控制器不直接管理 Pod 对象,而是由Deployment 管理 ReplicaSet,再由 ReplicaSet 负责管理 Pod 对象。

工作原理

​ Replicaset 核心作用在于代用户创建指定数量的 pod 副本,并确保 pod 副本一直处于满足用户期望的数量, 起到多退少补的作用,并且还具有自动扩容缩容等机制。

Replicaset 控制器主要由三个部分组成:

  • 用户期望的 pod 副本数:用来定义由这个控制器管控的 pod 副本有几个
  • 标签选择器:选定哪些 pod 是自己管理的,如果通过标签选择器选到的 pod 副本数量少于我们指定的数量,需要用到下面的组件
  • pod 资源模板:如果集群中现存的 pod 数量不够我们定义的副本中期望的数量怎么办,需要新建 pod,这就需要 pod 模板,新建的 pod 是基于模板来创建的

资源清单文件编写技巧

#查看定义 Replicaset 资源需要的字段有哪些
[root@k8s01 pod]# kubectl explain rs
KIND:     ReplicaSet
VERSION:  apps/v1

DESCRIPTION:
     ReplicaSet ensures that a specified number of pod replicas are running at
     any given time.

FIELDS:
   apiVersion	<string>
	 #当前资源使用的 api 版本,跟 VERSION: apps/v1 保持一致
	 
   kind	<string>
   	 #资源类型,跟 KIND: ReplicaSet 保持一致

   metadata	<Object>
   	 #元数据,定义 Replicaset 名字的

   spec	<Object>
   	 #定义副本数、定义标签选择器、定义 Pod 模板

   status	<Object>
   	 #状态信息,不能改
#查看 replicaset 的 spec 字段如何定义
[root@k8s01 pod]# kubectl explain rs.spec
KIND:     ReplicaSet
VERSION:  apps/v1

RESOURCE: spec <Object>

DESCRIPTION:
     Spec defines the specification of the desired behavior of the ReplicaSet.
     More info:
     https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status

     ReplicaSetSpec is the specification of a ReplicaSet.

FIELDS:
   minReadySeconds	<integer>

   replicas	<integer>
   	 #定义的 pod 副本数,根据我们指定的值创建对应数量的 pod

   selector	<Object> -required-
   	 #用于匹配 pod 的标签选择器

   template	<Object>
   	 #定义 Pod 的模板,基于这个模板定义的所有 pod 是一样的

#查看 replicaset 的 spec.template 字段如何定义
#对于 template 而言,其内部定义的就是 pod,pod 模板是一个独立的对象
[root@k8s01 pod]# kubectl explain rs.spec.template
KIND:     ReplicaSet
VERSION:  apps/v1

RESOURCE: template <Object>

DESCRIPTION:
     Template is the object that describes the pod that will be created if
     insufficient replicas are detected. More info:
     https://kubernetes.io/docs/concepts/workloads/controllers/replicationcontroller#pod-template

     PodTemplateSpec describes the data a pod should have when created from a
     template

FIELDS:
   metadata	<Object>

   spec	<Object>
   
[root@k8s01 pod]# kubectl explain rs.spec.template.spec

​ 通过上面可以看到,ReplicaSet 资源中有两个 spec 字段。第一个 spec 声明的是 ReplicaSet 定义多少个 Pod 副本(默认将仅部署 1 个 Pod)、匹配 Pod 标签的选择器、创建 pod 的模板。第二个 spec 是spec.template.spec:主要用于 Pod 里的容器属性等配置。

​ .spec.template 里的内容是声明 Pod 对象时要定义的各种属性,所以这部分也叫做 PodTemplate(Pod 模板)。还有一个值得注意的地方是:在.spec.selector 中定义的标签选择器必须能够匹配到spec.template.metadata.labels 里定义的 Pod 标签,否则 Kubernetes 将不允许创建 ReplicaSet。

使用案例

把 frontend.tar.gz 上传到 k8s02 和 k8s03 上,解压

[root@k8s02 images]# docker load -i frontend.tar.gz
[root@k8s03 images]# docker load -i frontend.tar.gz

编写一个 ReplicaSet 资源清单

replicaset.yaml

apiVersion: apps/v1
kind: ReplicaSet
metadata:
  name: frontend
  labels:
    app: guestbook
    tier: frontend
spec:
  selector:
    matchLabels:
      tier: frontend
  replicas: 3
  template:
    metadata:
      labels:
        tier: frontend
    spec:
      containers:
        - name: php-redis
          image: yecc/gcr.io-google_samples-gb-frontend:v3
          imagePullPolicy: IfNotPresent
[root@k8s01 controller]# kubectl apply -f replicaset.yaml 
replicaset.apps/frontend created
[root@k8s01 controller]# kubectl get rs
NAME       DESIRED   CURRENT   READY   AGE
frontend   3         3         3       4s
[root@k8s01 controller]# kubectl get pods
NAME             READY   STATUS    RESTARTS   AGE
frontend-88hzq   1/1     Running   0          8s
frontend-cz9mm   1/1     Running   0          8s
frontend-vjg72   1/1     Running   0          8s

#pod 的名字是由控制器的名字-随机数组成的

#资源清单详细说明

apiVersion: apps/v1    #ReplicaSet 这个控制器属于的核心群组
kind: ReplicaSet      #创建的资源类型
metadata:
  name: frontend    #控制器的名字
  labels:
    app: guestbook
    tier: frontend
spec:
  selector:
    matchLabels:
      tier: frontend    #管理带有 tier=frontend 标签的 pod
  replicas: 3   #管理的 pod 副本数量
  template:     #定义 pod 的模板
    metadata:
      labels:
        tier: frontend    #pod 标签,一定要有,这样上面控制器就能找到它要管理的 pod 是哪些了
    spec:
      containers:    #定义 pod 里运行的容器
        - name: php-redis    #定义容器的名字
          image: yecc/gcr.io-google_samples-gb-frontend:v3
          imagePullPolicy: IfNotPresent

扩容、缩容、更新

#Replicaset 实现 pod 的动态扩容

​ ReplicaSet 最核心的功能是可以动态扩容和回缩,如果我们觉得两个副本太少了,想要增加,只需要修改配置文件 replicaset.yaml 里的 replicas 的值即可,原来 replicas: 3,现在变成 replicaset:4,修改之后,执行如下命令更新:

[root@k8s01 controller]# kubectl apply -f replicaset.yaml 
replicaset.apps/frontend configured
[root@k8s01 controller]# kubectl get rs
NAME       DESIRED   CURRENT   READY   AGE
frontend   4         4         4       5m29s
[root@k8s01 controller]# kubectl get pods
NAME             READY   STATUS    RESTARTS   AGE
frontend-88hzq   1/1     Running   0          5m19s
frontend-cz9mm   1/1     Running   0          5m19s
frontend-sgl8j   1/1     Running   0          3s
frontend-vjg72   1/1     Running   0          5m19s

#也可以直接编辑控制器实现扩容

#这个是我们把请求提交给了 apiserver,实时修改
[root@k8s01 controller]# kubectl edit rs frontend
replicaset.apps/frontend edited
[root@k8s01 controller]# kubectl get rs
NAME       DESIRED   CURRENT   READY   AGE
frontend   5         5         5       7m56s
[root@k8s01 controller]# kubectl get pods
NAME             READY   STATUS    RESTARTS   AGE
frontend-586sc   1/1     Running   0          45s
frontend-88hzq   1/1     Running   0          8m
frontend-cz9mm   1/1     Running   0          8m
frontend-sgl8j   1/1     Running   0          2m44s
frontend-vjg72   1/1     Running   0          8m

image-20240520174049126

#Replicaset 实现 pod 的动态缩容

​ 如果我们觉得 5 个 Pod 副本太多了,想要减少,只需要修改配置文件 replicaset.yaml 里的replicas 的值即可,把 replicaset:4 变成 replicas: 2,修改之后,执行如下命令更新:

[root@k8s01 controller]# kubectl apply -f replicaset.yaml 
replicaset.apps/frontend configured
[root@k8s01 controller]# kubectl get rs
NAME       DESIRED   CURRENT   READY   AGE
frontend   2         2         2       9m20s
[root@k8s01 controller]# kubectl get pods
NAME             READY   STATUS    RESTARTS   AGE
frontend-88hzq   1/1     Running   0          9m25s
frontend-vjg72   1/1     Running   0          9m25s

#Replicaset 实现 pod 的更新

#把 myapp-v2.tar.gz 上传到 k8s02 和 k8s03 上,手动解压

[root@k8s02 images]# docker load -i myapp-v2.tar.gz
[root@k8s03 images]# docker load -i myapp-v2.tar.gz
#修改镜像 image: yecc/gcr.io-google_samples-gb-frontend:v3 变成- image: ikubernetes/myapp:v2,修改之后保存退出
[root@k8s01 controller]# kubectl edit rs frontend
replicaset.apps/frontend edited

#可以看到镜像变成了 ikubernetes/myapp:v2,说明滚动升级成功了
[root@k8s01 controller]# kubectl get rs -o wide
NAME       DESIRED   CURRENT   READY   AGE   CONTAINERS   IMAGES                 SELECTOR
frontend   2         2         2       13m   php-redis    ikubernetes/myapp:v2   tier=frontend
[root@k8s01 controller]# kubectl get pods -o wide
NAME             READY   STATUS    RESTARTS   AGE   IP               NODE    NOMINATED NODE   READINESS GATES
frontend-88hzq   1/1     Running   0          14m   10.244.235.139   k8s03   <none>           <none>
frontend-vjg72   1/1     Running   0          14m   10.244.235.140   k8s03   <none>           <none>
[root@k8s01 controller]# curl 10.244.235.139

image-20240520175016817

[root@k8s01 controller]# curl 10.244.235.140

image-20240520175045012

#上面可以看到虽然镜像已经更新了,但是原来的 pod 使用的还是之前的镜像,新创建的 pod 才会使用最新的镜像

[root@k8s01 controller]# kubectl get pods -o wide
NAME             READY   STATUS    RESTARTS   AGE   IP               NODE    NOMINATED NODE   READINESS GATES
frontend-88hzq   1/1     Running   0          18m   10.244.235.139   k8s03   <none>           <none>
frontend-vjg72   1/1     Running   0          18m   10.244.235.140   k8s03   <none>           <none>

#10.244.235.139 这个 ip 对应的 pod 删除
[root@k8s01 controller]# kubectl delete pods frontend-88hzq
pod "frontend-88hzq" deleted

#重新生成了一个新的 pod:frontend-z5b96
[root@k8s01 controller]# kubectl get pods -o wide
NAME             READY   STATUS    RESTARTS   AGE   IP               NODE    NOMINATED NODE   READINESS GATES
frontend-vjg72   1/1     Running   0          18m   10.244.235.140   k8s03   <none>           <none>
frontend-z5b96   1/1     Running   0          10s   10.244.236.157   k8s02   <none>           <none>

[root@k8s01 controller]# curl 10.244.236.157

image-20240520175330522

#新生成的 pod 的镜像已经变成了 myapp 的,说明更新完成了

#如果我们直接修改 replicaset.yaml 文件,把 image: yecc/gcr.io-google_samples-gb-frontend:v3 变成- image: ikubernetes/myapp:v2

[root@k8s01 controller]# kubectl apply -f replicaset.yaml 
replicaset.apps/frontend configured
[root@k8s01 controller]# kubectl get pods
NAME             READY   STATUS    RESTARTS   AGE
frontend-vjg72   1/1     Running   0          21m
frontend-z5b96   1/1     Running   0          3m17s

#发现原来的 pod 还是用的 frontend:v3 这个镜像,没有实现自动更新

​ 生产环境如果升级,可以删除一个 pod,观察一段时间之后没问题再删除另一个 pod,但是这样需要人工干预多次;实际生产环境一般采用蓝绿发布,原来有一个 rs1,再创建一个 rs2(控制器),通过修改 service 标签,修改 service 可以匹配到 rs2 的控制器,这样才是蓝绿发布,这个也需要我们精心的部署规划,我们有一个控制器就是建立在 rs 之上完成的,叫做 Deployment

Deployment

Deployment 官方文档:

https://kubernetes.io/docs/concepts/workloads/controllers/deployment/

概述

​ Deployment 是 kubernetes 中最常用的资源对象,为 ReplicaSet 和 Pod 的创建提供了一种声明式的定义方法,在 Deployment 对象中描述一个期望的状态,Deployment 控制器就会按照一定的控制速率把实际状态改成期望状态,通过定义一个 Deployment 控制器会创建一个新的 ReplicaSet 控制器,通过ReplicaSet 创建 pod,删除 Deployment 控制器,也会删除 Deployment 控制器下对应的 ReplicaSet 控制器和 pod 资源.

​ 使用 Deployment 而不直接创建 ReplicaSet 是因为 Deployment 对象拥有许多 ReplicaSet 没有的特性,例如滚动升级和回滚。

扩展:声明式定义是指直接修改资源清单 yaml 文件,然后通过 kubectl apply -f 资源清单 yaml 文件,就可以更改资源

​ Deployment 控制器是建立在 rs 之上的一个控制器,可以管理多个 rs,每次更新镜像版本,都会生成一个新的 rs,把旧的 rs 替换掉,多个 rs 同时存在,但是只有一个 rs 运行

image-20240521093800339

​ rs v1 控制三个 pod,删除一个 pod,在 rs v2 上重新建立一个,依次类推,直到全部都是由 rs v2控制,如果 rs v2 有问题,还可以回滚,Deployment 是建构在 rs 之上的,多个 rs 组成一个Deployment,但是只有一个 rs 处于活跃状态.

工作原理

​ Deployment 可以使用声明式定义,直接在命令行通过纯命令的方式完成对应资源版本的内容的修改,也就是通过打补丁的方式进行修改;Deployment 能提供滚动式自定义自控制的更新;对 Deployment来讲,我们在实现更新时还可以实现控制更新节奏和更新逻辑。

什么叫做更新节奏和更新逻辑

​ 比如说 Deployment 控制 5 个 pod 副本,pod 的期望值是 5 个,但是升级的时候需要额外多几个pod,那我们控制器可以控制在 5 个 pod 副本之外还能再增加几个 pod 副本;比方说能多一个,但是不能少,那么升级的时候就是先增加一个,再删除一个,增加一个删除一个,始终保持 pod 副本数是 5 个;还有一种情况,最多允许多一个,最少允许少一个,也就是最多 6 个,最少 4 个,第一次加一个,删除两个,第二次加两个,删除两个,依次类推,可以自己控制更新方式,这种滚动更新需要加readinessProbe 和 livenessProbe 探测,确保 pod 中容器里的应用都正常启动了才删除之前的 pod。

​ 启动第一步,刚更新第一批就暂停了也可以;假如目标是 5 个,允许一个也不能少,允许最多可以10 个,那一次加 5 个即可;这就是我们可以自己控制节奏来控制更新的方法。

通过 Deployment 对象,你可以轻松的做到以下事情:

  1. 创建 ReplicaSet 和 Pod
  2. 滚动升级(不停止旧服务的状态下升级)和回滚应用(将应用回滚到之前的版本)
  3. 平滑地扩容和缩容
  4. 暂停和继续 Deployment

资源清单文件编写技巧

#查看 Deployment 资源对象由哪几部分组成
[root@k8s01 controller]# kubectl explain deploy
KIND:     Deployment
VERSION:  apps/v1

DESCRIPTION:
     Deployment enables declarative updates for Pods and ReplicaSets.

FIELDS:
   apiVersion	<string>
   	 #该资源使用的 api 版本

   kind	<string>
   	 #创建的资源是什么?

   metadata	<Object>
   	 #元数据,包括资源的名字和名称空间

   spec	<Object>
   	 #定义容器的
   status	<Object>
   	 #状态,不可以修改
#查看 Deployment 下的 spec 字段
[root@k8s01 controller]# kubectl explain deploy.spec
KIND:     Deployment
VERSION:  apps/v1

RESOURCE: spec <Object>

DESCRIPTION:
     Specification of the desired behavior of the Deployment.

     DeploymentSpec is the specification of the desired behavior of the
     Deployment.

FIELDS:
   minReadySeconds	<integer>
   	 #Kubernetes 在等待设置的时间后才进行升级 
	 #如果没有设置该值,Kubernetes 会假设该容器启动起来后就提供服务了

   paused	<boolean>
   	 #暂停,当我们更新的时候创建 pod 先暂停,不是立即更新

   progressDeadlineSeconds	<integer>
   	 # k8s 在升级过程中有可能由于各种原因升级卡住(这个时候还没有明确的升级失败),比如在拉取翻墙的镜像,权限不够等错误。那么这个时候就需要有个 deadline ,在 deadline之内如果还卡着,那么就上报这个情况,这个时候这个 Deployment 状态就被标记为 False,并且注明原因。但是它并不会阻止 Deployment 继续进行卡住后面的操作。完全由用户进行控制。

   replicas	<integer>
   	 #副本数

   revisionHistoryLimit	<integer>
   	 #保留的历史版本,默认是 10

   selector	<Object> -required-
   	 #标签选择器,选择它关联的 pod

   strategy	<Object>
   	 #更新策略

   template	<Object> -required-
   	 #定义的 pod 模板

#查看 Deployment 下的 spec.strategy 字段
[root@k8s01 controller]# kubectl explain deploy.spec.strategy
KIND:     Deployment
VERSION:  apps/v1

RESOURCE: strategy <Object>

DESCRIPTION:
     The deployment strategy to use to replace existing pods with new ones.

     DeploymentStrategy describes how to replace existing pods with new ones.

FIELDS:
   rollingUpdate	<Object>
     Rolling update config params. Present only if DeploymentStrategyType =
     RollingUpdate.

   type	<string>
     Type of deployment. Can be "Recreate" or "RollingUpdate". Default is
     RollingUpdate.
      #支持两种更新,Recreate 和 RollingUpdate 
	 #Recreate 是重建式更新,删除一个更新一个
	 #RollingUpdate 滚动更新,定义滚动更新方式,也就是 pod 能多几个,少几个
#查看 Deployment 下的 spec.strategy.rollingUpdate 字段
[root@k8s01 controller]# kubectl explain deploy.spec.strategy.rollingUpdate
KIND:     Deployment
VERSION:  apps/v1

RESOURCE: rollingUpdate <Object>

DESCRIPTION:
     Rolling update config params. Present only if DeploymentStrategyType =
     RollingUpdate.

     Spec to control the desired behavior of rolling update.

FIELDS:
   maxSurge	<string>
   	 #我们更新的过程当中最多允许超出的指定的目标副本数有几个;它有两种取值方式,第一种直接给定数量,第二种根据百分比,百分比表示原本是 5 个,最多可以超出 20%,那就允许多一个,最多可以超过 40%,那就允许多两个

   maxUnavailable	<string>
   	 #最多允许几个不可用 假设有 5 个副本,最多一个不可用,就表示最少有 4 个可用
#查看 Deployment 下的 spec.template 字段 
#template 为定义 Pod 的模板,Deployment 通过模板创建 Pod
[root@k8s01 controller]# kubectl explain deploy.spec.template
KIND:     Deployment
VERSION:  apps/v1

RESOURCE: template <Object>

DESCRIPTION:
     Template describes the pods that will be created.

     PodTemplateSpec describes the data a pod should have when created from a
     template

FIELDS:
   metadata	<Object>
   	 #定义模板的名字

   spec	<Object>
   	#deployment.spec.template 为 Pod 定义的模板,和 Pod 定义不太一样,template 中不包含apiVersion 和 Kind 属性,要求必须有 metadata。deployment.spec.template.spec 为容器的属性信息,其他定义内容和 Pod 一致。

#查看 Deployment 下的 spec.template.spec 字段
[root@k8s01 controller]# kubectl explain deploy.spec.template.spec
KIND:     Deployment
VERSION:  apps/v1

RESOURCE: spec <Object>

DESCRIPTION:
     Specification of the desired behavior of the pod. More info:
     https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status

     PodSpec is a description of a pod.

FIELDS:
   activeDeadlineSeconds	<integer>
   	 #activeDeadlineSeconds 表示 Pod 可以运行的最长时间,达到设置的该值后,Pod 会自动停止。

   affinity	<Object>
   	 #定义亲和性,跟直接创建 pod 时候定义亲和性类似

   automountServiceAccountToken	<boolean>
   	  #身份认证相关的

   containers	<[]Object> -required-
   	  #定义容器属性

   dnsConfig	<Object>
   	 #设置 Pod 的 DNS

   dnsPolicy	<string>
   	 # dnsPolicy 决定 Pod 内预设的 DNS 配置策略
   	 # None 无任何策略:使用自定义的策略 
	 # Default 默认:使用宿主机的 dns 配置,/etc/resolv.conf 
	 # ClusterFirst 集群 DNS 优先,与 Default 相反,会预先使用 kube-dns (或 CoreDNS ) 的信息当预设置参数写入到该 Pod 内的 DNS 配置。 
	 # ClusterFirstWithHostNet 集群 DNS 优先,并伴随着使用宿主机网络:同时使用 hostNetwork 与 kube-dns 作为 Pod 预设 DNS 配置。

   enableServiceLinks	<boolean>

   ephemeralContainers	<[]Object>
   	 #定义临时容器

   hostAliases	<[]Object>
   	 #在 pod 中增加域名解析的

   hostIPC	<boolean>
   	 #使用主机 IPC

   hostNetwork	<boolean>
   	 #是否使用宿主机的网络

   hostPID	<boolean>
   	  #可以设置容器里是否可以看到宿主机上的进程。True 可以

   hostname	<string>

   imagePullSecrets	<[]Object>

   initContainers	<[]Object>
   	 #定义初始化容器

   nodeName	<string>
   	 #定义 pod 调度到具体哪个节点上

   nodeSelector	<map[string]string>
   	  #定义节点选择器

   overhead	<map[string]string>
   	  #overhead 是 1.16 引入的字段,在没有引入 Overhead 之前,只要一个节点的资源可用量大于等于 Pod 的 requests 时,这个 Pod 就可以被调度到这个节点上。引入 Overhead 之后,只有节点的资源可用量大于等于 Overhead 加上 requests 的和时才能被调度上来。

   preemptionPolicy	<string>

   priority	<integer>

   priorityClassName	<string>
   
   readinessGates	<[]Object>

   restartPolicy	<string>
   	 #Pod 重启策略

   runtimeClassName	<string>

   schedulerName	<string>

   securityContext	<Object>
   	 #是否开启特权模式

   serviceAccount	<string>

   serviceAccountName	<string>

   setHostnameAsFQDN	<boolean>

   shareProcessNamespace	<boolean>

   subdomain	<string>

   terminationGracePeriodSeconds	<integer>
   	 #在真正删除容器之前,K8S 会先发终止信号(kill -15 {pid})给容器,默认 30s

   tolerations	<[]Object>
   	 #定义容忍度

   topologySpreadConstraints	<[]Object>

   volumes	<[]Object>
   	 #挂载存储卷

​ 临时容器与其他容器的不同之处在于,它们缺少对资源或执行的保证,并且永远不会自动重启,因此不适用于构建应用程序。临时容器使用与常规容器相同的 ContainerSpec 段进行描述,但许多字段是不相容且不允许的。临时容器没有端口配置,因此像 ports,livenessProbe,readinessProbe 这样的字段是不允许的。

​ Pod 资源分配是不可变的,因此 resources 配置是不允许的。

临时容器用途:

​ 当由于容器崩溃或容器镜像不包含调试应用程序而导致 kubectl exec 无用时,临时容器对于交互式故障排查很有用。

使用案例

deployment 是一个三级结构,deployment 管理 replicaset,replicaset 管理 pod,

例子:用 deployment 创建一个 pod

#把 myapp-blue-v1.tar.gz 和 myapp-blue-v2.tar.gz 上传到 k8s02 和 k8s03 上,

手动解压:

[root@k8s02 images]# docker load -i myapp-blue-v1.tar.gz
[root@k8s02 images]# docker load -i myapp-blue-v2.tar.gz

[root@k8s03 images]# docker load -i myapp-blue-v1.tar.gz
[root@k8s03 images]# docker load -i myapp-blue-v2.tar.gz

deploy-demo.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp-v1
spec:
  replicas: 2
  selector:
    matchLabels:
      app: myapp
      version: v1
  template:
    metadata:
      labels:
        app: myapp
        version: v1
    spec:
      containers:
        - name: myapp
          image: janakiramm/myapp:v1
          imagePullPolicy: IfNotPresent
          ports:
            - containerPort: 80
#kubectl apply:表示声明式的定义,既可以创建资源,也可以动态更新资源
[root@k8s01 controller]# kubectl apply -f deploy-demo.yaml 
deployment.apps/myapp-v1 created
#查看 deploy 状态
[root@k8s01 controller]# kubectl get deploy
NAME       READY   UP-TO-DATE   AVAILABLE   AGE
myapp-v1   2/2     2            2           6s

创建的控制器名字是 myapp-v1

  1. NAME :列出名称空间中 deployment 的名称
  2. READY:显示 deployment 有多少副本数。它遵循 ready/desired 的模式。
  3. UP-TO-DATE: 显示已更新到所需状态的副本数。
  4. AVAILABLE: 显示你的可以使用多少个应用程序副本。
  5. AGE :显示应用程序已运行的时间。
[root@k8s01 controller]# kubectl get rs
NAME                  DESIRED   CURRENT   READY   AGE
myapp-v1-67fd9fc9c8   2         2         2       10s

创建 deploy 的时候也会创建一个 rs(replicaset),67fd9fc9c8 这个随机数字是我们引用pod 的模板 template 的名字的 hash 值

  1. NAME: 列出名称空间中 ReplicaSet 资源
  2. DESIRED:显示应用程序的所需副本数,这些副本数是在创建时定义的。这是所需的状态
  3. CURRENT: 显示当前正在运行多少个副本
  4. READY: 显示你的用户可以使用多少个应用程序副本
  5. AGE :显示应用程序已运行的时间

请注意,ReplicaSet 的名称始终设置为[DEPLOYMENT-NAME]-[RANDOM-STRING]。RANDOM-STRING 是随机生成的

[root@k8s01 controller]# kubectl get pods -o wide
NAME                        READY   STATUS    RESTARTS   AGE    IP               NODE    NOMINATED NODE   READINESS GATES
myapp-v1-67fd9fc9c8-fw4jl   1/1     Running   0          6m4s   10.244.236.159   k8s02   <none>           <none>
myapp-v1-67fd9fc9c8-z4bcn   1/1     Running   0          6m4s   10.244.236.158   k8s02   <none>           <none>

#请求刚才创建的 pod 资源

[root@k8s01 controller]# curl 10.244.236.159

image-20240521103911936

资源清单文件详细解读

apiVersion: apps/v1     #deployment 对应的 api 版本
kind: Deployment        #创建的资源是 deployment
metadata:
  name: myapp-v1        #deployment 的名字
spec:
  replicas: 2           #deployment 管理的 pod 副本数
  selector:             #标签选择器
    matchLabels:        # matchLabels 下定义的标签需要跟 template.metadata.labels 定义的标签一致
      app: myapp
      version: v1
  template:
    metadata:
      labels:
        app: myapp
        version: v1
    spec:               #定义容器的属性
      containers:
        - name: myapp
          image: janakiramm/myapp:v1       #容器使用的镜像
          imagePullPolicy: IfNotPresent     #镜像拉取策略
          ports:
            - containerPort: 80           #容器里的应用的端口

扩容、缩容、滚动更新、回滚

  1. 扩容

    #通过 deployment 管理应用,实现扩容,把副本数变成 3
    #直接修改 replicas 数量,如下,变成 3
    
    #修改之后保存退出,执行
    [root@k8s01 controller]# kubectl apply -f deploy-demo.yaml 
    deployment.apps/myapp-v1 configured
    #注意:apply 不同于 create,apply 可以执行多次;create 执行一次,再执行就会报错复。
    
    [root@k8s01 controller]# kubectl get pods
    NAME                        READY   STATUS    RESTARTS   AGE
    myapp-v1-67fd9fc9c8-fw4jl   1/1     Running   0          14m
    myapp-v1-67fd9fc9c8-h9p2k   1/1     Running   0          32s
    myapp-v1-67fd9fc9c8-z4bcn   1/1     Running   0          14m
    #上面可以看到 pod 副本数变成了 3 个
    
    #查看 myapp-v1 这个控制器的详细信息
    [root@k8s01 controller]# kubectl describe deploy/myapp-v1
    

    image-20240521110051622

  2. 缩容

    #通过 deployment 管理应用,实现缩容,把副本数变成 2
    #直接修改 replicas 数量,如下,变成 2
    
    #修改之后保存退出,执行
    [root@k8s01 controller]# kubectl apply -f deploy-demo.yaml 
    deployment.apps/myapp-v1 configured
    
    [root@k8s01 controller]# kubectl get pods
    NAME                        READY   STATUS    RESTARTS   AGE
    myapp-v1-67fd9fc9c8-fw4jl   1/1     Running   0          30m
    myapp-v1-67fd9fc9c8-z4bcn   1/1     Running   0          30m
    
  3. 滚动更新

    #在一个终端窗口执行如下:
    #-w监听
    [root@k8s01 controller]# kubectl get pods -w
    NAME                        READY   STATUS    RESTARTS   AGE
    myapp-v1-67fd9fc9c8-fw4jl   1/1     Running   0          32m
    myapp-v1-67fd9fc9c8-z4bcn   1/1     Running   0          32m
    
    
    #打开一个新的终端窗口更改镜像版本,按如下操作:
    [root@k8s01 controller]# vim deploy-demo.yaml
    把 image: janakiramm/myapp:v1 变成 image: janakiramm/myapp:v2 
    保存退出,执行
    [root@k8s01 controller]# kubectl apply -f deploy-demo.yaml 
    deployment.apps/myapp-v1 configured
    

    再回到刚才执行监测 kubectl get pods -w 的那个窗口,可以看到信息如下:

    image-20240521110640550

    pending 表示正在进行调度,ContainerCreating 表示正在创建一个 pod,running 表示运行一个 pod,running 起来一个 pod 之后再 Terminating(停掉)一个 pod,以此类推,直到所有 pod 完成滚动升级

    #在另外一个窗口执行
    [root@k8s01 controller]# kubectl get rs
    NAME                  DESIRED   CURRENT   READY   AGE
    myapp-v1-67fd9fc9c8   0         0         0       36m
    myapp-v1-75fb478d6c   2         2         2       87s
    #上面可以看到 rs 有两个,上面那个是升级之前的,已经被停掉,但是可以随时回滚
    
    #查看 myapp-v1 这个控制器的历史版本
    [root@k8s01 controller]# kubectl rollout history deploy/myapp-v1
    deployment.apps/myapp-v1 
    REVISION  CHANGE-CAUSE
    1         <none>
    2         <none>
    
  4. 回滚

    [root@k8s01 controller]# kubectl rollout undo deploy/myapp-v1 --to-revision=1
    deployment.apps/myapp-v1 rolled back
    
    [root@k8s01 controller]# kubectl rollout history deploy/myapp-v1
    deployment.apps/myapp-v1 
    REVISION  CHANGE-CAUSE
    2         <none>
    3         <none>
    

自定义滚动更新策略

maxSurge 和 maxUnavailable 用来控制滚动更新的更新策略

取值范围

  • 数值

    • maxUnavailable: [0, 副本数]
    • maxSurge: [0, 副本数]
    • 注意:两者不能同时为 0。
  • 比例

    • maxUnavailable: [0%, 100%] 向下取整,比如 10 个副本,5%的话==0.5 个,但计算按照 0 个;
    • maxSurge: [0%, 100%] 向上取整,比如 10 个副本,5%的话==0.5 个,但计算按照 1 个;

    注意:两者不能同时为 0。

建议配置

  • maxUnavailable == 0
  • maxSurge == 1

这是我们生产环境提供给用户的默认配置。即“一上一下,先上后下”最平滑原则:

​ 1 个新版本 pod ready(结合 readiness)后,才销毁旧版本 pod。此配置适用场景是平滑更新、保证服务平稳,但也有缺点,就是“太慢”了。

总结:

​ maxUnavailable:和期望的副本数比,不可用副本数最大比例(或最大值),这个值越小,越能保证服务稳定,更新越平滑;

​ maxSurge:和期望的副本数比,超过期望副本数最大比例(或最大值),这个值调的越大,副本更新速度越快。

自定义策略:

#修改更新策略:maxUnavailable=1,maxSurge=1
spec:
  strategy:
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 1
# 查看 myapp-v1 这个控制器的详细信息
[root@k8s01 controller]# kubectl describe deploy/myapp-v1

image-20240522091651610

上面可以看到 RollingUpdateStrategy: 1 max unavailable, 1 max surge

​ 这个 rollingUpdate 更新策略变成了刚才设定的,因为我们设定的 pod 副本数是 3,1 和 1 表示最少不能少于 2 个 pod,最多不能超过 4 个 pod

​ 这个就是通过控制 RollingUpdateStrategy 这个字段来设置滚动更新策略的

Daemonset

概念、原理解读

  1. 概述

    DaemonSet 控制器能够确保 k8s 集群所有的节点都运行一个相同的 pod 副本,当向k8s 集群中增加 node 节点时,这个 node 节点也会自动创建一个 pod 副本,当 node 节点从集群移除,这些 pod 也会自动删除;删除 Daemonset 也会删除它们创建的 pod

  2. 工作原理:如何管理 Pod

    daemonset 的控制器会监听 kuberntes 的 daemonset 对象、pod 对象、node 对象,这些被监听的对象变动,就会触发 syncLoop 循环让 kubernetes 集群朝着 daemonset 对象描述的状态进行演进。

  3. 典型的应用场景

    • 在集群的每个节点上运行存储,比如:glusterd 或 ceph。
    • 在每个节点上运行日志收集组件,比如:flunentd 、 logstash、filebeat 等。
    • 在每个节点上运行监控组件,比如:Prometheus、 Node Exporter 、collectd 等。
  4. DaemonSet 与 Deployment 的区别

    Deployment 部署的副本 Pod 会分布在各个 Node 上,每个 Node 都可能运行好几个副本。

    DaemonSet 的不同之处在于:每个 Node 上最多只能运行一个副本。

资源清单文件编写技巧

[root@k8s01 controller]# kubectl explain ds
KIND:     DaemonSet
VERSION:  apps/v1

DESCRIPTION:
     DaemonSet represents the configuration of a daemon set.

FIELDS:
   apiVersion	<string>
   	 #当前资源使用的 api 版本,跟 VERSION: apps/v1 保持一致

   kind	<string>
   	 #资源类型,跟 KIND: DaemonSet 保持一致

   metadata	<Object>
   	  #元数据,定义 DaemonSet 名字的

   spec	<Object>
   	 #定义容器的

   status	<Object>
   
 
#查看 DaemonSet 的 spec 字段如何定义
[root@k8s01 controller]# kubectl explain ds.spec
KIND:     DaemonSet
VERSION:  apps/v1

RESOURCE: spec <Object>

DESCRIPTION:
     The desired behavior of this daemon set. More info:
     https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status

     DaemonSetSpec is the specification of a daemon set.

FIELDS:
   minReadySeconds	<integer>
   	 #当新的 pod 启动几秒种后,再 kill 掉旧的pod。

   revisionHistoryLimit	<integer>
   	 #历史版本可以保留多少个

   selector	<Object> -required-
   	 #用于匹配 pod 的标签选择器

   template	<Object> -required-
   	 #定义 Pod 的模板,基于这个模板定义的所有 pod 是一样的

   updateStrategy	<Object>
	 #daemonset 的升级策略
	 
	 
#查看 DaemonSet 的 spec.template 字段如何定义? 
#对于 template 而言,其内部定义的就是 pod,pod 模板是一个独立的对象

使用案例

部署日志收集组件 fluentd

#把 fluentd-2-5-1.tar.gz 上传到 k8s01 和 k8s02 和 k8s03 上,解压
[root@k8s01 images]# docker load -i fluentd_2_5_1.tar.gz
[root@k8s02 images]# docker load -i fluentd_2_5_1.tar.gz
[root@k8s03 images]# docker load -i fluentd_2_5_1.tar.gz

#编写一个 DaemonSet 资源清单

daemonset.yaml

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: fluentd-elasticsearch
  namespace: kube-system
  labels:
    k8s-app: fluentd-logging
spec:
  selector:
    matchLabels:
      app: fluentd-elasticsearch
  template:
    metadata:
      labels:
        app: fluentd-elasticsearch
    spec:
      tolerations:
        - key: node-role.kubernetes.io/master
          effect: NoSchedule
      containers:
        - name: fluentd-elasticsearch
          image: xianchao/fluentd:v2.5.1
          imagePullPolicy: IfNotPresent
          resources:
            limits:
              memory: 200Mi
            requests:
              cpu: 100m
              memory: 200Mi
          volumeMounts:
            - mountPath: /var/log
              name: varlog
            - mountPath: /var/lib/docker/containers
              readOnly: true
              name: varlibdockercontainers
      volumes:
        - name: varlog
          hostPath:
            path: /var/log
        - name: varlibdockercontainers
          hostPath:
            path: /var/lib/docker/containers
[root@k8s01 controller]# kubectl apply -f daemonset.yaml 
daemonset.apps/fluentd-elasticsearch created
[root@k8s01 controller]# kubectl get ds -n kube-system
NAME                    DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR            AGE
calico-node             3         3         3       3            3           kubernetes.io/os=linux   4d3h
fluentd-elasticsearch   3         3         3       3            3           <none>                   17s
kube-proxy              3         3         3       3            3           kubernetes.io/os=linux   4d3h
[root@k8s01 controller]# kubectl get pods -n kube-system -l app=fluentd-elasticsearch -o wide
NAME                          READY   STATUS    RESTARTS   AGE   IP               NODE    NOMINATED NODE   READINESS GATES
fluentd-elasticsearch-8ngq7   1/1     Running   0          67s   10.244.236.178   k8s02   <none>           <none>
fluentd-elasticsearch-svfcv   1/1     Running   0          67s   10.244.235.144   k8s03   <none>           <none>
fluentd-elasticsearch-x8b5s   1/1     Running   0          67s   10.244.73.66     k8s01   <none>           <none>
#通过上面可以看到在 k8s 的三个节点均创建了 fluentd 这个 pod
#pod 的名字是由控制器的名字-随机数组成的

Statefulset

概念、原理解读

StatefulSet 是为了管理有状态服务的问题而设计的

有状态服务:

​ StatefulSet 是有状态的集合,管理有状态的服务,它所管理的 Pod 的名称不能随意变化。数据持久化的目录也是不一样,每一个 Pod 都有自己独有的数据持久化存储目录。比如 MySQL 主从、redis 集群等。

无状态服务:

​ RC、Deployment、DaemonSet 都是管理无状态的服务,它们所管理的 Pod 的 IP、名字,启停顺序等都是随机的。个体对整体无影响,所有 pod 都是共用一个数据卷的,部署的 tomcat 就是无状态的服务,tomcat 被删除,在启动一个新的 tomcat,加入到集群即可,跟 tomcat 的名字无关。

StatefulSet 由以下几个部分组成:

  1. Headless Service:用来定义 pod 网路标识,生成可解析的 DNS 记录
  2. volumeClaimTemplates:存储卷申请模板,创建 pvc,指定 pvc 名称大小,自动创建pvc,且 pvc 由存储类供应
  3. StatefulSet:管理 pod 的

什么是 Headless service

​ Headless service 不分配 clusterIP,headless service 可以通过解析 service 的 DNS,返回所有 Pod 的 dns 和 ip 地址 (statefulSet 部署的 Pod 才有 DNS),普通的 service,只能通过解析service 的 DNS 返回 service 的 ClusterIP。

为什么要用 headless service(没有 service ip 的 service)

​ 在使用 Deployment 时,创建的 Pod 名称是没有顺序的,是随机字符串,在用 statefulset 管理pod 时要求 pod 名称必须是有序的 ,每一个 pod 不能被随意取代,pod 重建后 pod 名称还是一样的。因为 pod IP 是变化的,所以要用 Pod 名称来识别。pod 名称是 pod 唯一性的标识符,必须持久稳定有效。这时候要用到无头服务,它可以给每个 Pod 一个唯一的名称。

  1. headless service 会为 service 分配一个域名

    ..svc.cluster.local

    K8s 中资源的全局 FQDN 格式:

    Service_NAME.NameSpace_NAME.Domain.LTD.

    Domain.LTD.=svc.cluster.local. #这是默认 k8s 集群的域名。

    FQDN 全称 Fully Qualified Domain Name 即全限定域名:同时带有主机名和域名的名称FQDN = Hostname + DomainName

    如 主机名是 k8s

    域名是 baidu.com

    FQDN= k8s.baidu.com

  2. StatefulSet 会为关联的 Pod 保持一个不变的 Pod Name

    statefulset 中 Pod 的名字格式为 ( S t a t e f u l S e t n a m e ) − (StatefulSet name)- (StatefulSetname)(pod 序号)

  3. StatefulSet 会为关联的 Pod 分配一个 dnsName

    ...svc.cluster.local

为什么要用 volumeClaimTemplate

​ 对于有状态应用都会用到持久化存储,比如 mysql 主从,由于主从数据库的数据是不能存放在一个目录下的,每个 mysql 节点都需要有自己独立的存储空间。而在 deployment 中创建的存储卷是一个共享的存储卷,多个 pod 使用同一个存储卷,它们数据是同步的,而 statefulset 定义中的每一个 pod 都不能使用同一个存储卷,这就需要使用 volumeClainTemplate,当在使用statefulset 创建 pod 时,volumeClainTemplate 会自动生成一个 PVC,从而请求绑定一个PV,每一个 pod 都有自己专用的存储卷。Pod、PVC 和 PV 对应的关系图如下:

image-20240524105957795

资源清单文件编写技巧

#查看定义 Statefulset 资源需要的字段
[root@k8s01 ~]# kubectl explain statefulset
KIND:     StatefulSet
VERSION:  apps/v1

DESCRIPTION:
     StatefulSet represents a set of pods with consistent identities. Identities
     are defined as:
     - Network: A single stable DNS and hostname.
     - Storage: As many VolumeClaims as requested. The StatefulSet guarantees
     that a given network identity will always map to the same storage identity.

FIELDS:
   apiVersion	<string>
   	  #定义 statefulset 资源需要使用的 api 版本

   kind	<string>
   	 #定义的资源类型

   metadata	<Object>
   	 #元数据

   spec	<Object>
   	 #定义容器相关的信息

   status	<Object>
   
  
#查看 statefulset.spec 字段如何定义
[root@k8s01 controller]# kubectl explain statefulset.spec
KIND:     StatefulSet
VERSION:  apps/v1

RESOURCE: spec <Object>

DESCRIPTION:
     Spec defines the desired identities of pods in this set.

     A StatefulSetSpec is the specification of a StatefulSet.

FIELDS:
   podManagementPolicy	<string>
   	 #pod 管理策略

   replicas	<integer>
   	 #副本数

   revisionHistoryLimit	<integer>
   	 #保留的历史版本

   selector	<Object> -required-
   	 #标签选择器,选择它所关联的 pod

   serviceName	<string> -required-
   	 #headless service 的名字

   template	<Object> -required-
   	 #生成 pod 的模板

   updateStrategy	<Object>
   	 #更新策略

   volumeClaimTemplates	<[]Object>
   	 #存储卷申请模板
   	 
   	 
#查看 statefulset 的 spec.template 字段如何定义
[root@k8s01 controller]# kubectl explain statefulset.spec.template
KIND:     StatefulSet
VERSION:  apps/v1

RESOURCE: template <Object>

DESCRIPTION:
     template is the object that describes the pod that will be created if
     insufficient replicas are detected. Each pod stamped out by the StatefulSet
     will fulfill this Template, but have a unique identity from the rest of the
     StatefulSet.

     PodTemplateSpec describes the data a pod should have when created from a
     template

FIELDS:
   metadata	<Object>

   spec	<Object>
   	 #定义容器属性的

​ 通过上面可以看到,statefulset 资源中有两个 spec 字段。第一个 spec 声明的是 statefulset 定义多少个 Pod 副本(默认将仅部署 1 个 Pod)、匹配 Pod 标签的选择器、创建 pod 的模板、存储卷申请模板,第二个 spec 是 spec.template.spec:主要用于 Pod 里的容器属性等配置。.spec.template 里的内容是声明 Pod 对象时要定义的各种属性,所以这部分也叫做PodTemplate(Pod 模板)。还有一个值得注意的地方是:在.spec.selector 中定义的标签选择器必须能够匹配到 spec.template.metadata.labels 里定义的 Pod 标签,否则 Kubernetes 将不允许创建 statefulset

使用案例

#创建存储类

class-web.yaml

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: nfs-web
provisioner: example.com/nfs

#编写一个 Statefulset 资源清单文件

statefulset.yaml

apiVersion: v1
kind: Service
metadata:
  name: nginx
spec:
  selector:
    app: nginx
  ports:
    - protocol: TCP
      port: 80
  type: ClusterIP
  clusterIP: None
  
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: nginx
  labels:
    app: nginx

spec:
  selector:
    matchLabels:
      app: nginx
  serviceName: nginx
  replicas: 2
  template:
    metadata:
      name: web
      labels:
        app: nginx
    spec:
      containers:
        - name: nginx
          image: nginx
          imagePullPolicy: IfNotPresent
          ports:
            - containerPort: 80
              name: web
          volumeMounts:
            - mountPath: /usr/share/nginx/html
              name: www
  volumeClaimTemplates:
    - metadata:
        name: www
      spec:
        accessModes:
          - ReadWriteOnce
        storageClassName: nfs-web
        resources:
          requests:
            storage: 1Gi
#更新资源清单文件
[root@k8s01 controller]# kubectl apply -f statefulset.yaml 
service/nginx created
statefulset.apps/nginx created
#查看 statefulset 是否创建成功
[root@k8s01 controller]# kubectl get statefulset
NAME   READY   AGE
web    2/2     31s
#查看 pod
[root@k8s01 controller]# kubectl get pods
NAME                               READY   STATUS    RESTARTS   AGE
nfs-provisioner-554f9cf4cf-jvhc4   1/1     Running   0          20h
web-0                              1/1     Running   0          9s
web-1                              1/1     Running   0          5s
#通过上面可以看到创建的 pod 是有序的

#查看 headless service
[root@k8s01 controller]# kubectl get svc
NAME         TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
kubernetes   ClusterIP   10.96.0.1    <none>        443/TCP   4d23h
nginx        ClusterIP   None         <none>        80/TCP    63s

#查看 pvc
[root@k8s01 controller]# kubectl get pvc
NAME        STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   AGE
www-web-0   Bound    pvc-d6b273fa-db09-43a3-b32f-9016328b2407   1Gi        RWO            nfs-web        91s
www-web-1   Bound    pvc-20a7f417-e973-41be-b190-d9999637029d   1Gi        RWO            nfs-web        87s
#查看 pv
[root@k8s01 controller]# kubectl get pv
NAME                                       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM               STORAGECLASS   REASON   AGE
pvc-20a7f417-e973-41be-b190-d9999637029d   1Gi        RWO            Delete           Bound    default/www-web-1   nfs-web                 94s
pvc-d6b273fa-db09-43a3-b32f-9016328b2407   1Gi        RWO            Delete           Bound    default/www-web-0   nfs-web                 98s

#查看 pod 主机名
[root@k8s01 controller]# for i in 0 1;do kubectl exec web-$i -- sh -c 'hostname';done
web-0
web-1

#使用 kubectl run 运行一个提供 nslookup 命令的容器的,这个命令来自于 dnsutils 包,通过对 pod 主机名执行 nslookup,可以检查它们在集群内部的 DNS 地址:
[root@k8s01 controller]# kubectl exec -it web-0 -- /bin/bash
root@web-0:/# apt-get update
root@web-0:/# apt-get install dnsutils -y

root@web-0:/# nslookup web-1.nginx.default.svc.cluster.local
Server:		10.96.0.10
Address:	10.96.0.10#53
#statefulset 创建的 pod 也是有 dns 记录的
Name:	web-1.nginx.default.svc.cluster.local
Address: 10.244.236.184


root@web-0:/# nslookup nginx.default.svc.cluster.local
Server:		10.96.0.10
Address:	10.96.0.10#53
#查询 service dns,会把对应的 pod ip 解析出来
Name:	nginx.default.svc.cluster.local
Address: 10.244.236.183
Name:	nginx.default.svc.cluster.local
Address: 10.244.236.184

管理 pod

  • 动态扩容

    ​ 如果我们觉得两个副本太少了,想要增加,只需要修改配置文件 statefulset.yaml 里的 replicas的值即可,原来 replicas: 2,现在变成 replicaset: 3,修改之后,执行如下命令更新:

    [root@k8s01 controller]# kubectl apply -f statefulset.yaml 
    service/nginx unchanged
    statefulset.apps/web configured
    [root@k8s01 controller]# kubectl get sts
    NAME   READY   AGE
    web    3/3     12m
    [root@k8s01 controller]# kubectl get pods
    NAME                               READY   STATUS    RESTARTS   AGE
    nfs-provisioner-554f9cf4cf-jvhc4   1/1     Running   0          20h
    web-0                              1/1     Running   0          12m
    web-1                              1/1     Running   0          12m
    web-2                              1/1     Running   0          28s
    

    ​ 也可以直接编辑控制器实现扩容

    #这个是我们把请求提交给了 apiserver,实时修改
    # spec 下的 replicas 后面的值改成 4,保存退出
    [root@k8s01 controller]# kubectl edit sts web
    statefulset.apps/web edited
    [root@k8s01 controller]# kubectl get pods
    NAME                               READY   STATUS    RESTARTS   AGE
    nfs-provisioner-554f9cf4cf-jvhc4   1/1     Running   0          20h
    web-0                              1/1     Running   0          14m
    web-1                              1/1     Running   0          14m
    web-2                              1/1     Running   0          115s
    web-3                              1/1     Running   0          24s
    
  • 动态缩容

    ​ 如果我们觉得 4 个 Pod 副本太多了,想要减少,只需要修改配置文件 statefulset.yaml 里的replicas 的值即可,把 replicaset:4 变成 replicas: 2,修改之后,执行如下命令更新:

    [root@k8s01 controller]# kubectl apply  -f statefulset.yaml 
    service/nginx unchanged
    statefulset.apps/web configured
    [root@k8s01 controller]# kubectl get pods
    NAME                               READY   STATUS    RESTARTS   AGE
    nfs-provisioner-554f9cf4cf-jvhc4   1/1     Running   0          20h
    web-0                              1/1     Running   0          15m
    web-1                              1/1     Running   0          15m
    
    
  • 更新

    myapp.tar.gz 上传到 k8s02 上和 k8s03,手动解压

    [root@k8s02 images]# docker load -i myapp.tar.gz
    [root@k8s03 images]# docker load -i myapp.tar.gz
    

    修改镜像 nginx 变成- image: ikubernetes/myapp:v2,修改之后保存退出

    [root@k8s01 images]# kubectl edit sts web
    statefulset.apps/web edited
    [root@k8s01 images]# kubectl get pods -o wide
    NAME                               READY   STATUS    RESTARTS   AGE   IP               NODE    NOMINATED NODE   READINESS GATES
    nfs-provisioner-554f9cf4cf-jvhc4   1/1     Running   0          20h   10.244.236.176   k8s02   <none>           <none>
    web-0                              1/1     Running   0          10s   10.244.236.186   k8s02   <none>           <none>
    web-1                              1/1     Running   0          16s   10.244.236.185   k8s02   <none>           <none>
    #查看 pod 详细信息
    [root@k8s01 images]# kubectl describe pods web-0
    

    image-20240524114252330

    通过上面可以看到 pod 已经使用刚才更新的镜像 ikubernetes/myapp:v2 了

f statefulset.yaml
service/nginx unchanged
statefulset.apps/web configured
[root@k8s01 controller]# kubectl get pods
NAME READY STATUS RESTARTS AGE
nfs-provisioner-554f9cf4cf-jvhc4 1/1 Running 0 20h
web-0 1/1 Running 0 15m
web-1 1/1 Running 0 15m




- 更新

myapp.tar.gz 上传到 k8s02 上和 k8s03,手动解压

```shell
[root@k8s02 images]# docker load -i myapp.tar.gz
[root@k8s03 images]# docker load -i myapp.tar.gz

修改镜像 nginx 变成- image: ikubernetes/myapp:v2,修改之后保存退出

[root@k8s01 images]# kubectl edit sts web
statefulset.apps/web edited
[root@k8s01 images]# kubectl get pods -o wide
NAME                               READY   STATUS    RESTARTS   AGE   IP               NODE    NOMINATED NODE   READINESS GATES
nfs-provisioner-554f9cf4cf-jvhc4   1/1     Running   0          20h   10.244.236.176   k8s02   <none>           <none>
web-0                              1/1     Running   0          10s   10.244.236.186   k8s02   <none>           <none>
web-1                              1/1     Running   0          16s   10.244.236.185   k8s02   <none>           <none>
#查看 pod 详细信息
[root@k8s01 images]# kubectl describe pods web-0

[外链图片转存中…(img-SF6vULq3-1719910287075)]

通过上面可以看到 pod 已经使用刚才更新的镜像 ikubernetes/myapp:v2 了

Logo

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

更多推荐