K8S:几种资源调度方式-RC/RS/Deployment/StatefulSet/DaemonSet

发布时间 2023-10-09 17:11:13作者: ShineLe

学习自:k8s资源调度-RC/RS/Deployment/StatefulSet/DaemonSet - 知乎

使用Deployment、StatefulSet部署应用__GalenZhang888的博客-CSDN博客

https://blog.csdn.net/zf14840/article/details/128367067

https://blog.51cto.com/u_15746412/7000073

前言

下文会经常提到状态一词:

Deployment用于部署无状态服务,是最常用的控制器

STS是有状态集,常用于部署有状态且需要有序启动的应用程序。

这里的状态是什么意思?

有状态:如Redis这种,存在主从节点,会选举出一个M节点工作。

无状态:所有节点地位平等,多台同时协作工作。

Replication Controller(RC)

RC通过Label控制Pod的创建和销毁,它可以保证任何时候都有指定数量的Pod副本在运行。这一点通过RC的yaml中的spec.replicas来确定。

如果存在的Pod>replicas,那么RC会终止多余的Pod。反之会启动更多的Pod来保证达到期望值。

因此在管理Pod时,哪怕应用程序只需要一个Pod,也建议用RC这种自动管理方式来管理Pod。RC所管理的Pod不限于某个Node,而是监视K8S集群的多个Node上的多个Pod。

一个RC的yaml:

apiVersion: v1
kind: ReplicationController
metadata:
  name: nginx
spec:
  replicas: 3 #副本数
  selector:
    app: nginx
  template:
    metadata:
      name: nginx
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx
        ports:
        - containerPort: 80  

ReplicaSet(RS)

RS可以视为RC的优化版,除了具有RC的功能——协调创建、删除、更新Pod之外,与RC唯一的区别在于:RS支持灵活的Label Selector,RC的LS只支持选择某个确定标签,而RS可以以集合的方式选择标签(通过spec.selector.matchExpressions进行),使用这种集合方式可以实现RollingUpdate

后续的Deployment也是通过RS实现了Pod副本的自动控制功能。

RS的yaml示例:

apiVersion: apps/v1
kind: ReplicaSet
metadata:
  name: frontend
  labels:
    app: test
    version: v2
spec:
  replicas: 3
  selector:
    matchLabels:
      version: v2
    matchExpressions: #集合式标签选择器,允许同时有v1和v2两个版本的pod。
      - {key: version, operator: In, values: [v1,v2]}
  template:
    metadata:
      labels:
        app: test
        version: v2
    spec:
      containers:
      - name: nginx
        image: nginx:1.15.2
        resources:
          requests:
            cpu: 100m
            memory: 100Mi
        env:
        - name: IS_env
          value: env
        ports:
        - containerPort: 80  

RC和RS是两种简单部署Pod的方式。

它们在创建、删除Pod时的区别不大,生产中也比较少用到,通常使用较为高级的Deployment等进行Pod管理。

Deployment

为了更好地解决Pod编排问题,K8S从1.2版本开始引入了Deployment,在其内部使用了RS来实现这个目的。

Deployment用于部署无状态服务,是最常用的控制器

Deployment相比RC的优势在于可以随时知道Pod部署进度,即当前容器正处于Pod创建、调度、绑定、启动的哪个阶段。

它一般用于管理维护企业内部无状态的微服务,如springboot、configserver。可以管理多个Pod副本无缝迁移、自动扩缩容、灾难恢复、一键回滚等功能。

一个Deployment的yaml文件:

apiVersion: apps/v1
kind: Deployment
metadata:
  annotations:
    deployment.kubernetes.io/revision: "1"
  creationTimestamp: "2021-06-16T07:49:17Z"
  generation: 1
  labels:  #deploy自身的标签
    app: nginx
  name: nginx
  namespace: test-wang
spec:
  progressDeadlineSeconds: 600
  replicas: 1 #副本数
  revisionHistoryLimit: 10 #保留历史记录的次数,设置为0的话,不保留历史数据
  # minReadySeconds: 0 #可选参数,指定新创建的Pod在没有任何容器崩溃的情况下视为Ready最小的秒数,
默认为0,即一旦被创建就视为可用。 selector: #匹配RS,一旦创建就不建议修改,否则RS会脱离deploy的掌控 matchLabels: app: nginx strategy: rollingUpdate: maxSurge: 25% maxUnavailable: 25% type: RollingUpdate
#更新deployment的方式 1.RollingUpdate:滚动更新(默认),可以指定
maxSurge(超过期望值的最大Pod数,默认25%)和maxUnavailable(最大不可用数量,默认25%)
2.Recreate 重建 先删除旧的Pod,在创建新的Pod template: metadata: #匹配Pod,要和匹配RS的一致 creationTimestamp: null labels: app: nginx spec: #和Pod的一致。 containers: - image: nginx:1.15.2 imagePullPolicy: IfNotPresent name: nginx resources: {} terminationMessagePath: /dev/termination-log terminationMessagePolicy: File dnsPolicy: ClusterFirst restartPolicy: Always schedulerName: default-scheduler securityContext: {} terminationGracePeriodSeconds: 30

deployment常用的命令

1、get:查询

kubectl get deploy -n test-wang -o wide
NAME    READY   UP-TO-DATE   AVAILABLE   AGE     CONTAINERS   IMAGES         SELECTOR
nginx   1/1     1            1           5m23s   nginx        nginx:1.15.2   app=nginx

参数-n后跟节点的名字

返回项:

NAME:名称

READY:Pod状态,已经准备和所需的Pod副本数

UP-TO-DATE:最新版本的Pod副本数,指示在RollingUpdate的过程中,有多少Pod已经成功升级

AVAILABLE:已经可用的Pod副本数,即存活的Pod数

AGE:应用程序运行的时间

CONTAINERS:容器名称

IMAGES:镜像

SELECTOR:该Deploy所管理的Pod的Label

2、create:创建

kubectl create -f XXX.yaml

3、set image:更新

kubectl set image deploy nginx nginx=nginx:1.15.3

4、rollout:回滚、查看历史版本

kubectl rollout history deploy nginx #查看历史版本
kubectl rollout undo deploy nginx #回滚到上一个版本
kubectl  rollout history deploy nginx #查看历史记录
kubectl rollout history deploy nginx --revision=3 #查看某个版本的详细信息
kubectl rollout undo deploy nginx --to-revision=3 #回滚到某个版本
kubectl rollout pause deployment nginx #暂停
kubectl rollout resume deploy nginx #恢复

StatefulSet(STS)

STS是有状态集,常用于部署有状态且需要有序启动的应用程序。

STS管理的Pod都有稳定、唯一的网络标识,可以用来发现其他成员

它控制的Pod副本的启停顺序都是受控的,操作第n个Pod时,需要前n-1个Pod都是Ready状态。

它管理的Pod采用稳定的持久化存储,删除时不会删除相关的存储卷,这些卷使用K8S其他资源管理。

例如生产环境中,可以用StatefulSet来部署需要持久化的RabbitMQ、Redis、Kafka集群。这些集群有一些共同特点:每个节点都有固定身份,并且可以通过身份相互通信,规模固定,不随意变动,Pod都是有状态,通常会持久化数据到永久存储,当磁盘损坏时某个节点无法正常运行,使集群功能受损。

StatefulSet和Deploy类似,一个STS也同样管理着相同容器规范的Pod。区别在于STS为每个Pod维护了一个持久标识符,在重新调度时也会保留,一般格式为StatefuleSetName-Number。例如某个STS的名为Redis,指定创建3个Pod,那么创建出来的Pod名为Redis-0、Redis-1、Redis-2

STS创建的Pod间,一般采用Headless Service进行通信,它与普通Service的区别在于Headless Service没有ClusterIP,而是用自定义的EndPoint进行通信。Headless的格式和STS管理的Pod名字格式类似:

statefulSetName-{0..N-1}.serviceName.namespace.svc.cluster.local
  • statefulSetName:STS的名字
  • 0..N-1:Pod序号
  • serviceName:Headless Service的名字
  • namepsace:Service所在命名空间
  • cluster.local:集群域

以一个Redis的例子说明STS的作用

某个项目需要部署主从模式Redis,可以使用STS,因为STS启动Pod时,需要前置Pod已经启动;由于STS中的Pod标识固定,因此用户可以通过标识判断Pod角色。

例如某个STS名为redis-ms,用它来部署主从架构的Redis,第一个容器启动时的标识符redis-ms-0,并且Pod内的主机名也为redis-ms-0,此时就能根据主机名判断,当主机名为redis-ms-0的容器作为Redis的M节点,其余为S节点。那么S连接M时就可以用不会更改的M的Headless Service,此时S的配置文件如下:

port 6379
slaveof redis-ms-0.redis-ms.public-service.svc.cluster.local 6379
tcp-backlog 511
timeout 0
tcp-keepalive 0

注意第二行slaveof,reids-ms-0.xxx.xxx.local就是M的Headless Service,在同一命名空间下只需要写为redis-ms-0.redis-ms即可,后半截可以省略。

STS注意事项

1、一般STS会用于有以下需求的应用程序中:

  • 需要稳定、独一无二的网络标识符
  • 需要持久化数据
  • 需要有序、优雅部署、扩展
  • 需要有序RollingUpdate

如果应用程序不需要稳定标识符、有序扩展,应该使用无状态的控制器部署,例如Deployment或RS。

2、Pod所用的存储必须由PersistentVolume Provisioner(持久化卷配置器)根据请求配置StorageClass,或者由管理员预先配合,当然也可以不配置存储。

3、为了确保数据安全,删除、缩放STS不会删除与STS关联的卷,可以手动选择性地删除PVC和PV;

4、STS采用Headless Service负责Pod的网络身份和通信,需要提前创建该服务;

5、删除一个STS,不保证对Pod的终止,要在STS中实现Pod的有序、正常终止,可以在删除前将STS的副本缩减为0。

STS的yaml文件

apiVersion: v1
kind: Service
metadata:
  name: nginx #Service定义了一个名字为Nginx的Headless Service,k8s所创建的Service格式为nginx-0.nginx.default.svc.cluster.local,其他的类似
  namespace: test-k8s
  labels:
    app: nginx
spec:
  ports:
  - port: 80
    name: web
  clusterIP: None #设置None后不会有clusterIP,但是可以通过无头服务访问到它,不强制要求设置None,可以避免资源的浪费
  selector:
    app: nginx
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: web # StatefulSet定义了一个名字为web的StatefulSet,replicas表示部署Pod的副本数,本实例为2,当StatefulSet控制器创建Pod时,它会添加一个标签statefulset.kubernetes.io/pod-name,该标签的值为Pod的名称,用于匹配Service。
  namespace: test-k8s
spec:
  serviceName: "nginx"
  replicas: 2
  selector: #在StatefulSet中必须设置Pod选择器用来匹配其标签(.spec.template.metadata.labels)。在1.8版本之前,如果未配置该字段,将被设置为默认值,在1.8版本之后,如果未指定匹配Pod Selector,则会导致StatefulSet创建错误
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx
        ports:
        - containerPort: 80
          name: web

sts的常见操作和特性

1、通过get查看STS的Pod,可以发现名称都是xxx-0、xxx-1,如果用exec进去,会发现主机名称也和Pod一致,是固定的。

如果用get查询service,会发现它没有Ip地址

2、扩容sts时,只有web0创建好了才能创建web1,web2,中间任何一个过程出问题都会导致下一个Pod创建失败。

如果在扩容时,删除了中间的某个Pod,那么会先把这个Pod新建再完成后续创建。

缩容时,是从序号较大的开始,如果在该过程中某个序号较小的挂了,那么会等它变为Reday再继续。

3、删除

级联删除:删除sts时删除Pod(默认)

非级联删除:删除STS时不删除Pod

kubectl delete sts web --cascade=false

  

DaemonSet(DS)

DS,守护进程集,在所有节点或匹配的节点上都部署一个Pod。

使用DS的场景:

  • 运行集群存储的Daemon,例如ceph或glusterd;
  • 节点的CNI网络插件,calico
  • 节点日志的收集:fluentd、filebeat
  • 节点监控:node exporter
  • 服务暴露:部署一个ingress nginx

DS的yaml

apiVersion: apps/v1
kind: DaemonSet
metadata:
  labels:
    app: nginx
  name: nginx
  namespace: test-k8s
spec:
  revisionHistoryLimit: 10
  selector:
    matchLabels:
      app: nginx
  updateStrategy: #滚动更新策略
    rollingUpdate:
       maxUnavailabel: 1 #滚动更新时最大不可用数目
    type: RollingUpdate 
  template:
    metadata:
      creationTimestamp: null
      labels:
        app: nginx
    spec:
      containers:
      - image: nginx:1.15.2
        imagePullPolicy: IfNotPresent
        name: nginx
        resources: {}
        terminationMessagePath: /dev/termination-log
        terminationMessagePolicy: File
      dnsPolicy: ClusterFirst
      restartPolicy: Always
      schedulerName: default-scheduler
      securityContext: {}
      terminationGracePeriodSeconds: 30