Pod控制器

Pod控制器:

RC、RS控制器的核心:

  • 期望的副本数(replicas)
  • 标签选择器(selector)
  • pod模板(template)

注意:
控制器本身有一个spec配置,而template是为控制器提供的模板pod(创建多个副本时,直接获取模板的信息生成)

发布方式控制:

RS默认使用的滚动发布,但RS自身只能手动控制,要自动实现需要Deployment控制器
手动停一个,再创建一个,重复操作是滚动
手动停一个,再创建一个,后续不动是金丝雀
手动创建一批,再把service转向新RS,是蓝绿


RS控制器:

RC的升级版
RC、RS已过时

kubectl explain rs.spec

例1: 用rs创建pod
apiVersion: apps/v1
kind: ReplicaSet 
metadata:
	name: rs-xx		#控制器的name
spec:
	replicas: 2
	selector:
		matchLabels:	#匹配的pod标签
			app: rs-t1
			xxx: qqqq
	template:
		metadata:
			name: rs-t1-tmp
			labels:		#pod模板的标签
				app: rs-t1
				xxx: qqqq
		spec:
			containers:
				- name: ngx
					image: nginx
					imagePullPolicy: IfNotPresent
					ports:
						- name: http
							containerPort: 80

Deployment控制器:

调用RS,基于RS控制pod,并提供额外功能。pod对象本身支持的方法,deploy都支持
只能用于无状态的应用,如果是mysql的主从、redis集群就不行

语法格式:

kubectl explain deploy.spce #查看详细语法

spce:
	replicas: <ini>			#pod创建的副本数
	minReadySeconds: int	#新建pod认为准备就绪的秒数,默认0秒,认为创建完成即准备就绪
	paused: 布尔值			#暂停部署,默认false。如果指定true,则任务将不会执行,并且创建的任务将不会被视为任务的生成或被评估。如果指定任何其他值,则将导致任务被暂停。
	selector:						#标签选择器,部署时,deployment控制器会根据此标签来部署
		matchLabels: <map[string]string>					#匹配标签条件,部分版本控制器会使用matchExpressions条
			标签: 值				#匹配的标签
		matchExpressions: <[]Object>
			key: <string> -required-
			operator: <string> -required-
				#In
				#NotIn
				#Exists
				#DoesNotExist
			values:	<[]string>
	template:				#发布模板
		metadata:				#定义模板元数据,标签与选择器写的标签对应,否则没有pod控制器来创建这个模板
			标签: 值				#对应标签选择器的内容
		spec:					#定义pod相关内容
			containers:			#容器相关配置,大部分与pod相同,是直接调用的pod控制器本身
				env:			#环境变量相关
	strategy <Object>		#自动更新策略
		type: 策略 			#更新策略
			#Recreate,重建更新(删一个建一个)
			#RollingUpdate,滚动更新
		rollingUpdate <Object>		#控制滚动更新的粒度,仅滚动更新使用
			maxSurge				#更新时,最多能超出定义的副本数几个,取值是:int、百分比。最多和最小只能一个为0,默认25%
			maxUnavailable			#更新时,最多有几个不可用(删除几个),默认25%
	revisionHistoryLimit <int> 		#保留几个历史版本,默认10个
	progressDeadlineSeconds: int

案例:

例1: deploy创建pod
apiVersion: apps/v1
kind: Deployment
metadata:
	name: ngx-dep
	lables:
		app: ngx-dep
spec:
	replicas: 3
	selector:
		matchLabels:
			app: ngx
	template:
		metadata:
			labels:
				app: ngx
		spec:
			containers:
				- name: nginx
				  image: nginx
				  imagePullPolicy: IfNotPresent
				  ports: 
						- name: http
						  containerPort: 80
						  protocol: TCP
					env:
						- name: "passwd"
							value: "123456"
						- name: "xxx"
							value: "123456"
					 resources:
						requests:
						  cpu: "100m"
						  memory: "100Mi"
						limits:
						  cpu: "0.3"
						  memory: "100Mi"

DaemonSet

用于系统级的pod控制器,如logstash,保证每个node上运行一个收集器
用于控制无状态的应用,且必须是守护进程方式运行,任何时刻多无需停止
常用于运行:

​ logstash
​ filebeat
​ 普罗米休斯

语法格式:

kubectl explain daemonset.spec

spec:		#参数与Deployment大部分相同
	updateStrategy		#设置滚动更新
		type: 更新策略	
			#RollingUpdate,滚动更新,默认
			#OnDelete,删除时更新,等于重建更新
		rollingUpdate <Object>	#滚动更新粒度
			maxUnavailable		#最多不可以

案例:

例1: 运行filebeat
apiVersion: apps/v1
kind: DaemonSet
metadata:
	name: filebeat-ds
spec:
	selector:
		matchLabels:
			app: filebeat
	template:
		metadata:
			labels:
				app: filebeat
		spec:
			containers:
				- name: filebeat
					image: elastic/filebeat:7.16.0
					imagePullPolicy: IfNotPresent

Job

用于启动一次性的任务


Cronjob


StatefulSet

有状态应用控制器,用于管理有状态应用,如redis集群、zk集群、mysql主从等

有状态应用运行要求:

  • 稳定且唯一的网络标识符
  • 稳定且持久的存储
  • 有序、平滑的部署和扩展
  • 有序、平滑的终止和删除
  • 有序的滚动更新

组件:

  • headless service(无头服务)
    如redis集群的每个节点名称都是唯一的,所以需要用无头服务,访问时直接请求pod
  • statefulset(控制器)
    deployment控制器创建pod时,每个pod名称都是随机生成的,这不符合redis集群节点的唯一性,所以需要把每个pod名称固定
  • volumeClaimtemplate(存储卷申请模板)
    如redis集群,每个节点的槽位不一样,数据也不一样,所以不能使用同一个存储卷,需要每个节点单独使用一个存储卷,创建时只能用一个存储模板,每个pod启动时单独申请一个pvc和pv

pvc模板的保留策略

默认情况下,sts创建的pod在删除时,模板创建的对应pvc不会自动删除,而是保留,需要手动删除或helm工具管理
sts控制器对pvc的策略有2种情况:

  • whenDeleted(删除sts时),控制器删除
  • whenScaled(缩容sts时),pod删除

4种策略: #目前是Alpha特性

  • whenDeleted、**whenScaled **都是:Retain
    • 默认的保留策略。它适用于 StatefulSet 卷上的数据是不可替代的且只能手动删除的情况
  • whenDeleted 是 Delete ,whenScaled 是 Retain
    • sts删除时pvc删除,缩容时会保留,扩容时,可以从前一个被删除副本重新连接所有数据
  • whenDeletedwhenScaled 都是: Delete
    • 缩容时,pvc立即删除;但更新调度、pod转移到其他节点而不是缩容时,pvc会保留继续使用。当创建一个新的副本时, 来自以前副本的任何数据都不可用。适用于数据生命周期短于副本生命周期的情况
  • whenDeleted 是 Retain ,whenScaled 是 Delete
    • sts删除时保留,缩容时删除。如Elasticsearch集群,减少副本时,pod的数据不再需要,pvc因此可以删除。但临时关闭Elasticsearch 集群进行维护时数据是希望保留,以供下次启动继续使用。 如果需要使 Elasticsearch 系统脱机,可重新创建sts控制器来恢复 Elasticsearch 集群。 保存 Elasticsearch 数据的 PVCs 不会被删除,新的副本将自动使用它们

语法格式:

kubectl explain sts.spec

spec:
	replicas				#创建pod数量
	selector				#pod标签选择器
  serviceName			#无头svc的名称
  template				#定义pod模板
  updateStrategy		#更新策略
	  rollingUpdate		#自定义更新策略
 			partition: 数量		#手动指定更新pod数量,如总共5个pod,0-4下标,指定分区=4,则更新下标是4的pod,等于灰度。默认是0,也就是全部
	volumeClaimTemplates: <[]Object>		#pvc自动申请模板
		- metadata: 
  		  name
  	  spec:
    		accessModes: 读写权限
  		  resources:
  			  requests:
  				  storage: 大小
	podManagementPolicy: 策略			#创建、缩减pod时的策略
	  #OrderedReady,默认策略,按顺序创建,顺序删除
	  #Parallel,平行创建无先后顺序,缩减时全部删除
	revisionHistoryLimit: int		#pod修改的历史记录数,默认记录10个历史版本
	persistentVolumeClaimRetentionPolicy:			#pvc的保留策略,1.22版本开始的alpha特性,需手动为api-server传递选项--feature-gates=StatefulSetAutoDeletePVC=true 开启
		whenDeleted: 策略
			#Retain,默认保留
			#Delete
		whenScaled: 策略
			#Retain,默认保留
			#Delete

案例:

例1: sts创建ngx,做扩容,缩容
1)准备nfs
mkdir -p /data/nfs/v{1..3}
vim /etc/exports
/data/xx/v1  2.2.0.0/16(rw,no_root_squash)
/data/xx/v2  2.2.0.0/16(rw,no_root_squash)
/data/xx/v3  2.2.0.0/16(rw,no_root_squash)

exportfs -av
2)2创建pv
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv01
spec:
  nfs:
    path: /data/nfs/v1
    server: 2.2.2.30
  accessModes: ["ReadWriteMany","ReadWriteOnce"]
  capacity:
    storage: 1Gi
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv02
spec:
  nfs:
    path: /data/nfs/v2
    server: 2.2.2.30
  accessModes: ["ReadWriteMany","ReadWriteOnce"]
  capacity:
    storage: 1Gi
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv03
spec:
  nfs:
    path: /data/nfs/v3
    server: 2.2.2.30
  accessModes: ["ReadWriteMany","ReadWriteOnce"]
  capacity:
    storage: 1Gi
3)使用statefulset创建pod
apiVersion: v1
kind: Service
metadata:
  name: ngx-svc
spec:
  clusterIP: None
  ports:
    - port: 80
      name: web
  selector:
    app: ngx
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: ngx-sts
spec:
  replicas: 2
  selector:
    matchLabels:
      app: ngx
  serviceName: ngx-svc
  template:
    metadata:
      labels:
        app: ngx
    spec:
      containers:
        - name: ngx
          image: nginx
          imagePullPolicy: IfNotPresent
          ports:
            - containerPort: 80
          volumeMounts:
            - name: html
              mountPath: /usr/share/nginx/html
  volumeClaimTemplates:
    - metadata:
        name: html
      spec:
        accessModes:
          - ReadWriteOnce
        resources:
          requests:
            storage: 1Gi
  persistentVolumeClaimRetentionPolicy:
    whenDeleted: Delete
    whenScaled: Delete

4)测试扩容、缩容

#扩容
kubectl scale sts --replicas=3 ngx-sts

#缩容
kubectl patch sts ngx-sts -p '{"spec":{"replicas":2}}'
kubectl get po
例2: 指定sts更新策略,实现灰度发布
1)先实现金丝雀更新
#指定副本更新,从最后一个更新到第一个
kubectl patch sts ngx-sts -p '{"spec":{"updateStrategy":{"rollingUpdate":{"partition":2}}}}'

#更新
kubectl set image statfulset ngx-sts ngx=nginx:1.18
2)查看更新变化
#查看pod的镜像版本变更,只是ngx-sts-2变化
kubectl get pod ngx-sts-2 -o custom-columns=CONTAINER:.spec.containers[0].name,IMAGE:.spec.containers[0].image

#第一个pod的版本还没有更新
kubectl get pod ngx-sts-0 -o custom-columns=CONTAINER:.spec.containers[0].name,IMAGE:.spec.containers[0].image
3)再全部发布
kubectl patch sts ngx-sts -p '{"spec":{"updateStrategy":{"rollingUpdate":{"partition":0}}}}'
例3: 实现mysql的主从复制

生成配置

在启动 Pod 规约中的任何容器之前,Pod 首先按顺序运行所有的初始化容器
第一个名为 `init-mysql` 的初始化容器根据序号索引生成特殊的 MySQL 配置文件。
该脚本通过从 Pod 名称的末尾提取索引来确定自己的序号索引,而 Pod 名称由 `hostname` 命令返回。 然后将序数(带有数字偏移量以避免保留值)保存到 MySQL `conf.d` 目录中的文件 `server-id.cnf`。 这一操作将 StatefulSet 所提供的唯一、稳定的标识转换为 MySQL 服务器 ID
将内容复制到conf.d中,`init-mysql` 容器中的脚本也可以应用 ConfigMap 中的 `primary.cnf` 或 `replica.cnf`。 由于示例部署结构由单个 MySQL 主节点和任意数量的副本节点组成, 因此脚本仅将序数 `0` 指定为主节点,而将其他所有节点指定为副本节点。
与 StatefulSet 控制器的部署顺序保证相结合, 可以确保 MySQL 主服务器在创建副本服务器之前已准备就绪,以便它们可以开始复制。

克隆现有数据

通常,当新 Pod 作为副本节点加入集合时,必须假定 MySQL 主节点可能已经有数据。 还必须假设复制日志可能不会一直追溯到时间的开始。
这些保守的假设是允许正在运行的 StatefulSet 随时间扩大和缩小而不是固定在其初始大小的关键。
第二个名为 `clone-mysql` 的初始化容器,第一次在带有空 PersistentVolume 的副本 Pod 上启动时,会在从属 Pod 上执行克隆操作。 这意味着它将从另一个运行中的 Pod 复制所有现有数据,使此其本地状态足够一致, 从而可以开始从主服务器复制。
MySQL 本身不提供执行此操作的机制,因此本示例使用了一种流行的开源工具 Percona XtraBackup。 在克隆期间,源 MySQL 服务器性能可能会受到影响。 为了最大程度地减少对 MySQL 主服务器的影响,该脚本指示每个 Pod 从序号较低的 Pod 中克隆。 可以这样做的原因是 StatefulSet 控制器始终确保在启动 Pod `N + 1` 之前 Pod `N` 已准备就绪。

开始复制

初始化容器成功完成后,应用容器将运行。MySQL Pod 由运行实际 `mysqld` 服务的 `mysql` 容器和充当辅助工具的xtrabackup 容器组成。
`xtrabackup` sidecar 容器查看克隆的数据文件,并确定是否有必要在副本服务器上初始化 MySQL 复制。 如果是这样,它将等待 `mysqld` 准备就绪,然后使用从 XtraBackup 克隆文件中提取的复制参数执行 `CHANGE MASTER TO` 和 `START SLAVE` 命令。
一旦副本服务器开始复制后,它会记住其 MySQL 主服务器,并且如果服务器重新启动或连接中断也会自动重新连接。 另外,因为副本服务器会以其稳定的 DNS 名称查找主服务器(`mysql-0.mysql`), 即使由于重新调度而获得新的 Pod IP,它们也会自动找到主服务器。
最后,开始复制后,`xtrabackup` 容器监听来自其他 Pod 的连接,处理其数据克隆请求。 如果 StatefulSet 扩大规模,或者下一个 Pod 失去其 PersistentVolumeClaim 并需要重新克隆, 则此服务器将无限期保持运行
1)准备nfs
mkdir -p /data/nfs/sql-{1..3}
exportfs -av
2)创建pv
apiVersion: v1
kind: PersistentVolume
metadata:
  name: sql-1
spec:
  nfs:
    path: /data/nfs/sql-1
    server: 2.2.2.30
  accessModes: ["ReadWriteMany","ReadWriteOnce"]
  capacity:
    storage: 10Gi
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: sql-2
spec:
  nfs:
    path: /data/nfs/sql-2
    server: 2.2.2.30
  accessModes: ["ReadWriteMany","ReadWriteOnce"]
  capacity:
    storage: 10Gi
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: sql-3
spec:
  nfs:
    path: /data/nfs/sql-3
    server: 2.2.2.30
  accessModes: ["ReadWriteMany","ReadWriteOnce"]
  capacity:
    storage: 10Gi
3)创建cm
apiVersion: v1
kind: ConfigMap
metadata:
  name: mysql
  labels:
    app: mysql
    app.kubernetes.io/name: mysql
data:
  primary.cnf: |
    [mysqld]
    log-bin
  replica.cnf: |
    [mysqld]
    super-read-only
3)创建无头服务

做了读写分离svc

apiVersion: v1
kind: Service
metadata:
  name: mysql
  labels:
    app: mysql
    app.kubernetes.io/name: mysql
spec:
  ports:
    - name: mysql
      port: 3306
  clusterIP: None
  selector:
    app: mysql
---
apiVersion: v1
kind: Service
metadata:
  name: mysql-read
  labels:
    app: mysql
    app.kubernetes.io/name: mysql
    readonly: "true"
spec:
  ports:
    - name: mysql
      port: 3306
  selector:
    app: mysql
4)创建mysql主从复制

官方文档的此配置清单有问题, 此为修改后

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: mysql
spec:
  selector:
    matchLabels:
      app: mysql
      app.kubernetes.io/name: mysql
  serviceName: mysql
  replicas: 3
  template:
    metadata:
      labels:
        app: mysql
        app.kubernetes.io/name: mysql
    spec:
    	volumes:
        - name: conf
          emptyDir: {}
        - name: config-map
          configMap:
            name: mysql
      initContainers:
        - name: init-mysql
          image: mysql:5.7
          env:
            - name: MYSQL_ALLOW_EMPTY_PASSWORD
              value: "1"
          command:
            - bash
            - "-c"
            - |
              set -ex
              #从pod序号索引生成 mysql server-id
              [[ `cat /etc/hostname` =~ -([0-9]+)$ ]] || exit 1
              ordinal=${BASH_REMATCH[1]}
              echo [mysqld] > /mnt/conf.d/server-id.cnf
              #添加偏移量以避免使用 server-id=0 这一保留值
              echo server-id=$((100 + $ordinal)) >> /mnt/conf.d/server-id.cnf
              #将合适的conf.d文件从config-map复制到emptyDir
              if [[ $ordinal -eq 0 ]]; then
                cp /mnt/config-map/primary.cnf /mnt/conf.d/
              else
                cp /mnt/config-map/replica.cnf /mnt/conf.d/
              fi
          volumeMounts:
            - name: conf
              mountPath: /mnt/conf.d
            - name: config-map
              mountPath: /mnt/config-map
        - name: clone-mysql
          image: ist0ne/xtrabackup:1.0
          command:
            - bash
            - "-c"
            - |
              set -ex
              #如果已有数据,则跳过克隆
              [[ -d /var/lib/mysql/mysql ]] && exit 0
              #跳过主实例(序号索引 0)的克隆
              [[ `hostname` =~ -([0-9]+)$ ]] || exit 1
              ordinal=${BASH_REMATCH[1]}
              [[ $ordinal -eq 0 ]] && exit 0
              #从原来的对等节点克隆数据
              ncat --recv-only mysql-$(($ordinal-1)).mysql 3307 | xbstream -x -C /var/lib/mysql
              #准备备份,对数据进行整理
              xtrabackup --prepare --target-dir=/var/lib/mysql
          volumeMounts:
            - name: data
              mountPath: /var/lib/mysql
              subPath: mysql
            - name: conf
              mountPath: /etc/mysql/conf.d
      containers:
        - name: mysql
          image: mysql:5.7
          env:
            - name: MYSQL_ALLOW_EMPTY_PASSWORD
              value: "1"
          ports:
            - containerPort: 3306
          volumeMounts:
            - name: data
              mountPath: /var/lib/mysql
              subPath: mysql
            - name: conf
              mountPath: /etc/mysql/conf.d
          resources:
            requests:
              cpu: 200m
              memory: 500Mi
          livenessProbe:
            exec:
              command: ["mysqladmin", "ping"]
            initialDelaySeconds: 30
            periodSeconds: 10
            timeoutSeconds: 5
          readinessProbe:
            exec:
              command: ["mysql", "-e", "SELECT 1"]
            initialDelaySeconds: 15
            periodSeconds: 2
            timeoutSeconds: 1
        - name: xtrabackup
          image: ist0ne/xtrabackup:1.0
          ports:
            - containerPort: 3307
          command:
            - bash
            - "-c"
            - |
              set -ex
              cd /var/lib/mysql
              #如果有克隆数据后产生的文件,从此文件确定binlog位置
              if [[ -f xtrabackup_slave_info && "x$(<xtrabackup_slave_info)" != "x" ]]; then
                #XtraBackup已经生成了部分的“CHANGE MASTER TO”查询,需要删除末尾的分号
                cat xtrabackup_slave_info | sed -E 's/;$//g' > change_master_to.sql.in
                #生成语句后,原来的就不再需要
                rm -f xtrabackup_slave_info xtrabackup_binlog_info

              elif [[ -f xtrabackup_binlog_info ]]; then
                #直接从主实例进行克隆。解析binlog位置
                [[ `cat xtrabackup_binlog_info` =~ ^(.*?)[[:space:]]+(.*?)$ ]] || exit 1
                rm -f xtrabackup_binlog_info xtrabackup_slave_info
                echo "CHANGE MASTER TO MASTER_LOG_FILE='${BASH_REMATCH[1]}',\
                      MASTER_LOG_POS=${BASH_REMATCH[2]}" > change_master_to.sql.in
              fi

              #检查是否需要主从复制
              if [[ -f change_master_to.sql.in ]]; then
                echo "Waiting mysqld start"
                #循环查看mysql状态,直到mysqld启动完成,可以连接上
                until mysql -h 127.0.0.1 -e "SELECT 1"; do sleep 1; done
                echo "Initializing replication from clone position"
                #从库执行前面生成的sql,完成主从复制
                mysql -h 127.0.0.1 \
                      -e "$(<change_master_to.sql.in), \
                              MASTER_HOST='mysql-0.mysql', \
                              MASTER_USER='root', \
                              MASTER_PASSWORD='', \
                              MASTER_CONNECT_RETRY=10; \
                            START SLAVE;" || exit 1
                #如果容器重新启动,最多尝试一次
                mv change_master_to.sql.in change_master_to.sql.orig
              fi

              #当对等点请求时,启动服务器发送备份
              exec ncat --listen --keep-open --send-only --max-conns=1 3307 -c \
                "xtrabackup --backup --slave-info --stream=xbstream --host=127.0.0.1 --user=root"
          volumeMounts:
            - name: data
              mountPath: /var/lib/mysql
              subPath: mysql
            - name: conf
              mountPath: /etc/mysql/conf.d
          resources:
            requests:
              cpu: 100m
              memory: 100Mi
      
  volumeClaimTemplates:
    - metadata:
        name: data
      spec:
        accessModes: ["ReadWriteOnce"]
        resources:
          requests:
            storage: 5Gi
posted @ 2022-09-02 15:14  suyanhj  阅读(129)  评论(0编辑  收藏  举报