Kubernetes Controllers

环境准备

[root@master30 ~]# kubectl create ns controllers
[root@master30 ~]# kubectl config set-context --current --namespace controllers

Controllers 介绍

Controller 主要作用是确保所管理的资源处于用户期望的状态,通过不断地监控资源的状态,并根据实际状态与期望状态之间的差异执行相应的动作,来实现资源的自愈、自动扩展等功能。

先简单回顾一下:容器按照是否持续运行可分为两类。

  • 服务类容器: 一直运行任务,通常持续提供服务, 比如HTTP等。

  • 工作类容器:一次性任务, 比如批处理程序,完成后容器就退出。

Kubernetes 中用于管理服务类容器的控制器有 ReplicaSet 、Deployment 和 DaemonSet 等。

Kubernetes 中用于管理工作类容器的控制器有 Job 和 CronJob。

ReplicaSets

ReplicaSets 介绍

ReplicaSet,简称RS,是维护一组在任何时候都处于运行状态的 Pod 副本的稳定集合。 因此,它通常用来保证给定数量的、完全相同的 Pod 的可用性。

ReplicaSet 工作原理

ReplicaSet 部分主要字段:

  • 一个用来识别可获得的 Pod 的集合的选择算符。
  • 一个用来标明应该维护的副本个数的数值。
  • 一个用来指定创建新 Pod 时要使用的 Pod 模板。

每个 ReplicaSet 根据 Pod 模板创建制定数量 Pod, 进而实现其存在价值。

  • 如果pod数量多于指定数量,则RS会终止额外的pod。
  • 如果pod数量少于指定数量,则RS会创建额外的pod。例如宿主机内核升级,在其他节点上创建新Pod。

ReplicaSet 使用

ReplicaSet 创建
[root@master30 ~]# vim rs.yaml
apiVersion: apps/v1
kind: ReplicaSet
metadata:
  name: nginx
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      name: nginx
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: docker.io/library/nginx:latest
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 80
[root@master30 ~]# kubectl apply -f rs.yaml

[root@master30 ~]# kubectl get rs
NAME    DESIRED   CURRENT   READY   AGE
nginx   3         3         3       8m45s

[root@master30 ~]# kubectl get pods
NAME          READY   STATUS    RESTARTS   AGE
nginx-95pth   1/1     Running   0          8m48s
nginx-9jg4f   1/1     Running   0          8m48s
nginx-tjtp2   1/1     Running   0          8m48s

[root@master30 ~]# kubectl describe pod nginx-9jg4f |grep Controlled
Controlled By:  ReplicaSet/nginx
ReplicaSet 健壮性测试

测试1:删除单个

[root@master30 ~]# kubectl get rs
NAME    DESIRED   CURRENT   READY   AGE
nginx   3         3         3       8m45s
[root@master30 ~]# kubectl get pods
NAME          READY   STATUS    RESTARTS   AGE
nginx-95pth   1/1     Running   0          8m48s
nginx-9jg4f   1/1     Running   0          8m48s
nginx-tjtp2   1/1     Running   0          8m48s

# 删除一个pod
[root@master30 ~]# kubectl get pods
NAME          READY   STATUS    RESTARTS   AGE
nginx-95pth   1/1     Running   0          8m48s
nginx-9jg4f   1/1     Running   0          8m48s
nginx-tjtp2   1/1     Running   0          8m48s
[root@master30 ~]# kubectl delete pod nginx-95pth --force 
[root@master30 ~]# kubectl get pods
NAME          READY   STATUS    RESTARTS   AGE
nginx-4qw2z   1/1     Running   0          2s
nginx-9jg4f   1/1     Running   0          9m20s
nginx-tjtp2   1/1     Running   0          9m20s

Pod 的 metadata.ownerReferences 字段,显示所属主资源。 正是通过这一连接,ReplicaSet 知道它所维护的 Pod 集合的状态, 并据此计划其操作行为。

ReplicaSet 使用 selector 获得 Pod 集合。如果某个 Pod 没有 OwnerReference 或者其 OwnerReference 不是一个控制器, 且其匹配到某 ReplicaSet 的选择算符,则该 Pod 立即被此 ReplicaSet 获得。

测试2:创建具有相同标签的pod

[root@master30 ~]# kubectl run nginx --image=docker.io/library/nginx:latest -l app=nginx;kubectl get pods
pod/nginx created
NAME          READY   STATUS        RESTARTS   AGE
nginx         0/1     Terminating   0          0s
nginx-4qw2z   1/1     Running       0          3m40s
nginx-9jg4f   1/1     Running       0          12m
nginx-tjtp2   1/1     Running       0          12m

# 刚创建出来就被Terminating
ReplicaSet 删除

删除RS控制器,会删除它管理的pods。

[root@master30 ~]# kubectl delete rs nginx 
[root@master30 ~]# kubectl get pods

使用**–cascade=orphan**选项,只删除RS,保留pod。

[root@master30 ~]# kubectl apply -f rs.yaml 
[root@master30 ~]# kubectl delete rs nginx --cascade=orphan
[root@master30 ~]# kubectl get pods
NAME              READY   STATUS    RESTARTS   AGE
pod/nginx-27vzb   1/1     Running   0          73s
pod/nginx-7lc95   1/1     Running   0          73s
pod/nginx-mmrhk   1/1     Running   0          73s

# 删除pod
[root@master30 ~]# kubectl delete all -l app=nginx

Deployment

Deployment 介绍

Deployment,简称 deploy,为 PodReplicaSet 提供声明式的更新能力。

ReplicaSet 能确保运行指定数量的pod。Deployment能管理ReplicaSets,并提供对pod的更新等功能。因此,我们建议你使用Deployment来管理ReplicaSets,除非你需要自定义更新编排。这意味着你可能永远不需要操作ReplicaSet对象,而是使用Deployment替代管理 。

Deployment 用例

以下是 Deployments 的典型用例:

Deployment 管理

创建

命令行方式
[root@master30 ~]# kubectl create deployment web --image=docker.io/library/nginx:1.27 --replicas=2

# 查看deployment创建的资源
[root@master30 ~]# kubectl get all
NAME                      READY   STATUS    RESTARTS   AGE
pod/web-b78cbd74b-6fjxs   1/1     Running   0          3s
pod/web-b78cbd74b-mh6fh   1/1     Running   0          3s

NAME                  READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/web   2/2     2            2           3s

NAME                            DESIRED   CURRENT   READY   AGE
replicaset.apps/web-b78cbd74b   2         2         2       3s

# 查看deployment详细信息
[root@master30 ~]# kubectl describe deployments.apps web 
Events:
  Type    Reason             Age   From                   Message
  ----    ------             ----  ----                   -------
  Normal  ScalingReplicaSet  21s   deployment-controller  Scaled up replica set web-b78cbd74b to 2

# ReplicaSet与Deployment关系
[root@master30 ~]# kubectl describe replicaset.apps web-b78cbd74b | grep Controlled
Controlled By:  Deployment/web
# 指明ReplicaSet是由Deployment/web创建的。

# pod与ReplicaSet关系
[root@master30 ~]# kubectl describe pod web-b78cbd74b-6fjxs | grep Controlled
Controlled By:  ReplicaSet/web-b78cbd74b
# 指明pod是由ReplicaSet/web-b78cbd74b创建的。
yaml 文件方式
# 获取deployment的yaml文件
[root@master30 ~]# kubectl create deployment web --image=docker.io/library/nginx:1.27 --replicas=2 --dry-run=client -o yaml > deployment-web.yaml
[root@master30 ~]# cat deployment-web.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: web
  name: web
spec:
  replicas: 2
  selector:
    matchLabels:
      app: web
  template:
    metadata:
      labels:
        app: web
    spec:
      containers:
      - image: docker.io/library/nginx:1.27
        name: nginx
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 80

格式说明:

① apiVersion,是当前配置格式的版本。
② kind,是要创建的资源类型, 这里是Deployment。
③ metadata,是该资源的元数据, name是必需的元数据项。
④ spec,是该Deployment的规格说明。
⑤ spec.replicas,指明副本数量, 默认为1。
⑥ spec.template,定义Pod的模板, 这是配置文件的重要部分。
⑦ spec.template.metadata,定义Pod的元数据, 至少要定义一个label。 label的key和value可以任意指定。
⑧ spec.template.spec,描述Pod的规格, 此部分定义Pod中每一个容器的属性,name和image是必需的。

创建方式进行比较

  • 基于命令行的方式:
    • 简单、 直观、 快捷, 上手快。
    • 适合临时测试或实验。
  • 基于配置文件的方式:
    • 配置文件描述了What, 即应用最终要达到的状态。
    • 配置文件提供了创建资源的模板, 能够重复部署。
    • 可以像管理代码一样管理部署。
    • 适合正式的、 跨环境的、 规模化部署。
    • 这种方式要求熟悉配置文件的语法, 有一定难度。

*kubectl apply **命令不但能够创建Kubernetes资源, 也能对资源进行更新, 非常方便。

编辑
# 方法1:命令行直接修改
[root@master30 ~]# kubectl edit deployments.apps web

# 方法2:编辑资源文件,然后apply应用

# 方法3:命令行修改,例如修改deployment副本数
[root@master30 ~]# kubectl scale deployment web --replicas=4
删除

删除deployments时,默认会删除deployments管理的子资源。

[root@master30 ~]# kubectl delete deployments.apps web
deployment.apps "web" deleted

使用**–cascade=orphan选项**删除deployments,不会删除deployments管理的子资源。

[root@master30 ~]# kubectl apply -f deployment-web.yaml
[root@master30 ~]# kubectl delete deployments.apps web --cascade=orphan

# 先确山删除对象
[root@master30 ~]# kubectl get all -l app=web

# 然后再删除
[root@master30 ~]# kubectl delete all -l app=web
[root@master30 ~]# kubectl get all -l app=web
水平伸缩
# 创建 deployment
[root@master30 ~]# kubectl create deployment web --image=docker.io/library/nginx:1.27 --replicas=2
[root@master30 ~]# kubectl scale deployment web --replicas=3

# 或者
[root@master30 ~]# kubectl edit deployments.apps web

# 或者修改yaml文件并apply
[root@master30 ~]# kubectl get deployments.apps web -o yaml > web.yaml
[root@master30 ~]# vim web.yaml

[root@master30 ~]# kubectl get pod
NAME                  READY   STATUS    RESTARTS   AGE
web-5899d78c9-cckln   1/1     Running   0          9m28s
web-5899d78c9-p8pk4   1/1     Running   0          43s
web-5899d78c9-phntq   1/1     Running   0          9m28s
健壮性测试

关闭 worker节点,测试pod重建。

[root@master30 ~]# kubectl get pod -o wide
NAME                  READY   STATUS    RESTARTS   AGE     IP              NODE               NOMINATED NODE   READINESS GATES
web-5899d78c9-cckln   1/1     Running   0          14m     10.224.51.134   worker31.laoma.cloud   <none>           <none>
web-5899d78c9-p8pk4   1/1     Running   0          6m12s   10.224.51.135   worker31.laoma.cloud   <none>           <none>
web-5899d78c9-phntq   1/1     Running   0          14m     10.224.225.69   worker32.laoma.cloud   <none>           <none>

# 关闭 worker32
[root@worker32 ~]# init 0

# 等待一段时间(5分钟), Kubernetes 判定 worker32不可用, 将worker32上的Pod标记为Unknown状态, 并在worker31上重建Pod,维持总副本数为3

# 当worker32恢复后, Unknown的Pod会被删除, 已经运行的Pod不会重新调度回worker32。

K8s 判断节点宕机,要经过 3 个阶段

  1. Node 节点上kubelet 默认 每 10s 发一次心跳上报自身状态(kubelet → kube-apiserver)

  2. Master 上 controller-manager5 秒检查一次心跳,连续 40s 没收到 Node节点心跳,判定 Node 节点不健康,b标记为 NotReady

    参数:node-monitor-period=5snode-monitor-grace-period=40s

    该参数属于 kube-controller-manager 组件,该组件以静态 Pod 形式运行在 master 节点,路径:

/etc/kubernetes/manifests/kube-controller-manager.yaml
  1. 编辑静态 Pod 配置文件,找到 command 段,添加或修改 --pod-eviction-timeout 参数,保存文件,触发静态 Pod 重启。

  2. 节点 NotReady 持续满 5 分钟,开始把 Pod 驱逐到别的节点。

    参数:pod-eviction-timeout=300s

    该参数也属于 kube-controller-manager 组件,该组件以静态 Pod 形式运行在 master 节点。修改方法同上。

更新镜像
# 设置 deployment 的 image 为 docker.io/library/nginx:1.28

# 获取容器名称
[root@master30 ~]# kubectl get deployments.apps -o wide
NAME   READY   UP-TO-DATE   AVAILABLE   AGE    CONTAINERS   IMAGES       SELECTOR
web    3/3     3            3           139m   nginx       docker.io/library/nginx:1.27   app=web

# 或者
[root@master30 ~]# kubectl describe deployments.apps web |grep Container -i -A2
  Containers:
   nginx:
    Image:        docker.io/library/nginx:1.27

# 更新镜像为docker.io/library/nginx:1.28
[root@master30 ~]# kubectl set image deployment/web nginx=docker.io/library/nginx:1.28 --record
# 或者直接编辑deploy设置镜像
[root@master30 ~]# kubectl edit deployments.apps web 

# 新增了一个replicaset,用于创建新的pod
[root@master30 ~]# kubectl get rs
NAME                             DESIRED   CURRENT   READY   AGE
replicaset.apps/web-5899d78c9    0         0         0       26m
replicaset.apps/web-6c57bdf5f4   3         3         3       9s

# 查看镜像版本
[root@master30 ~]# kubectl get deployments.apps web -o wide
NAME   READY   UP-TO-DATE   AVAILABLE   AGE   CONTAINERS   IMAGES       SELECTOR
web    3/3     3            3           26m   nginx        docker.io/library/nginx:1.28   app=web
版本控制

使用 kubectl rollout 命令控制deployment版本。

[root@master30 ~]# kubectl rollout -h
Manage the rollout of one or many resources.
        
 Valid resource types include:

  *  deployments
  *  daemonsets
  *  statefulsets

Examples:
  # Rollback to the previous deployment
  kubectl rollout undo deployment/abc
  
  # Check the rollout status of a daemonset
  kubectl rollout status daemonset/foo
  
  # Restart a deployment
  kubectl rollout restart deployment/abc
  
  # Restart deployments with the 'app=nginx' label
  kubectl rollout restart deployment --selector=app=nginx

Available Commands:
  history       View rollout history
  pause         Mark the provided resource as paused
  restart       Restart a resource
  resume        Resume a paused resource
  status        Show the status of the rollout
  undo          Undo a previous rollout

Usage:
  kubectl rollout SUBCOMMAND [options]

Use "kubectl rollout <command> --help" for more information about a given command.
Use "kubectl options" for a list of global command-line options (applies to all commands).

示例

# 再次更新镜像为 docker.io/library/nginx:1.28
[root@master30 ~]# kubectl set image deployment/web nginx=docker.io/library/nginx:1.28 --record 

# 查看更新记录
[root@master30 ~]# kubectl rollout history deployment web
deployment.apps/web 
REVISION  CHANGE-CAUSE
1         <none>
2         kubectl set image deployment/web nginx=docker.io/library/nginx:1.28 --record=true
3         kubectl set image deployment/web nginx=nginx:1.29 --record=true

# 回滚到版本1
[root@master30 ~]# kubectl rollout undo deployment web --to-revision=1
deployment.apps/web rolled back
[root@master30 ~]# kubectl rollout history deployment web
deployment.apps/web 
REVISION  CHANGE-CAUSE
2         kubectl set image deployment/web *=docker.io/library/nginx:1.28 --record=true
3         kubectl set image deployment/web *=nginx:1.29 --record=true
4         <none>
滚动更新

Kubernetes提供了两个参数maxSurge和maxUnavailable来精细控制Pod的替换数量 。

  • **maxSurge,此参数控制滚动更新过程中副本总数超过 DESIRED 的上限的数量。**maxSurge可以是具体的整数(比如3) , 也可以是百分百, 向上取整。 maxSurge默认值为25%。

    例如, DESIRED为10, 那么副本总数的最大值为 roundUp(10 + 10 * 25%) =13, 所以我们看到 CURRENT 就是13。

  • maxUnavailable,此参数控制滚动更新过程中不可用的副本相占DESIRED的最大比例。 maxUnavailable可以是具体的整数(比如3), 也可以是百分百, 向下取整。 maxUnavailable默认值为25%。

    例如, DESIRED为10, 那么可用的副本数至少要为10 - roundDown(10 * 25%)= 8, 所以我们看到AVAILABLE是8。

总结:

  • maxSurge 值越大, 初始创建的新副本数量就越多。
  • **maxUnavailable **值越大, 初始销毁的旧副本数量就越多,更新初期造成不可用副本数量越多。

理想情况下, 我们这个案例滚动更新的过程应该是这样的:

  1. 创建3个新副本,此时Running副本数为10,maxSurge副本总数达到13。
  2. 销毁2个旧副本,同时再创建2个新副本。此时Running副本数为8。如果之前创建的3个副本状态没有变更为Running,则ContainerCreating副本数为5,maxSurge副本总数仍为13。
  3. 当新副本状态变更为Running, 例如之前创建的5个新副本在同一时刻状态变为running。当然这是一种理想情况。
  4. 此时running状态副本为13个,那么此时可以一次性销毁5个旧副本,同时又可以一次性创建5个新副本,使running副本数回到8。
  5. 这个过程会持续进行, 直到所有的旧副本被新副本替换,滚动更新完成
Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐