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

一、Replicaset控制器:概念、原理解读

1.1 Replicaset概述

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


1.2  Replicaset工作原理:如何管理Pod?

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

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

1、用户期望的pod副本数:用来定义由这个控制器管控的pod副本有几个。

2、标签选择器:选定哪些pod是自己管理的,如果通过标签选择器选到的pod副本数量少于我们指定的数量,需要用到下面的组件。

3、pod资源模板:如果集群中现存的pod数量不够我们定义的副本中期望的数量怎么办,需要新建pod,这就需要pod模板,新建的pod是基于模板来创建的。

二、 Replicaset资源清单文件编写技巧

2.1、查看定义Replicaset资源需要的字段有哪些?

帮助命令:kubectl explain replicaset

root@k8s-master:~/K8sStudy/Chapter2-7# kubectl explain replicaset |grep '<*>'
  apiVersion    <string>								#当前资源使用的api版本,跟VERSION:  apps/v1保持一致
  kind  <string>												#资源类型,跟KIND: ReplicaSet保持一致
  metadata      <ObjectMeta>						#元数据,定义Replicaset名字的
  spec  <ReplicaSetSpec>								#定义副本数、定义标签选择器、定义Pod模板
  status        <ReplicaSetStatus>			#状态信息,不能改
root@k8s-master:~/K8sStudy/Chapter2-7#

2.2、查看replicaset的spec字段如何定义?

帮助命令:kubectl explain replicaset.spec

root@k8s-master:~/K8sStudy/Chapter2-7# kubectl explain replicaset.spec |grep '<*>'
FIELD: spec <ReplicaSetSpec>
  minReadySeconds       <integer>
  replicas      <integer>												#定义的pod副本数,根据我们指定的值创建对应数量的pod
  selector      <LabelSelector> -required-			#用于匹配pod的标签选择器,匹配自己管理的pod
  template      <PodTemplateSpec>								#定义Pod的模板,基于这个模板定义的所有pod是一样的
root@k8s-master:~/K8sStudy/Chapter2-7#

2.3、查看replicaset的spec.template字段如何定义?

对于template而言,其内部定义的就是pod,pod模板是一个独立的对象。

帮助命令:kubectl explain replicaset.spec.template

root@k8s-master:~/K8sStudy/Chapter2-7# kubectl explain replicaset.spec.template |grep '<*>'
FIELD: template <PodTemplateSpec>
  metadata      <ObjectMeta>					#元数据,定义pod名字的								
  spec  <PodSpec>											# 定义Pod容器等
root@k8s-master:~/K8sStudy/Chapter2-7#

通过上面可以看到,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。


三、Replicaset使用案例:部署nginx网站

3.1、编写一个ReplicaSet资源清单

root@k8s-master:~/K8sStudy/Chapter2-7# cat Eg-Replicaset.yaml 
apiVersion: apps/v1																				#ReplicaSet 这个控制器属于的核心群组
kind: ReplicaSet 																					#创建的资源类型
metadata:
  name: frontend																					#控制器的名字
  namespace: default
  labels:
    app: nginx
    tier: frontend
spec:
  minReadySeconds: 10
  replicas: 2																							#管理的pod副本数量
  selector:
    matchLabels:
      tier1: frontend1																		#管理带有tie1r=frontend1标签的pod
  template:																								#定义pod的模板
    metadata:
      labels:
        tier1: frontend1																	#pod标签,一定要有,这样上面控制器就能找到它要管理的pod是哪些了
    spec:
      containers:																					#定义pod里运行的容器
      - name: nginx																				#定义容器的名字
        image: docker.io/library/nginx:latest
        imagePullPolicy: IfNotPresent
        ports:																						#定义端口
        - name: nginx																			#定义容器的名字
          containerPort: 80																#定义容器暴露的端口
        startupProbe:
          initialDelaySeconds: 20
          periodSeconds: 5
          timeoutSeconds: 10
          httpGet:
            scheme: HTTP
            port: 80
            path: /
        livenessProbe:
          initialDelaySeconds: 20
          periodSeconds: 5
          timeoutSeconds: 10
          httpGet:
            scheme: HTTP
            port: 80
            path: /
        readinessProbe:
          initialDelaySeconds: 20
          periodSeconds: 5
          timeoutSeconds: 10
          httpGet:
            scheme: HTTP
            port: 80
            path: /

3.2、创建ReplicaSet资源

root@k8s-master:~/K8sStudy/Chapter2-7# kubectl apply -f Eg-Replicaset.yaml 
replicaset.apps/frontend created
root@k8s-master:~/K8sStudy/Chapter2-7# 
root@k8s-master:~/K8sStudy/Chapter2-7# kubectl get replicaset
NAME       DESIRED   CURRENT   READY   AGE
frontend   2         2         2       23m
root@k8s-master:~/K8sStudy/Chapter2-7# 
root@k8s-master:~/K8sStudy/Chapter2-7# kubectl get pod
NAME             READY   STATUS    RESTARTS   AGE
frontend-6rpxl   1/1     Running   0          24m
frontend-7mp87   1/1     Running   0          24m
root@k8s-master:~/K8sStudy/Chapter2-7#

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


四、Replicaset管理pod:扩容、缩容、更新

4.1、Replicaset实现pod的动态扩容

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

root@k8s-master:~/K8sStudy/Chapter2-7# kubectl apply -f Eg-Replicaset.yaml
replicaset.apps/frontend configured
root@k8s-master:~/K8sStudy/Chapter2-7# kubectl get pods
NAME             READY   STATUS    RESTARTS   AGE
frontend-6rpxl   1/1     Running   0          32m
frontend-7mp87   1/1     Running   0          32m
frontend-kz79v   1/1     Running   0          27s
root@k8s-master:~/K8sStudy/Chapter2-7#

4.2、Replicaset实现pod的动态缩容

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

root@k8s-master:~/K8sStudy/Chapter2-7# kubectl apply -f Eg-Replicaset.yaml
replicaset.apps/frontend configured
root@k8s-master:~/K8sStudy/Chapter2-7# kubectl get pods
NAME             READY   STATUS    RESTARTS   AGE
frontend-6rpxl   1/1     Running   0          35m
frontend-7mp87   1/1     Running   0          35m
root@k8s-master:~/K8sStudy/Chapter2-7#

4.3、Replicaset实现pod的更新

更新前pod状态,以及pod运行的web容器访问结果如下。

pod更新前:

pod状态:

K8s控制器Replicaset_ReplicaSet

web容器访问结果如下:

K8s控制器Replicaset_ReplicaSet_02

K8s控制器Replicaset_ReplicaSet_03

更新pod:

修改Eg-Replicaset.yaml中的镜像,将docker.io/library/nginx:latest改为docker.io/library/tomcat:latest,把nginx容器暴露的端口80改为8080,后面的钩子监听的端口也由80改为8080。

修改位置如下:

K8s控制器Replicaset_ReplicaSet_04

使修改的的yaml文件生效。执行kubectl apply -f Eg-Replicaset.yaml

root@k8s-master:~/K8sStudy/Chapter2-7# kubectl apply -f Eg-Replicaset.yaml 
replicaset.apps/frontend configured
root@k8s-master:~/K8sStudy/Chapter2-7#

Pod更新后:

查看pod。

root@k8s-master:~/K8sStudy/Chapter2-7# kubectl get pods -owide
NAME             READY   STATUS    RESTARTS   AGE    IP               NODE       NOMINATED NODE   READINESS GATES
frontend-6rpxl   1/1     Running   0          136m   10.244.113.159   k8s-node   <none>           <none>
frontend-7mp87   1/1     Running   0          136m   10.244.113.158   k8s-node   <none>           <none>
root@k8s-master:~/K8sStudy/Chapter2-7#

上面可以看到,虽然Eg-Replicaset.yaml修改了镜像和一些端口,执行了kubectl apply -fEg-Replicaset.yaml,但是pod还是原来的pod,并没有创建新的pod,没有实现自动更新。

手动删除一个镜像,kubectl delete pods frontend-6rpxl --force, pod的名字写自己实际的名称

root@k8s-master:~/K8sStudy/Chapter2-7# kubectl delete pods frontend-6rpxl --force
Warning: Immediate deletion does not wait for confirmation that the running resource has been terminated. The resource may continue to run on the cluster indefinitely.
pod "frontend-6rpxl" force deleted
root@k8s-master:~/K8sStudy/Chapter2-7#
root@k8s-master:~/K8sStudy/Chapter2-7# kubectl get pods
NAME             READY   STATUS    RESTARTS   AGE
frontend-7gmln   1/1     Running   0          35s
frontend-7mp87   1/1     Running   0          7h31m
root@k8s-master:~/K8sStudy/Chapter2-7# 
root@k8s-master:~/K8sStudy/Chapter2-7# kubectl get pods -owide
NAME             READY   STATUS    RESTARTS   AGE     IP               NODE       NOMINATED NODE   READINESS GATES
frontend-7gmln   1/1     Running   0          64s     10.244.113.164   k8s-node   <none>           <none>
frontend-7mp87   1/1     Running   0          7h32m   10.244.113.158   k8s-node   <none>           <none>
root@k8s-master:~/K8sStudy/Chapter2-7#

重新生成了一个新的pod:frontend-7gmln,IP地址:10.244.113.164

查看更新pod后,新产生的pod的web容器访问结果:

K8s控制器Replicaset_ReplicaSet_05

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

也证明,ReplicaSet在更新了yaml文件后,不会自动更新pod,必须手动删除pod,然后才会生成新的更新后的Pod。

总结:

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