# K8s 资源调度 deployment、statefulset、daemonset

# 1. 无状态应用管理 Deployment

[root@k8s-master01 ~]# cat nginx-deploy.yaml 
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deploy
  labels:
    app: nginx-deploy
  annotations:
    app: nginx-deploy
  namespace: default
spec:
  selector:
    matchLabels:
      app: nginx-deploy
  replicas: 3
  template:
    metadata:
      labels:
        app: nginx-deploy
    spec:
      containers:
        - name: nginx-deploy
          image: nginx:1.21.0
          imagePullPolicy: IfNotPresent
      restartPolicy: Always

示例解析:

  1. nginx-deploy:Deployment 的名称;

  2. replicas: 创建 Pod 的副本数;

  3. selector:定义 Deployment 如何找到要管理的 Pod,与 template 的 label(标签)对应,apiVersion 为 apps/v1 必须指定该字段;

  4. template 字段包含以下字段:

    • app: nginx-deploy 使用 label(标签)标记 Pod;

    • spec:表示 Pod 运行一个名字为 nginx 的容器;

    • image:运行此 Pod 使用的镜像;

    • Port:容器用于发送和接收流量的端口。

# 1.1 更新 Deployment

假如更新 Nginx Pod 的 image 使用 nginx:latest,并使用 --record 记录当前更改的参数,后期回滚时可以查看到对应的信息:

[root@k8s-master01 ~]# kubectl set image deployment nginx-deploy nginx-deploy=nginx:latest --record

更新过程为新旧交替更新,首先新建一个 Pod,当 Pod 状态为 Running 时,删除一个旧的 Pod,同时再创建一个新的 Pod。当触发一个更新后,会有新的 ReplicaSet 产生,旧的 ReplicaSet 会被保存,查看此时 ReplicaSet,可以从 AGE 或 READY 看出来新旧 ReplicaSet:

[root@k8s-master01 ~]# kubectl get rs
NAME                      DESIRED   CURRENT   READY   AGE
nginx-deploy-65bfb77869   0         0         0       50s
nginx-deploy-85b94dddb4   3         3         3       8s

通过 describe 查看 Deployment 的详细信息:

[root@k8s-master01 ~]#  kubectl describe deploy nginx-deploy
Name:                   nginx-deploy
Namespace:              default
CreationTimestamp:      Mon, 14 Apr 2025 11:28:03 +0800
Labels:                 app=nginx-deploy
Annotations:            app: nginx-deploy
                        deployment.kubernetes.io/revision: 2
                        kubernetes.io/change-cause: kubectl set image deployment nginx-deploy nginx-deploy=nginx:latest --record=true
Selector:               app=nginx-deploy
Replicas:               3 desired | 3 updated | 3 total | 3 available | 0 unavailable
StrategyType:           RollingUpdate
MinReadySeconds:        0
RollingUpdateStrategy:  25% max unavailable, 25% max surge
Pod Template:
  Labels:  app=nginx-deploy
  Containers:
   nginx-deploy:
    Image:         nginx:latest
    Port:          <none>
    Host Port:     <none>
    Environment:   <none>
    Mounts:        <none>
  Volumes:         <none>
  Node-Selectors:  <none>
  Tolerations:     <none>
Conditions:
  Type           Status  Reason
  ----           ------  ------
  Available      True    MinimumReplicasAvailable
  Progressing    True    NewReplicaSetAvailable
OldReplicaSets:  nginx-deploy-65bfb77869 (0/0 replicas created)
NewReplicaSet:   nginx-deploy-85b94dddb4 (3/3 replicas created)
Events:
  Type    Reason             Age   From                   Message
  ----    ------             ----  ----                   -------
  Normal  ScalingReplicaSet  71s   deployment-controller  Scaled up replica set nginx-deploy-65bfb77869 from 0 to 3
  Normal  ScalingReplicaSet  29s   deployment-controller  Scaled up replica set nginx-deploy-85b94dddb4 from 0 to 1
  Normal  ScalingReplicaSet  28s   deployment-controller  Scaled down replica set nginx-deploy-65bfb77869 from 3 to 2
  Normal  ScalingReplicaSet  28s   deployment-controller  Scaled up replica set nginx-deploy-85b94dddb4 from 1 to 2
  Normal  ScalingReplicaSet  27s   deployment-controller  Scaled down replica set nginx-deploy-65bfb77869 from 2 to 1
  Normal  ScalingReplicaSet  27s   deployment-controller  Scaled up replica set nginx-deploy-85b94dddb4 from 2 to 3
  Normal  ScalingReplicaSet  26s   deployment-controller  Scaled down replica set nginx-deploy-65bfb77869 from 1 to 0

在 describe 中可以看出,第一次创建时,它创建了一个名为 nginx-deploy-65bfb77869 的 ReplicaSet,并直接将其扩展为 3 个副本。更新部署时,它创建了一个新的 ReplicaSet,命名为 nginx-deploy-85b94dddb4,并将其副本数扩展为 1,然后将旧的 ReplicaSet 缩小为 2,这样至少可以有 2 个 Pod 可用,最多创建了 4 个 Pod。以此类推,使用相同的滚动更新策略向上和向下扩展新旧 ReplicaSet,最终新的 ReplicaSet 可以拥有 3 个副本,并将旧的 ReplicaSet 缩小为 0。

# 1.2 回滚 Deployment

当更新了版本不稳定或配置不合理时,可以对其进行回滚操作,假设我们又进行了几次更新(此处以更新镜像版本触发更新,更改配置效果类似):

# kubectl set image deployment nginx-deploy nginx-deploy=nginx:1.21.1 --record
# kubectl set image deployment nginx-deploy nginx-deploy=nginx:1.21.2 --record

使用 kubectl rollout history 查看更新历史:

[root@k8s-master01 ~]# kubectl rollout history deployment nginx-deploy
deployment.apps/nginx-deploy 
REVISION  CHANGE-CAUSE
1         <none>
2         kubectl set image deployment nginx-deploy nginx-deploy=nginx:latest --record=true
3         kubectl set image deployment nginx-deploy nginx-deploy=nginx:1.21.1 --record=true
4         kubectl set image deployment nginx-deploy nginx-deploy=nginx:1.21.2 --record=true

查看 Deployment 某次更新的详细信息,使用 --revision 指定某次更新版本号:

# kubectl rollout history deployment nginx-deploy --revision=4
deployment.apps/nginx-deploy with revision #4
Pod Template:
  Labels:	app=nginx-deploy
	pod-template-hash=65b576b795
  Annotations:	kubernetes.io/change-cause: kubectl set image deployment nginx-deploy nginx-deploy=nginx:1.21.2 --record=true
  Containers:
   nginx-deploy:
    Image:	nginx:1.21.2
    Port:	<none>
    Host Port:	<none>
    Environment:	<none>
    Mounts:	<none>
  Volumes:	<none>
  Node-Selectors:	<none>
  Tolerations:	<none>

如果只需要回滚到上一个稳定版本,使用 kubectl rollout undo 即可:

# kubectl rollout undo deployment nginx-deploy

再次查看更新历史,发现 REVISION3 回到了 nginx:1.21.1:

# kubectl rollout history deployment nginx-deploy
deployment.apps/nginx-deploy 
REVISION  CHANGE-CAUSE
1         <none>
2         kubectl set image deployment nginx-deploy nginx-deploy=nginx:latest --record=true
4         kubectl set image deployment nginx-deploy nginx-deploy=nginx:1.21.2 --record=true
5         kubectl set image deployment nginx-deploy nginx-deploy=nginx:1.21.1 --record=true

如果要回滚到指定版本,使用 --to-revision 参数:

# kubectl rollout undo deployment nginx-deploy --to-revision=2
# 1.3 扩容 Deployment

当公司访问量变大,或者有预期内的活动时,三个 Pod 可能已无法支撑业务时,可以提前对其进行扩展。

使用 kubectl scale 动态调整 Pod 的副本数,比如增加 Pod 为 5 个:

# kubectl scale deployment nginx-deploy --replicas=5

查看 Pod,此时 Pod 已经变成了 5 个:

# kubectl get pods
NAME                            READY   STATUS    RESTARTS   AGE
nginx-deploy-85b94dddb4-2qrh6   1/1     Running   0          2m9s
nginx-deploy-85b94dddb4-gvkqj   1/1     Running   0          2m10s
nginx-deploy-85b94dddb4-mdfjs   1/1     Running   0          22s
nginx-deploy-85b94dddb4-rhgpr   1/1     Running   0          2m8s
nginx-deploy-85b94dddb4-vwjhl   1/1     Running   0          22s
# 1.4 暂停和恢复 Deployment 更新

上述演示的均为更改某一处的配置,更改后立即触发更新,大多数情况下可能需要针对一个资源文件更改多处地方,而并不需要多次触发更新,此时可以使用 Deployment 暂停功能,临时禁用更新操作,对 Deployment 进行多次修改后在进行更新。

使用 kubectl rollout pause 命令即可暂停 Deployment 更新:

# kubectl rollout pause deployment nginx-deploy

然后对 Deployment 进行相关更新操作,比如先更新镜像,然后对其资源进行限制(如果使用的是 kubectl edit 命令,可以直接进行多次修改,无需暂停更新,kubectlset 命令一般会集成在 CICD 流水线中):

# kubectl set image deployment nginx-deploy nginx-deploy=nginx:1.21.3
# kubectl set resources deployment nginx-deploy -c=nginx-deploy --limits=cpu=200m,memory=512Mi

通过 rollout history 可以看到没有新的更新:

#  kubectl rollout history deployment nginx-deploy

进行完最后一处配置更改后,使用 kubectl rollout resume 恢复 Deployment 更新:

# kubectl rollout resume deployment nginx-deploy

可以查看到恢复更新的 Deployment 创建了一个新的 RS(ReplicaSet 缩写):

# kubectl get rs

可以查看 Deployment 的 image(镜像)已经变为 nginx:1.21.3

[root@k8s-master01 ~]# kubectl get pods -oyaml|grep image
    - image: nginx:1.21.3
      imagePullPolicy: IfNotPresent
      image: docker.io/library/nginx:1.21.3
      imageID: docker.io/library/nginx@sha256:644a70516a26004c97d0d85c7fe1d0c3a67ea8ab7ddf4aff193d9f301670cf36
    - image: nginx:1.21.3
      imagePullPolicy: IfNotPresent
      image: docker.io/library/nginx:1.21.3
      imageID: docker.io/library/nginx@sha256:644a70516a26004c97d0d85c7fe1d0c3a67ea8ab7ddf4aff193d9f301670cf36
    - image: nginx:1.21.3
      imagePullPolicy: IfNotPresent
      image: docker.io/library/nginx:1.21.3
      imageID: docker.io/library/nginx@sha256:644a70516a26004c97d0d85c7fe1d0c3a67ea8ab7ddf4aff193d9f301670cf36
    - image: nginx:1.21.3
      imagePullPolicy: IfNotPresent
      image: docker.io/library/nginx:1.21.3
      imageID: docker.io/library/nginx@sha256:644a70516a26004c97d0d85c7fe1d0c3a67ea8ab7ddf4aff193d9f301670cf36
    - image: nginx:1.21.3
      imagePullPolicy: IfNotPresent
      image: docker.io/library/nginx:1.21.3
      imageID: docker.io/library/nginx@sha256:644a70516a26004c97d0d85c7fe1d0c3a67ea8ab7ddf4aff193d9f301670cf36
# 1.5 更新 Deployment 的注意事项

在默认情况下,revision 保留 10 个旧的 ReplicaSet,其余的将在后台进行垃圾回收,可以在.spec.revisionHistoryLimit 设置保留 ReplicaSet 的个数。当设置为 0 时,不保留历史记录。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deploy
  namespace: default
  labels:
    app: nginx-deploy
spec:
  replicas: 5
  selector:
    matchLabels:
      app: nginx-deploy
  template:
    metadata:
      labels:
        app: nginx-deploy
    spec:
      containers:
        - name: nginx-deploy
          image: nginx:1.21.3
          resources:
            limits:
              cpu: 200m
              memory: 512Mi
          imagePullPolicy: IfNotPresent
      restartPolicy: Always
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxUnavailable: 25%
      maxSurge: 25%
  revisionHistoryLimit: 10

更新策略:

  • spec.strategy.type==Recreate,表示重建,先删掉旧的 Pod 再创建新的 Pod;
  strategy:
    type: Recreate
  • spec.strategy.type==RollingUpdate,表示滚动更新,可以指定 maxUnavailable 和 maxSurge 来控制滚动更新过程;

    • spec.strategy.rollingUpdate.maxUnavailable,指定在回滚更新时最大不可用的 Pod 数量,可选字段,默认为 25%,可以设置为数字或百分比,如果 maxSurge 为 0,则该值不能为 0;

    • spec.strategy.rollingUpdate.maxSurge 可以超过期望值的最大 Pod 数,可选字段,默认为 25%,可以设置成数字或百分比,如果 maxUnavailable 为 0,则该值不能为 0。

  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxUnavailable: 25%
      maxSurge: 25%

# 2. 有状态应用管理 StatefulSet

apiVersion: v1
kind: Service
metadata:
  name: web
  namespace: default
spec:
  ports:
    - port: 80
      targetPort: 80
      protocol: TCP
      name: http
  selector:
    app: nginx
  type: ClusterIP
  clusterIP: None
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: nginx
  namespace: default
  labels:
    app: nginx
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
        - name: nginx
          image: nginx:latest
          resources:
            limits:
              cpu: '1'
              memory: 1Gi
            requests:
              cpu: 100m
              memory: 128Mi
      restartPolicy: Always
  serviceName: web
  • kind: Service 定义了一个名字为 web 的 Headless Service,创建的 Service 格式为 nginx-0.web.default.svc.cluster.local,其他的类似,因为没有指定 Namespace(命名空间),所以默认部署在 default;
  • kind: StatefulSet 定义了一个名字为 nginx 的 StatefulSet,replicas 表示部署 Pod 的副本数,本实例为 3。
# 2.1 创建 StatefulSet
[root@k8s-master01 ~]# kubectl get pods
NAME      READY   STATUS    RESTARTS   AGE
nginx-0   1/1     Running   0          8m51s
nginx-1   1/1     Running   0          8m50s
nginx-2   1/1     Running   0          8m48s
[root@k8s-master01 ~]# kubectl get svc
NAME         TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
kubernetes   ClusterIP   10.96.0.1    <none>        443/TCP   6d1h
web          ClusterIP   None         <none>        80/TCP    9m28s
[root@k8s-master01 ~]# kubectl get sts
NAME    READY   AGE
nginx   3/3     8m58s
# 2.2 StatefulSet 创建 Pod 流程

StatefulSet 管理的 Pod 部署和扩展规则如下:

  • 对于具有 N 个副本的 StatefulSet,将按顺序从 0 到 N-1 开始创建 Pod;
  • 当删除 Pod 时,将按照 N-1 到 0 的反顺序终止;
  • 在缩放 Pod 之前,必须保证当前的 Pod 是 Running(运行中)或者 Ready(就绪);
  • 在终止 Pod 之前,它所有的继任者必须是完全关闭状态。

StatefulSet 的 pod.Spec.TerminationGracePeriodSeconds(终止 Pod 的等待时间)不应该指定为 0,设置为 0 对 StatefulSet 的 Pod 是极其不安全的做法,优雅地删除 StatefulSet 的 Pod 是非常有必要的,而且是安全的,因为它可以确保在 Kubelet 从 APIServer 删除之前,让 Pod 正常关闭。

当创建上面的 Nginx 实例时,Pod 将按 nginx-0、nginx-1、nginx-2 的顺序部署 3 个 Pod。在 nginx-0 处于 Running 或者 Ready 之前,nginx-1 不会被部署,相同的,nginx-2 在 web-1 未处于 Running 和 Ready 之前也不会被部署。如果在 nginx-1 处于 Running 和 Ready 状态时,nginx-0 变成 Failed 失败)状态,那么 nginx-2 将不会被启动,直到 nginx-0 恢复为 Running 和 Ready 状态。

如果用户将 StatefulSet 的 replicas 设置为 1,那么 nginx-2 将首先被终止,在完全关闭并删除 nginx-2 之前,不会删除 nginx-1。如果 nginx-2 终止并且完全关闭后,nginx-0 突然失败,那么在 nginx-0 未恢复成 Running 或者 Ready 时,nginx-1 不会被删除。

# 2.3 tatefulSet 扩容和缩容

和 Deployment 类似,可以通过更新 replicas 字段扩容 / 缩容 StatefulSet,也可以使用 kubectlscale、kubectl edit 和 kubectl patch 来扩容 / 缩容一个 StatefulSet。

# kubectl scale sts nginx --replicas=5
# 2.4 StatefulSet 更新策略

On Delete 策略

OnDelete 更新策略实现了传统(1.7 版本之前)的行为,它也是默认的更新策略。当我们选择这个更新策略并修改 StatefulSet 的.spec.template 字段时,StatefulSet 控制器不会自动更新 Pod,必须手动删除 Pod 才能使控制器创建新的 Pod。

  updateStrategy:
    type: OnDelete

RollingUpdate 策略

RollingUpdate(滚动更新)更新策略会自动更新一个 StatefulSet 中所有的 Pod,采用与序号索引相反的顺序进行滚动更新。

  updateStrategy:
    type: RollingUpdate
    rollingUpdate:
      partition: 0
# 2.5 分段更新

将分区改为 2,此时会自动更新 nginx-2、nginx-3、nginx-4(因为之前更改了更新策略),但是不会更新 nginx-0 和 nginx-1:

  updateStrategy:
    type: RollingUpdate
    rollingUpdate:
      partition: 2

将 sts 镜像为 nginx:1.21.1

# kubectl set image sts nginx nginx=nginx:1.21.1

按照上述方式,可以实现分阶段更新,类似于灰度 / 金丝雀发布。查看最终的结果如下:

[root@k8s-master01 ~]# kubectl get pods -oyaml|grep image
    - image: nginx:latest
      imagePullPolicy: IfNotPresent
      image: docker.io/library/nginx:latest
      imageID: docker.io/library/nginx@sha256:fad8e1cd52e24bce7b72cd7cb674a2efad671647b917055f5bd8a1f7ac9b1af8
    - image: nginx:latest
      imagePullPolicy: IfNotPresent
      image: docker.io/library/nginx:latest
      imageID: docker.io/library/nginx@sha256:fad8e1cd52e24bce7b72cd7cb674a2efad671647b917055f5bd8a1f7ac9b1af8
    - image: nginx:1.21.1
      imagePullPolicy: IfNotPresent
      image: docker.io/library/nginx:1.21.1
      imageID: docker.io/library/nginx@sha256:a05b0cdd4fc1be3b224ba9662ebdf98fe44c09c0c9215b45f84344c12867002e
    - image: nginx:1.21.1
      imagePullPolicy: IfNotPresent
      image: docker.io/library/nginx:1.21.1
      imageID: docker.io/library/nginx@sha256:a05b0cdd4fc1be3b224ba9662ebdf98fe44c09c0c9215b45f84344c12867002e
    - image: nginx:1.21.1
      imagePullPolicy: IfNotPresent
      image: docker.io/library/nginx:1.21.1
      imageID: docker.io/library/nginx@sha256:a05b0cdd4fc1be3b224ba9662ebdf98fe44c09c0c9215b45f84344c12867002e
# 2.6 StatefulSet 挂载动态存储
apiVersion: v1
kind: Service
metadata:
  name: nginx
  labels:
    app: nginx
spec:
  ports:
  - port: 80
    name: web
  clusterIP: None
  selector:
    app: nginx
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: web
spec:
  selector:
    matchLabels:
      app: nginx 
  serviceName: "nginx"
  replicas: 3 1
  template:
    metadata:
      labels:
        app: nginx 
    spec:
      containers:
      - name: nginx
        image: nginx:1.20
        ports:
        - containerPort: 80
          name: web
        volumeMounts:
        - name: www
          mountPath: /usr/share/nginx/html
  volumeClaimTemplates:
  - metadata:
      name: www
    spec:
      accessModes: [ "ReadWriteOnce" ]
      storageClassName: "rook-ceph-block"
      resources:
        requests:
          storage: 10Gi

# 3. 守护进程集 DaemonSet

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: nginx-ds
  labels:
    app: nginx-ds
  namespace: default
spec:
  selector:
    matchLabels:
      app: nginx-ds
  template:
    metadata:
      labels:
        app: nginx-ds
    spec:
      containers:
        - name: nginx-ds
          image: nginx:latest
          imagePullPolicy: IfNotPresent
          resources:
            limits:
              memory: 1024Mi
              cpu: 1
            requests:
              memory: 128Mi
              cpu: 100m

此时会在每个节点创建一个 Pod:

[root@k8s-master01 ~]# kubectl get pods -o wide
NAME             READY   STATUS    RESTARTS   AGE   IP               NODE           NOMINATED NODE   READINESS GATES
nginx-ds-47dxc   1/1     Running   0          56s   172.16.85.213    k8s-node01     <none>           <none>
nginx-ds-4m89f   1/1     Running   0          56s   172.16.32.143    k8s-master01   <none>           <none>
nginx-ds-mtpc2   1/1     Running   0          56s   172.16.195.12    k8s-master03   <none>           <none>
nginx-ds-t5rxc   1/1     Running   0          56s   172.16.122.142   k8s-master02   <none>           <none>
nginx-ds-x86kc   1/1     Running   0          56s   172.16.58.222    k8s-node02     <none>           <none>

指定节点部署 Pod

      nodeSelector:
        ingress: 'true'

更新和回滚 DaemonSet

# kubectl set image ds nginx-ds nginx-ds=1.21.0 --record=true
# kubectl rollout undo daemonset <daemonset-name> --to-revision=<revision>

DaemonSet 的更新和回滚与 Deployment 类似,此处不再演示。

# 4. HPA

创建 deployment、service

apiVersion: v1
kind: Service
metadata:
  name: nginx-hpa-svc
  namespace: default
spec:
  ports:
    - port: 80
      targetPort: 80
      protocol: TCP
      name: http
  selector:
    app: nginx-hpa
  type: ClusterIP

---

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-hpa
  labels:
    app: nginx-hpa
  namespace: default
spec:
  selector:
    matchLabels:
      app: nginx-hpa
  replicas: 1
  template:
    metadata:
      labels:
        app: nginx-hpa
    spec:
      restartPolicy: Always
      containers:
        - name: nginx-hpa
          image: nginx:latest
          imagePullPolicy: IfNotPresent
          resources:
            limits:
              memory: 1024Mi
              cpu: 1
            requests:
              memory: 128Mi
              cpu: 100m

创建 HPA

# kubectl autoscale deployment nginx-hpa --cpu-percent=10 --min=1 --max=10
# kubectl get hpa
NAME        REFERENCE              TARGETS       MINPODS   MAXPODS   REPLICAS   AGE
nginx-hpa   Deployment/nginx-hpa   cpu: 0%/10%   1         10        1          16s

测试自动扩缩容

while true; do wget -q -O- http://10.96.18.221 > /dev/null; done
[root@k8s-master01 ~]# kubectl get pods
NAME                        READY   STATUS    RESTARTS   AGE
nginx-hpa-d8bcbdf7d-4mkxp   1/1     Running   0          66s
nginx-hpa-d8bcbdf7d-974q5   1/1     Running   0          6m36s
nginx-hpa-d8bcbdf7d-g6p2h   1/1     Running   0          66s
nginx-hpa-d8bcbdf7d-lvvsq   1/1     Running   0          111s
nginx-hpa-d8bcbdf7d-tgqmr   1/1     Running   0          111s
nginx-hpa-d8bcbdf7d-tzfbs   1/1     Running   0          21s

本文出自于:https://edu.51cto.com/course/23845.html

此文章已被阅读次数:正在加载...更新于

请我喝[茶]~( ̄▽ ̄)~*

Xu Yong 微信支付

微信支付

Xu Yong 支付宝

支付宝