08kubernetes核心概念 Controller

88 阅读21分钟

kubernetes核心概念 Controller

pod控制器controller

Controller作用及分类

controller用于控制pod

参考: kubernetes.io/zh/docs/con…

image.png

控制器主要分为:

  • Deployments 部署无状态应用,控制pod升级,回退
  • ReplicaSet 副本集,控制pod扩容,裁减
  • ReplicationController(相当于ReplicaSet的老版本,现在建议使用Deployments加ReplicaSet替代RC)
  • StatefulSets 部署有状态应用,结合Service、存储等实现对有状态应用部署
  • DaemonSet 守护进程集,运行在所有集群节点(包括master), 比如使用filebeat,node_exporter
  • Jobs 一次性
  • Cronjob 周期性

Deployment

Replicaset控制器的功能

  • 支持新的基于集合的selector(以前的rc里没有这种功能)
  • 通过改变Pod副本数量实现Pod的扩容和缩容

Deployment控制器的功能

  • Deployment集成了上线部署、滚动升级、创建副本、回滚等功能
  • Deployment里包含并使用了ReplicaSet

Deployment用于部署无状态应用

无状态应用的特点:

  • 所有pod无差别
  • 所有pod中容器运行同一个image
  • 所有pod可以运行在集群中任意node上
  • 所有pod无启动顺序先后之分
  • 随意pod数量扩容或缩容
  • 例如简单运行一个静态web程序
创建deployment类型应用

deployment-nginx.yml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: deploy-nginx			# deployment名
spec:				
  replicas: 1					# 副本集,deployment里使用了replicaset
  selector:
    matchLabels:
      app: nginx				# 匹配的pod标签,表示deployment和rs控制器控制带有此标签的pod
  template:					    # 代表pod的配置模板
    metadata:
      labels:
        app: nginx				# pod的标签
    spec:
      containers:				# 以下为pod里的容器定义
      - name: nginx
        image: nginx:1.15-alpine
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 80
# 应用YAML文件创建deployment
kubectl apply -f deployment-nginx.yml

# 也可以通过命令的方式
# kubectl create deployment deployment名称 --image=镜像名称 --replicas 集群个数

# 查看验证,deployment可简写成deploy
kubectl get deployment
NAME           READY   UP-TO-DATE   AVAILABLE   AGE
deploy-nginx   1/1     1            1           32s

kubectl get pods
NAME                          READY   STATUS    RESTARTS   AGE
deploy-nginx-79f57dcc-cxq9p   1/1     Running   0          92s

# replicasets可简写成rs
kubectl get replicasets
NAME                    DESIRED   CURRENT   READY   AGE
deploy-nginx-79f57dcc   1         1         1       2m2s
访问deployment
# 查看pod的IP地址
kubectl get pods -o wide
NAME                          READY   STATUS    RESTARTS   AGE   IP             NODE       NOMINATED NODE   READINESS GATES
deploy-nginx-79f57dcc-cxq9p   1/1     Running   0          14h   10.244.30.89   worker02   <none>           <none>

# 在任意集群节点上都可以访问此deploy里pod,但集群外部是不能访问的
curl 10.244.30.89
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
...
删除deployment中的pod
# 删除pod(注意: 是删除deployment中的pod)
kubectl delete pod deploy-nginx-79f57dcc-cxq9p

# 再次查看,发现又重新启动了一个pod(节点由worker02转为worker01了,IP地址也变化了)
kubectl get pods -o wide
NAME                          READY   STATUS    RESTARTS   AGE   IP            NODE       NOMINATED NODE   READINESS GATES
deploy-nginx-79f57dcc-qr9j4   1/1     Running   0          27s   10.244.5.13   worker01   <none>           <none>

pod的IP不是固定的,比如把整个集群关闭再启动,pod也会自动启动,但是IP地址也会变化。既然IP地址不是固定的,所以需要一个固定的访问endpoint给用户,那么这种方式就是service

pod版本升级
# 查看帮助
kubectl set image -h

# 升级前验证nginx版本
kubectl describe pods deploy-nginx-79f57dcc-qr9j4 | grep Image:
    Image:          nginx:1.15-alpine

kubectl exec deploy-nginx-79f57dcc-qr9j4 -- nginx -v
nginx version: nginx/1.15.12

# 升级为1.16版
# 'deployment deploy-nginx'代表名为deploy-nginx的deployment,'nginx=nginx:1.16-alpine'前面的nginx为容器名,--record  表示会记录该选项已经废除
kubectl set image deployment deploy-nginx nginx=nginx:1.16-alpine --record=true
deployment.apps/deploy-nginx image updated

# pod的名称变了
kubectl get pods -o wide
NAME                            READY   STATUS    RESTARTS   AGE     IP             NODE       NOMINATED NODE   READINESS GATES
deploy-nginx-5cd7f4857d-l6stp   1/1     Running   0          7m47s   10.244.30.90   worker02   <none>           <none>

# 容器名怎么查看?
kubectl describe pod deploy-nginx-5cd7f4857d-l6stp
kubectl edit deployment deploy-nginx
kubectl get deployment deploy-nginx -o yaml

# 验证
# 如果升级的pod数量较多,则需要一定时间,可通过下面命令查看是否已经成功
kubectl rollout status deployment deploy-nginx
deployment "deploy-nginx" successfully rolled out

# 验证版本,升级为1.16了
kubectl describe pod deploy-nginx-5cd7f4857d-l6stp | grep Image:
    Image:          nginx:1.16-alpine

kubectl exec deploy-nginx-5cd7f4857d-l6stp -- nginx -v
nginx version: nginx/1.16.1

# 再将nginx1升级为1.17版
kubectl set image deployment deploy-nginx nginx=nginx:1.17-alpine --record=true
deployment.apps/deploy-nginx image updated

kubectl get pods -o wide
NAME                            READY   STATUS    RESTARTS   AGE   IP             NODE       NOMINATED NODE   READINESS GATES
deploy-nginx-77495c487f-88jdl   1/1     Running   0          6s    10.244.30.95   worker02   <none>           <none>

kubectl describe pod deploy-nginx-77495c487f-88jdl | grep Image:
    Image:          nginx:1.17-alpine
pod版本回退
# 查看版本历史信息,最原始是1.15版
kubectl rollout history deployment deploy-nginxkubectl rollout history deployment deploy-nginx
deployment.apps/deploy-nginx
REVISION  CHANGE-CAUSE
1         <none>
2         kubectl set image deployment deploy-nginx nginx=nginx:1.16-alpine --record=true
3         kubectl set image deployment deploy-nginx nginx=nginx:1.17-alpine --record=true

# 查看要回退的版本
kubectl rollout history deployment deploy-nginx --revision=1
deployment.apps/deploy-nginx with revision #1
Pod Template:
  Labels:       app=nginx
        pod-template-hash=79f57dcc
  Containers:
   nginx:
    Image:      nginx:1.15-alpine
    Port:       80/TCP
    Host Port:  0/TCP
    Environment:        <none>
    Mounts:     <none>
  Volumes:      <none>

# 执行回退
kubectl rollout undo deployment deploy-nginx --to-revision=1
deployment.apps/deploy-nginx rolled back

# 验证
kubectl rollout history deployment deploy-nginx
deployment.apps/deploy-nginx
REVISION  CHANGE-CAUSE
2         kubectl set image deployment deploy-nginx nginx=nginx:1.16-alpine --record=true
3         kubectl set image deployment deploy-nginx nginx=nginx:1.17-alpine --record=true
4         <none>

kubectl get pods
NAME                          READY   STATUS    RESTARTS   AGE
deploy-nginx-79f57dcc-wpc6m   1/1     Running   0          70s

kubectl describe pod deploy-nginx-79f57dcc-wpc6m | grep Image:
    Image:          nginx:1.15-alpine

kubectl exec deploy-nginx-79f57dcc-wpc6m -- nginx -v
nginx version: nginx/1.15.12
副本扩容
# 查看帮助
kubectl scale -h

# 扩容为2个副本
kubectl scale deployment deploy-nginx --replicas=2
deployment.apps/deploy-nginx scaled

# 也可以通过修改yaml文件的方式,kubectl edit deploy Deployment名称

# 在两个worker节点上各1个pod
kubectl get pods -o wide
NAME                          READY   STATUS    RESTARTS   AGE     IP             NODE       NOMINATED NODE   READINESS GATES
deploy-nginx-79f57dcc-hvjr5   1/1     Running   0          22s     10.244.30.99   worker02   <none>           <none>
deploy-nginx-79f57dcc-wpc6m   1/1     Running   0          7m29s   10.244.5.17    worker01   <none>           <none>

# 继续扩容(我们这里只有2个worker,但是可以大于worker节点数)
kubectl scale deployment deploy-nginx --replicas=4
deployment.apps/deploy-nginx scaled

kubectl get pods -o wide
NAME                          READY   STATUS    RESTARTS   AGE     IP              NODE       NOMINATED NODE   READINESS GATES
deploy-nginx-79f57dcc-dmzc8   1/1     Running   0          24s     10.244.5.18     worker01   <none>           <none>
deploy-nginx-79f57dcc-hvjr5   1/1     Running   0          3m39s   10.244.30.99    worker02   <none>           <none>
deploy-nginx-79f57dcc-mxvg5   1/1     Running   0          24s     10.244.30.100   worker02   <none>           <none>
deploy-nginx-79f57dcc-wpc6m   1/1     Running   0          10m     10.244.5.17     worker01   <none>           <none>
副本裁减
# 指定副本数为1进行裁减
kubectl scale deployment deploy-nginx --replicas=1
deployment.apps/deploy-nginx scaled

kubectl get pods -o wide
NAME                          READY   STATUS    RESTARTS   AGE   IP            NODE       NOMINATED NODE   READINESS GATES
deploy-nginx-79f57dcc-wpc6m   1/1     Running   0          12m   10.244.5.17   worker01   <none>           <none>
多副本滚动更新
# 先扩容副本
kubectl scale deployment deploy-nginx --replicas=16

kubectl get pods
NAME                          READY   STATUS    RESTARTS   AGE
deploy-nginx-79f57dcc-2xkqt   1/1     Running   0          12s
deploy-nginx-79f57dcc-4h9vq   1/1     Running   0          12s
deploy-nginx-79f57dcc-4tvm7   1/1     Running   0          12s
deploy-nginx-79f57dcc-57hsw   1/1     Running   0          12s
deploy-nginx-79f57dcc-65b8s   1/1     Running   0          12s
deploy-nginx-79f57dcc-bnkfm   1/1     Running   0          12s
deploy-nginx-79f57dcc-f4rq4   1/1     Running   0          12s
deploy-nginx-79f57dcc-fgkl6   1/1     Running   0          12s
deploy-nginx-79f57dcc-fj2nf   1/1     Running   0          12s
deploy-nginx-79f57dcc-g8lm2   1/1     Running   0          12s
deploy-nginx-79f57dcc-lh9h8   1/1     Running   0          12s
deploy-nginx-79f57dcc-n9fwx   1/1     Running   0          12s
deploy-nginx-79f57dcc-nr4ss   1/1     Running   0          12s
deploy-nginx-79f57dcc-rgtq5   1/1     Running   0          12s
deploy-nginx-79f57dcc-vg7bk   1/1     Running   0          12s
deploy-nginx-79f57dcc-wpc6m   1/1     Running   0          13m

# 滚动更新
kubectl set image deployment deploy-nginx nginx=nginx:1.17-alpine --record
deployment.apps/deploy-nginx image updated

# 验证
kubectl rollout status deployment deploy-nginx
...
Waiting for deployment "deploy-nginx" rollout to finish: 12 of 16 updated replicas are available...
Waiting for deployment "deploy-nginx" rollout to finish: 13 of 16 updated replicas are available...
Waiting for deployment "deploy-nginx" rollout to finish: 14 of 16 updated replicas are available...
Waiting for deployment "deploy-nginx" rollout to finish: 15 of 16 updated replicas are available...
deployment "deploy-nginx" successfully rolled out
删除deployment
# 删除deployment,那么里面的pod也会被自动删除
# 直接命令删除
kubectl delete deployment deploy-nginx
# 通过文件的方式删除
kubectl delete -f deployment-nginx.yml

Replicaset

rs-nginx.yml

apiVersion: apps/v1
kind: ReplicaSet
metadata:
  name: rs-nginx
  namespace: default
spec:                    # replicaset的spec
  replicas: 2            # 副本数
  selector:              # 标签选择器,对应pod的标签
    matchLabels:
      app: nginx         # 匹配的label
  template:
    metadata:
      name: nginx		# pod名
      labels:           # 对应上面定义的标签选择器selector里面的内容
        app: nginx
    spec:               # pod的spec
      containers:
      - name: nginx
        image: nginx:1.15-alpine
        ports:
        - name: http
          containerPort: 80
# 应用YAML文件
kubectl apply -f rs-nginx.yml

# 验证
kubectl get rs
NAME       DESIRED   CURRENT   READY   AGE
rs-nginx   2         2         2       11s

kubectl get pods
NAME             READY   STATUS    RESTARTS   AGE
rs-nginx-5mnw5   1/1     Running   0          25s
rs-nginx-chkv5   1/1     Running   0          25s

# 找不到deployment,说明创建rs并没有创建deployment
kubectl get deployment
No resources found in default namespace.

# 删除
kubectl delete -f rs-nginx.yml

pod控制器Controller进阶

DaemonSet

DaemonSet介绍
  • DaemonSet能够让所有(或者特定)的节点运行同一个pod
  • 当节点加入到K8S集群中,pod会被(DaemonSet)调度到该节点上运行,当节点从K8S集群中被移除,被DaemonSet调度的pod会被移除
  • 如果删除DaemonSet,所有跟这个DaemonSet相关的pods都会被删除
  • 如果一个DaemonSet的Pod被杀死、停止、或者崩溃,那么DaemonSet将会重新创建一个新的副本在这台计算节点上
  • DaemonSet一般应用于日志收集、监控采集、分布式存储守护进程等
DaemonSet应用案例

daemonset-nginx.yml

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: daemonset-nginx			
spec:
  selector:
    matchLabels:
      name: nginx-ds
  template:
    metadata:
      labels:
        name: nginx-ds
    spec:
      tolerations:						# tolerations代表容忍
      - key: node-role.kubernetes.io/master  # 能容忍的污点key
        effect: NoSchedule   # kubectl explain pod.spec.tolerations查看(能容忍的污点effect)
      containers:
      - name: nginx
        image: nginx:1.15-alpine
        imagePullPolicy: IfNotPresent
        resources:    # resources资源限制是为了防止master节点的资源被占太多(根据实际情况配置)
          limits:
            memory: 100Mi
          requests:
            memory: 100Mi
# apply应用YAML文件
kubectl apply -f daemonset-nginx.yml

# 验证,daemonset可简写为ds
kubectl get daemonset
NAME              DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR   AGE
daemonset-nginx   2         2         2       2            2           <none>          14s

# 每个worker节点都会运行一个pod
kubectl get pods -o wide
NAME                    READY   STATUS    RESTARTS   AGE   IP              NODE       NOMINATED NODE   READINESS GATES
daemonset-nginx-j4tl5   1/1     Running   0          81s   10.244.30.118   worker02   <none>           <none>
daemonset-nginx-vddj2   1/1     Running   0          81s   10.244.5.35     worker01   <none>           <none>

# 删除
kubectl delete -f daemonset-nginx.yml

Job

Job介绍
  • 对于ReplicaSet而言,它希望pod保持预期数目、持久运行下去,除非用户明确删除,否则这些对象一直存在,它们针对的是耐久性任务,如web服务等
  • 对于非耐久性任务,比如压缩文件,任务完成后,pod需要结束运行,不需要pod继续保持在系统中,这个时候就要用到Job
  • Job负责批量处理短暂的一次性任务 (short lived one-off tasks),即仅执行一次的任务,它保证批处理任务的一个或多个Pod成功结束
Job应用案例
计算圆周率2000位

job1.yml

apiVersion: batch/v1
kind: Job
metadata:
  name: pi			# job名
spec:
  template:
    metadata:
      name: pi		# pod名
    spec:
      containers:
      - name: pi	   # 容器名
        image: perl	   # 此镜像有800多M,可提前导入到所有节点,也可能指定导入到某一节点然后指定调度到此节点
        imagePullPolicy: IfNotPresent
        command: ["perl",  "-Mbignum=bpi", "-wle", "print bpi(2000)"]
      restartPolicy: Never   # 执行完后不再重启
# 应用YAML文件创建job
kubectl apply -f job1.yml

# 验证,等待COMPLETIONS变为1/1
kubectl get jobs
NAME   COMPLETIONS   DURATION   AGE
pi     1/1           74s        76s

# Completed状态,不再是ready状态
kubectl get pods
NAME       READY   STATUS      RESTARTS   AGE
pi-sjzlh   0/1     Completed   0          81s

kubectl logs pi-sjzlh
3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348...

# 删除
kubectl delete -f job1.yml
创建固定次数job

job2.yml

apiVersion: batch/v1
kind: Job
metadata:
  name: busybox-job
spec:
  completions: 10                                               # 执行job的次数
  parallelism: 1                                                # 执行job的并发数
  template:
    metadata:
      name: busybox-job-pod
    spec:
      containers:
      - name: busybox
        image: busybox
        imagePullPolicy: IfNotPresent
        command: ["echo", "hello"]
      restartPolicy: Never
# 应用YAML文件创建job
kubectl apply -f job2.yml

# 验证
kubectl get job
NAME          COMPLETIONS   DURATION   AGE
busybox-job   1/10          4s         5s

# 32秒左右结束
kubectl get job
NAME          COMPLETIONS   DURATION   AGE
busybox-job   10/10         32s        33s

kubectl get pods
NAME                READY   STATUS      RESTARTS   AGE
busybox-job-5gb7h   0/1     Completed   0          74s
busybox-job-8brbl   0/1     Completed   0          68s
busybox-job-cqr6t   0/1     Completed   0          62s
busybox-job-ctjx9   0/1     Completed   0          81s
busybox-job-lzfws   0/1     Completed   0          65s
busybox-job-p9rzv   0/1     Completed   0          84s
busybox-job-pqkkd   0/1     Completed   0          77s
busybox-job-rp95t   0/1     Completed   0          55s
busybox-job-s56gr   0/1     Completed   0          71s
busybox-job-tmnx9   0/1     Completed   0          59s

# 删除
kubectl delete -f job2.yml
一次性备份MySQL数据库

通过Job控制器创建应用备份MySQL数据库

MySQL数据库准备

00_mysql.yaml

apiVersion: v1
kind: Service
metadata:
  name: mysql-test
  namespace: default
spec:
  ports:
  - port: 3306
    name: mysql
  clusterIP: None
  selector:
    app: mysql-dump

---

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: db
  namespace: default
spec:
  selector:
    matchLabels:
      app: mysql-dump
  serviceName: "mysql-test"
  template:
    metadata:
      labels:
        app: mysql-dump
    spec:
      nodeName: worker01
      containers:
      - name: mysql
        image: mysql:5.7
        env:
        - name: MYSQL_ROOT_PASSWORD
          value: "abc123"
        ports:
        - containerPort: 3306
        volumeMounts:
        - mountPath: "/var/lib/mysql"
          name: mysql-data
      volumes:
      - name: mysql-data
        hostPath:
          path: /opt/mysqldata

创建用于实现任务的资源清单文件

03_job.yaml

apiVersion: batch/v1
kind: Job
metadata:
  name: mysql-dump
spec:
  template:
    metadata:
      name: mysql-dump
    spec:
      nodeName: worker02
      containers:
      - name: mysql-dump
        image: mysql:5.7
        command: ["/bin/sh","-c","mysqldump --host=mysql-test -uroot -pabc123 --databases mysql > /root/mysql2023.sql"]
        volumeMounts:
        - mountPath: "/root"
          name: mysql-data
      restartPolicy: Never
      volumes:
      - name: mysql-data
        hostPath:
          path: /opt/mysqldump
kubectl apply -f 00_mysql.yaml
service/mysql-test created
statefulset.apps/db created

kubectl apply -f 03_job.yaml
job.batch/mysql-dump created

kubectl get pods -o wide
NAME               READY   STATUS      RESTARTS   AGE     IP             NODE       NOMINATED NODE   READINESS GATES
db-0               1/1     Running     0          6m47s   10.244.5.36    worker01   <none>           <none>
mysql-dump-blxsl   0/1     Completed   0          35s     10.244.30.67   worker02   <none>           <none>

# worker02
cat /opt/mysqldump/mysql2023.sql | tail -26
CREATE TABLE IF NOT EXISTS `slow_log` (
  `start_time` timestamp(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6),
  `user_host` mediumtext NOT NULL,
  `query_time` time(6) NOT NULL,
  `lock_time` time(6) NOT NULL,
  `rows_sent` int(11) NOT NULL,
  `rows_examined` int(11) NOT NULL,
  `db` varchar(512) NOT NULL,
  `last_insert_id` int(11) NOT NULL,
  `insert_id` int(11) NOT NULL,
  `server_id` int(10) unsigned NOT NULL,
  `sql_text` mediumblob NOT NULL,
  `thread_id` bigint(21) unsigned NOT NULL
) ENGINE=CSV DEFAULT CHARSET=utf8 COMMENT='Slow log';
...

# 删除
kubectl delete -f 03_job.yaml
kubectl delete -f 00_mysql.yaml

CronJob

CronJob介绍
  • 类似于Linux系统的crontab,在指定的时间周期运行相关的任务
  • 时间格式:分时日月周
CronJob应用案例
周期性输出字符

cronjob.yml

apiVersion: batch/v1
kind: CronJob
metadata:
  name: cronjob1
spec:
  schedule: "* * * * *"                 # 分时日月周
  jobTemplate:
    spec:
      template:
        spec:
          containers:
          - name: hello
            image: busybox
            args:
            - /bin/sh
            - -c
            - date; echo hello kubernetes
            imagePullPolicy: IfNotPresent
          restartPolicy: OnFailure
# 应用YAML文件创建cronjob
kubectl apply -f cronjob.yml

# 查看验证
kubectl get cronjob
NAME       SCHEDULE    SUSPEND   ACTIVE   LAST SCHEDULE   AGE
cronjob1   * * * * *   False     0        <none>          8s

# 看AGE时间,每分钟整点执行一次
kubectl get pods
NAME                      READY   STATUS      RESTARTS   AGE
cronjob1-28322093-ntxkl   0/1     Completed   0          2m32s
cronjob1-28322094-gr249   0/1     Completed   0          92s
cronjob1-28322095-twqsr   0/1     Completed   0          32s

# 删除
kubectl delete -f cronjob.yml
周期性备份MySQL数据库

MySQL数据库准备

00_mysql.yaml

apiVersion: v1
kind: Service
metadata:
  name: mysql-test
  namespace: default
spec:
  ports:
  - port: 3306
    name: mysql
  clusterIP: None
  selector:
    app: mysql-dump

---

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: db
  namespace: default
spec:
  selector:
    matchLabels:
      app: mysql-dump
  serviceName: "mysql-test"
  template:
    metadata:
      labels:
        app: mysql-dump
    spec:
      nodeName: worker01
      containers:
      - name: mysql
        image: mysql:5.7
        env:
        - name: MYSQL_ROOT_PASSWORD
          value: "abc123"
        ports:
        - containerPort: 3306
        volumeMounts:
        - mountPath: "/var/lib/mysql"
          name: mysql-data
      volumes:
      - name: mysql-data
        hostPath:
          path: /opt/mysqldata

Cronjob控制器类型应用资源清单文件

05_cronjob.yaml

apiVersion: batch/v1
kind: CronJob
metadata:
  name: mysql-dump
spec:
  schedule: "*/1 * * * *"
  jobTemplate:
    spec:
      template:
        spec:
          nodeName: worker02
          containers:
          - name: c1
            image: mysql:5.7
            command: ["/bin/sh","-c","mysqldump --host=mysql-test -uroot -pabc123 --databases mysql > /root/mysql`date +%Y%m%d%H%M`.sql"]
            volumeMounts:
              - name: mysql-data
                mountPath: "/root"
          restartPolicy: Never
          volumes:
            - name: mysql-data
              hostPath:
                path: /opt/mysqldump
kubectl apply -f 00_mysql.yaml

kubectl apply -f 05_cronjob.yaml

# 查看验证
kubectl get cronjob
NAME         SCHEDULE      SUSPEND   ACTIVE   LAST SCHEDULE   AGE
mysql-dump   */1 * * * *   False     0        30s             49s

# 看AGE时间,每分钟整点执行一次
kubectl get pods
NAME                        READY   STATUS      RESTARTS   AGE
db-0                        1/1     Running     0          4m
mysql-dump-28322104-fdmpg   0/1     Completed   0          2m33s
mysql-dump-28322105-dwc8r   0/1     Completed   0          93s
mysql-dump-28322106-cfxpl   0/1     Completed   0          33s

# worker02
ll /opt/mysqldump
total 11052
-rw-r--r-- 1 root root 3771736 Nov  7 11:04 mysql202311070304.sql
-rw-r--r-- 1 root root 3771736 Nov  7 11:05 mysql202311070305.sql
-rw-r--r-- 1 root root 3771736 Nov  7 11:06 mysql202311070306.sql

# 删除
kubectl delete -f 05_cronjob.yaml
kubectl delete -f 00_mysql.yaml

Controller之StatefulSet控制器

StatefulSet控制器作用

  • StatefulSet 是用来管理有状态应用的控制器
  • StatefulSet 用来管理某Pod集合的部署和扩缩, 并为这些 Pod 提供持久存储和持久标识符
  • 参考: kubernetes.io/zh/docs/con…

无状态应用与有状态应用

无状态应用

  • 如nginx
  • 请求本身包含了响应端为响应这一请求所需的全部信息。每一个请求都像首次执行一样,不会依赖之前的数据进行响应
  • 不需要持久化的数据
  • 无状态应用的多个实例之间互不依赖,可以无序的部署、删除或伸缩

有状态应用

  • 如mysql
  • 前后请求有关联与依赖
  • 需要持久化的数据
  • 有状态应用的多个实例之间有依赖,不能相互替换:无论怎么调度,每个 Pod 都有一个永久不变的 ID

StatefulSet的特点

  • 稳定的、唯一的网络标识符。(通过headless服务实现)
  • 稳定的、持久的存储。(通过PV,PVC,storageclass实现)
  • 有序的、优雅的部署和缩放
  • 有序的、自动的滚动更新

StatefulSet的YAML组成

  1. headless service: 实现稳定,唯一的网络标识
  2. statefulset类型资源: 写法和deployment几乎一致,就是类型不一样
  3. volumeClaimTemplate : 指定存储卷

创建StatefulSet应用

参考: kubernetes.io/zh/docs/tut…

编辑YAML资源清单文件

创建statelfulset应用来调用名为nfs-client的storageclass,以实现动态供给,这里需要先参考存储的动态供给创建storageclass

nginx-storageclass-nfs.yml

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											# statefulset的名称
spec:
  serviceName: "nginx"
  replicas: 3										# 3个副本
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.15-alpine
        ports:
        - containerPort: 80
          name: web
        volumeMounts:
        - name: www
          mountPath: /usr/share/nginx/html
  volumeClaimTemplates:
  - metadata:
      name: www
    spec:
      accessModes: [ "ReadWriteOnce" ]
      storageClassName: "nfs-client"		# 与前面定义的storageclass名称对应
      resources:
        requests:
          storage: 1Gi
kubectl apply -f nginx-storageclass-nfs.yml
应用部署后验证
# 验证pod
kubectl get pods
NAME                                      READY   STATUS    RESTARTS   AGE
nfs-client-provisioner-5bffc5866c-h79v4   1/1     Running   0          86s
web-0                                     1/1     Running   0          36s
web-1                                     1/1     Running   0          34s
web-2                                     1/1     Running   0          31s

# 验证pv,自动产生了3个pv
kubectl get pv
NAME                                       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM               STORAGECLASS   REASON   AGE
pvc-8f4dfaf6-e0bf-4681-8558-6be31c05e0e7   1Gi        RWO            Delete           Bound    default/www-web-2   nfs-client              50s
pvc-940a950e-e09e-4a71-a773-14c893e0014d   1Gi        RWO            Delete           Bound    default/www-web-1   nfs-client              53s
pvc-e31799a0-9bd3-4da8-bfd7-9f0ef74f7ade   1Gi        RWO            Delete           Bound    default/www-web-0   nfs-client              55s

# 验证pvc,自动产生了3个PVC
kubectl get pvc
NAME        STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   AGE
www-web-0   Bound    pvc-e31799a0-9bd3-4da8-bfd7-9f0ef74f7ade   1Gi        RWO            nfs-client     75s
www-web-1   Bound    pvc-940a950e-e09e-4a71-a773-14c893e0014d   1Gi        RWO            nfs-client     73s
www-web-2   Bound    pvc-8f4dfaf6-e0bf-4681-8558-6be31c05e0e7   1Gi        RWO            nfs-client     70s

# nfs 节点
# 在nfs服务器的共享目录中发现自动产生了3个子目录
ls /data/nfs/
default-www-web-0-pvc-e31799a0-9bd3-4da8-bfd7-9f0ef74f7ade  default-www-web-1-pvc-940a950e-e09e-4a71-a773-14c893e0014d  default-www-web-2-pvc-8f4dfaf6-e0bf-4681-8558-6be31c05e0e7

# master01
# 验证存储持久性
# 在web-0 pod中创建一个主页文件
kubectl exec -it web-0 -- /bin/sh -c "echo haha >  /usr/share/nginx/html/index.html"

# nfs 节点
# 在nfs服务器上发现文件被创建到了对应的目录中
ls /data/nfs/*/
/data/nfs/default-www-web-0-pvc-e31799a0-9bd3-4da8-bfd7-9f0ef74f7ade/:
index.html

/data/nfs/default-www-web-1-pvc-940a950e-e09e-4a71-a773-14c893e0014d/:

/data/nfs/default-www-web-2-pvc-8f4dfaf6-e0bf-4681-8558-6be31c05e0e7/:

# 文件内的内容也与web-0的pod中创建的一致
cat /data/nfs/default-www-web-0-pvc-e31799a0-9bd3-4da8-bfd7-9f0ef74f7ade/index.html
haha

# master01
# 删除web-0这个pod,再验证
kubectl delete pod web-0

# 因为控制器的原因,会迅速再拉起web-0这个pod
kubectl get pods
NAME                                      READY   STATUS    RESTARTS   AGE
nfs-client-provisioner-5bffc5866c-h79v4   1/1     Running   0          10m
web-0                                     1/1     Running   0          5s
web-1                                     1/1     Running   0          9m47s
web-2                                     1/1     Running   0          9m44s

# 新拉起的pod仍然是相同的存储数据
kubectl exec -it web-0 -- cat /usr/share/nginx/html/index.html
haha

访问验证

# 验证Coredns是否可用
kubectl get svc -n kube-system
NAME       TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)                  AGE
kube-dns   ClusterIP   10.96.0.10   <none>        53/UDP,53/TCP,9153/TCP   12d

dig -t a www.baidu.com @10.96.0.10
...
;; ANSWER SECTION:
www.baidu.com.          30      IN      CNAME   www.a.shifen.com.
www.a.shifen.com.       30      IN      A       183.2.172.185
www.a.shifen.com.       30      IN      A       183.2.172.42

;; Query time: 2020 msec
;; SERVER: 10.96.0.10#53(10.96.0.10)
;; WHEN: Tue Nov 14 16:22:22 CST 2023
;; MSG SIZE  rcvd: 149

dig -t a nginx.default.svc.cluster.local. @10.96.0.10
...
;; ANSWER SECTION:
nginx.default.svc.cluster.local. 30 IN  A       10.244.5.21
nginx.default.svc.cluster.local. 30 IN  A       10.244.5.23
nginx.default.svc.cluster.local. 30 IN  A       10.244.30.84

;; Query time: 13 msec
;; SERVER: 10.96.0.10#53(10.96.0.10)
;; WHEN: Tue Nov 14 16:23:02 CST 2023
;; MSG SIZE  rcvd: 201

dig -t a web-0.nginx.default.svc.cluster.local. @10.96.0.10
...
;; ANSWER SECTION:
web-0.nginx.default.svc.cluster.local. 30 IN A  10.244.30.84

;; Query time: 5 msec
;; SERVER: 10.96.0.10#53(10.96.0.10)
;; WHEN: Tue Nov 14 16:24:10 CST 2023
;; MSG SIZE  rcvd: 119

# 在kubernetes集群内创建pod访问
# 创建容器,并进入容器
kubectl run -i --tty --rm=true busybox --image=radial/busyboxplus

# 该请求会路由到web-0,web-1,web-2中的一个
curl nginx.default.svc.cluster.local.
haha

curl nginx.default.svc.cluster.local.
<html>
<head><title>403 Forbidden</title></head>

curl web-0.nginx.default.svc.cluster.local.
haha

exit

已部署应用滚动更新(含金丝雀发布)

它将按照与 Pod 终止相同的顺序(从最大序号到最小序号)进行,每次更新一个 Pod。StatefulSet可以使用partition参数来实现金丝雀更新,partition参数可以控制StatefulSet控制器更新的Pod。下面,我们就进行StatefulSet控制器的金丝雀更新实战

# 使用patch参数来指定了StatefulSet控制器的partition参数为2,表示当更新时,只有Pod的编号大于等于2的才更新。
kubectl patch sts web -p '{"spec":{"updateStrategy":{"rollingUpdate":{"partition":2}}}}'

kubectl exec -it web-0 -- nginx -v
nginx version: nginx/1.15.12

kubectl exec -it web-1 -- nginx -v
nginx version: nginx/1.15.12

kubectl exec -it web-2 -- nginx -v
nginx version: nginx/1.15.12

kubectl set image sts/web nginx=nginx:latest

kubectl exec -it web-0 -- nginx -v
nginx version: nginx/1.15.12

kubectl exec -it web-1 -- nginx -v
nginx version: nginx/1.15.12

kubectl exec -it web-2 -- nginx -v
nginx version: nginx/1.25.3

kubectl get pods -o custom-columns=Name:metadata.name,Image:spec.containers[0].image
Name                                      Image
nfs-client-provisioner-5bffc5866c-h79v4   registry.cn-beijing.aliyuncs.com/pylixm/nfs-subdir-external-provisioner:v4.0.0
web-0                                     nginx:1.15-alpine
web-1                                     nginx:1.15-alpine
web-2                                     nginx:latest
# 如何实现全部更新呢?
kubectl patch sts web -p '{"spec":{"updateStrategy":{"rollingUpdate":{"partition":0}}}}'

kubectl set image sts/web nginx=nginx:latest

kubectl get pods -o custom-columns=Name:metadata.name,Image:spec.containers[0].image
Name                                      Image
nfs-client-provisioner-5bffc5866c-h79v4   registry.cn-beijing.aliyuncs.com/pylixm/nfs-subdir-external-provisioner:v4.0.0
web-0                                     nginx:latest
web-1                                     nginx:latest
web-2                                     nginx:latest

已部署应用扩容与缩容

在StatefulSet扩容时,会创建一个新的Pod,该Pod与之前的所有Pod都是有顺序的,并且新Pod的序号最大。在缩容时,StatefulSet控制器删除的也是序号最大的Pod

kubectl scale sts web --replicas=4

kubectl get pods
NAME                                      READY   STATUS    RESTARTS   AGE
nfs-client-provisioner-5bffc5866c-h79v4   1/1     Running   0          37m
web-0                                     1/1     Running   0          101s
web-1                                     1/1     Running   0          103s
web-2                                     1/1     Running   0          5m24s
web-3                                     1/1     Running   0          18s

kubectl scale sts web --replicas=2

kubectl get pods
NAME                                      READY   STATUS    RESTARTS   AGE
nfs-client-provisioner-5bffc5866c-h79v4   1/1     Running   0          37m
web-0                                     1/1     Running   0          2m9s
web-1                                     1/1     Running   0          2m11s

# 删除
kubectl delete -f nginx-storageclass-nfs.yml
rm -f nginx-storageclass-nfs.yml