Kubernetesx学习之路

Master节点和Node节点概念

Master节点

Master节点是Kubernetes集群的控制节点,在生产环境中不建议部署集群核心组件外的任何Pod,公司业务的Pod更是不建议部署到Master节点上,以免升级或者维护时对业务造成影响。

Master节点的组件包括:

APIServer:APIServer是整个集群的控制中枢,提供集群中各个模块之间的数据交换,并将集群状态和信息存储到分布式键-值(key-value)存储系统Etcd集群中。同时它也是集群管理、资源配额、提供完备的集群安全机制的入口,为集群各类资源对象提供增删改查以及watch的REST API接口。APIServer作为Kubernetes的关键组件,使用Kubernetes API和 JSON over HTTP提供Kubernetes的内部和外部接口。

Scheduler:Scheduler是集群Pod的调度中心,主要是通过调度算法将Pod分配到最佳的节点(Node),它通过APIServer监听所有Pod的状态,一旦发现新的未被调度到任何Node节点的Pod(PodSpec.NodeName为空),就会根据一系列策略选择最佳节点进行调度,对每一个Pod创建一个绑定(binding),然后被调度的节点上的Kubelet负责启动该Pod。Scheduler是集群可插拔式组件,它跟踪每个节点上的资源利用率以确保工作负载不会超过可用资源。因此Scheduler必须知道资源需求、资源可用性以及其他约束和策略,例如服务质量、亲和力/反关联性要求、数据位置等。Scheduler将资源供应与工作负载需求相匹配以维持系统的稳定和可靠,因此Scheduler在调度的过程中需要考虑公平、资源高效利用、效率等方面的问题。

Controller Manager: Controller Manager是集群状态管理器(它的英文直译名为控制器管理器),以保证Pod或其他资源达到期望值。当集群中某个Pod的副本数或其他资源因故障和错误导致无法正常运行,没有达到设定的值时,Controller Manager会尝试自动修复并使其达到期望状态。Controller Manager包含NodeController、ReplicationController、EndpointController、NamespaceController、ServiceAccountController、ResourceQuotaController、ServiceController和TokenController,该控制器管理器可与API服务器进行通信以在需要时创建、更新或删除它所管理的资源,如Pod、服务断点等。

Etcd: Etcd由CoreOS开发,用于可靠地存储集群的配置数据,是一种持久性、轻量型、分布式的键-值(key-value)数据存储组件。Etcd作为Kubernetes集群的持久化存储系统,集群的灾难恢复、状态信息存储都与其密不可分,所以在Kubernetes高可用集群中,Etcd的高可用是至关重要的一部分,在生产环境中建议部署为大于3的奇数个数的Etcd,以保证数据的安全性和可恢复性。Etcd可与Master组件部署在同一个节点上,大规模集群环境下建议部署在集群外,并且使用高性能服务器来提高Etcd的性能和降低Etcd同步数据的延迟。

Node节点

Node节点也被称为Worker或Minion,是主要负责部署容器(工作负载)的单机(或虚拟机),集群中的每个节点都必须具备容器的运行环境(runtime),比如Docker及其他组件等。
Kubelet作为守护进程运行在Node节点上,负责监听该节点上所有的Pod,同时负责上报该节点上所有Pod的运行状态,确保节点上的所有容器都能正常运行。当Node节点宕机(NotReady状态)时,该节点上运行的Pod会被自动地转移到其他节点上。

Node节点包括:
Kubelet: 负责与Master通信协作,管理该节点上的Pod。

Kube-Proxy: 负责各Pod之间的通信和负载均衡。

Docker Engine: Docker引擎,负载对容器的管理。

Pod概念

什么是Pod?

Pod可简单地理解为是一组、一个或多个容器,具有共享存储/网络及如何运行容器的规范。Pad包含一个或多个相对紧密耦合的应用程序容器,处于同一个Pod中的容器共享同样的存储空间(Volume,卷或存储卷)、IP地址和Port端口,容器之间使用localhost:port相互访问。根据Docker的构造,Pod可被建模为一组具有共享命令空间、卷、IP地址和Port端口的Docker容器。
Pod包含的容器最好是一个容器只运行一个进程。每个Pod包含一个pause容器,pause容器是Pod的父容器,它主要负责僵尸进程的回收管理。
Kubernetes为每个Pod都分配一个唯一的IP地址,这样就可以保证应用程序使用同一端口,避免了发生冲突的问题。

Pod字段解析

apiVersion: v1 # 必选,API的版本号
kind: Pod	# 必选,类型Pod
metadata:	# 必选,元数据
  name: nginx	# 必选,符合RFC 1035规范的Pod名称
  namespace: web-testing # 可选,不指定默认为default,Pod所在的命名空间
  labels:	# 可选,标签选择器,一般用于Selector
    - app: nginx
  annotations:	# 可选,注释列表
    - app: nginx
spec:	# 必选,用于定义容器的详细信息
  containers:	# 必选,容器列表
  - name: nginx	# 必选,符合RFC 1035规范的容器名称
    image: nginx: v1	# 必选,容器所用的镜像的地址
    imagePullPolicy: Always	# 可选,镜像拉取策略
	command: 
	- nginx	# 可选,容器启动执行的命令
	- -g
	- "daemon off;"
		workingDir: /usr/share/nginx/html	# 可选,容器的工作目录
		volumeMounts:	# 可选,存储卷配置
		- name: webroot # 存储卷名称
		  mountPath: /usr/share/nginx/html # 挂载目录
		  readOnly: true	# 只读
		ports:	# 可选,容器需要暴露的端口号列表
		- name: http	# 端口名称
		  containerPort: 80	# 端口号
		  protocol: TCP	# 端口协议,默认TCP
		env:	# 可选,环境变量配置
		- name: TZ	# 变量名
		  value: Asia/Shanghai
		- name: LANG
		  value: en_US.utf8
		resources:	# 可选,资源限制和资源请求限制
		  limits:	# 最大限制设置
			cpu: 1000m
			memory: 1024MiB
		  requests:	# 启动所需的资源
			cpu: 100m
			memory: 512MiB
		readinessProbe:	# 可选,容器状态检查
		httpGet:	# 检测方式
			path: /	# 检查路径
			port: 80	# 监控端口
		  timeoutSeconds: 2	# 超时时间 
		  initialDelaySeconds: 60	# 初始化时间
		livenessProbe:	# 可选,监控状态检查
		  exec:	# 检测方式
			command: 
			- cat
			- /health
		  httpGet:	# 检测方式
			path: /_health
			port: 8080
			httpHeaders:
			- name: end-user
			  value: jason
		  tcpSocket:	# 检测方式
			port: 80
		  initialDelaySeconds: 60	# 初始化时间
		  timeoutSeconds: 2	# 超时时间
		  periodSeconds: 5	# 检测间隔
		  successThreshold: 2 # 检查成功为2次表示就绪
		  failureThreshold: 1 # 检测失败1次表示未就绪
		securityContext:	# 可选,限制容器不可信的行为
		  provoleged: false
	  restartPolicy: Always	# 可选,默认为Always
	  nodeSelector:	# 可选,指定Node节点
		region: subnet7
	  imagePullSecrets:	# 可选,拉取镜像使用的secret
	  - name: default-dockercfg-86258
	  hostNetwork: false	# 可选,是否为主机模式,如是,会占用主机端口
	  volumes:	# 共享存储卷列表
	  - name: webroot # 名称,与上述对应
		emptyDir: {}	# 共享卷类型,空
		hostPath:		# 共享卷类型,本机目录
		  path: /etc/hosts
		secret:	# 共享卷类型,secret模式,一般用于密码
		  secretName: default-token-tf2jp # 名称
		  defaultMode: 420 # 权限
		  configMap:	# 一般用于配置文件
		  name: nginx-conf
		  defaultMode: 420

Deployment

虽然ReplicaSet可以确保在任何给定时间运行的Pod副本达到指定的数量,但是Deployment(部署)是一个更高级的概念,它管理ReplicaSet并为Pod和ReplicaSet提供声明性更新以及许多其他有用的功能,所以建议在实际使用中,使用Deployment代替ReplicaSet。

如果在Deployment对象中描述了所需的状态,Deployment控制器就会以可控制的速率将实际状态更改为期望状态。也可以在Deployment中创建新的ReplicaSet,或者删除现有的Deployment并使用新的Deployment部署所用的资源。

创建Deployment

创建一个Deployment文件,并命名为dc-nginx.yaml,用于部署三个Nginx Pod:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  labels:
    app: nginx
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.7.9
        ports:
        - containerPort: 80

示例解析:

  • nginx-deployment:Deployment的名称。

  • replicas: 创建Pod的副本数。

  • selector:定义Deployment如何找到要管理的Pod,与template的label(标签)对应。

  • template字段包含以下字段:

    • app: nginx使用label(标签)标记Pod
    • spec:表示Pod运行一个名字为nginx的容器。
    • image:运行此Pod使用的镜像
    • Port:容器用于发送和接收流量的端口

使用kubectl create创建此Deployment:

[root@k8s-master01 2.2.8.1]# kubectl create -f dc-nginx.yaml 
deployment.apps/nginx-deployment created

使用kubectl get或者kubectl describe查看此Deployment:

[root@k8s-master01 2.2.8.1]# kubectl get deploy
NAME        DESIRED  CURRENT  UP-TO-DATE  AVAILABLE  AGE
nginx-deployment  3     3     3      1      60s

其中:

  • NAME:集群中Deployment的名称。

  • DESIRED:应用程序副本数。

  • CURRENT:当前正在运行的副本数。

  • UP-TO-DATE:显示已达到期望状态的被更新的副本数。

  • AVAILABLE:显示用户可以使用的应用程序副本数,当前为1,因为部分Pod仍在创建过程中。

  • AGE:显示应用程序运行的时间。

查看此时Deployment rollout的状态:

[root@k8s-master01 2.2.8.1]# kubectl rollout status deployment/nginx-deployment
deployment "nginx-deployment" successfully rolled out

再次查看此Deployment:

[root@k8s-master01 2.2.8.1]# kubectl get deploy
NAME        DESIRED  CURRENT  UP-TO-DATE  AVAILABLE  AGE
nginx-deployment  3     3     3      3      11m

查看此Deployment创建的ReplicaSet:

[root@k8s-master01 2.2.8.1]# kubectl get rs
NAME             DESIRED  CURRENT  READY  AGE
nginx-deployment-5c689d88bb  3     3     3    12m

查看此Deployment创建的Pod:

[root@k8s-master01 2.2.8.1]# kubectl get pods --show-labels
NAME                READY  STATUS  RESTARTS  AGE  LABELS
nginx-deployment-5c689d88bb-6b95k  1/1   Running  0     13m  app=nginx,pod-template-hash=5c689d88bb
nginx-deployment-5c689d88bb-9z5z2  1/1   Running  0     13m  app=nginx,pod-template-hash=5c689d88bb
nginx-deployment-5c689d88bb-jc8hr  1/1   Running  0     13m  app=nginx,pod-template-hash=5c689d88bb

更新Deployment

一般对应用程序升级或者版本迭代时,会通过Deployment对Pod进行滚动更新。

假如更新Nginx Pod的image使用nginx:1.9.1:

[root@k8s-master01 2.2.8.1]# kubectl set image deployment nginx-deployment nginx=nginx:1.9.1 --record
deployment.extensions/nginx-deployment image updated

当然也可以直接编辑Deployment,效果相同:

[root@k8s-master01 2.2.8.1]#  kubectl edit deployment.v1.apps/nginx-deployment
deployment.apps/nginx-deployment edited

使用kubectl rollout status查看更新状态:

[root@k8s-master01 2.2.8.1]# kubectl rollout status deployment.v1.apps/nginx-deployment
Waiting for deployment "nginx-deployment" rollout to finish: 1 out of 3 new replicas have been updated...
Waiting for deployment "nginx-deployment" rollout to finish: 2 out of 3 new replicas have been updated...
Waiting for deployment "nginx-deployment" rollout to finish: 2 out of 3 new replicas have been updated...
Waiting for deployment "nginx-deployment" rollout to finish: 2 out of 3 new replicas have been updated...
Waiting for deployment "nginx-deployment" rollout to finish: 1 old replicas are pending termination...
Waiting for deployment "nginx-deployment" rollout to finish: 1 old replicas are pending termination...
deployment "nginx-deployment" successfully rolled out

查看ReplicaSet:

[root@k8s-master01 2.2.8.1]# kubectl get rs 
NAME             DESIRED  CURRENT  READY  AGE
nginx-deployment-5c689d88bb  0     0     0    34m
nginx-deployment-6987cdb55b  3     3     3    5m14s

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

[root@k8s-master01 2.2.8.1]# kubectl describe deploy nginx-deployment
Name:          nginx-deployment
Namespace:       default
CreationTimestamp:   Thu, 24 Jan 2019 15:15:15 +0800
Labels:         app=nginx
Annotations:      deployment.kubernetes.io/revision: 2
​            kubernetes.io/change-cause: kubectl set image deployment nginx-deployment nginx=nginx:1.9.1 --record=true
Selector:        app=nginx
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
 Containers:
  nginx:
  Image:    nginx:1.9.1
  Port:     80/TCP
  Host Port:  0/TCP
  Environment: <none>
  Mounts:    <none>
 Volumes:    <none>
Conditions:
 Type      Status Reason
 ----      ------ ------
 Available   True  MinimumReplicasAvailable
 Progressing  True  NewReplicaSetAvailable
OldReplicaSets: <none>
NewReplicaSet:  nginx-deployment-6987cdb55b (3/3 replicas created)
Events:
 Type  Reason       Age  From          Message
 ----  ------       ----  ----          -------
 Normal ScalingReplicaSet 36m  deployment-controller Scaled up replica set nginx-deployment-5c689d88bb to 3
 Normal ScalingReplicaSet 7m16s deployment-controller Scaled up replica set nginx-deployment-6987cdb55b to 1
 Normal ScalingReplicaSet 5m18s deployment-controller Scaled down replica set nginx-deployment-5c689d88bb to 2
 Normal ScalingReplicaSet 5m18s deployment-controller Scaled up replica set nginx-deployment-6987cdb55b to 2
 Normal ScalingReplicaSet 4m35s deployment-controller Scaled down replica set nginx-deployment-5c689d88bb to 
 Normal ScalingReplicaSet 4m34s deployment-controller Scaled up replica set nginx-deployment-6987cdb55b to 3
 Normal  ScalingReplicaSet  3m30s  deployment-controller  Scaled down replica set nginx-deployment-5c689d88bb to 0

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

回滚Deployment

当新版本不稳定时,可以对其进行回滚操作,默认情况下,所有Deployment的rollout历史都保留在系统中,可以随时回滚。

假设我们又进行了几次更新:

[root@k8s-master01 2.2.8.1]# kubectl set image deployment nginx-deployment nginx=dotbalo/canary:v1 --record

[root@k8s-master01 2.2.8.1]# kubectl set image deployment nginx-deployment nginx=dotbalo/canary:v2 --record

使用kubectl rollout history查看部署历史:

[root@k8s-master01 2.2.8.1]# kubectl rollout history deployment/nginx-deployment
deployment.extensions/nginx-deployment
REVISION CHANGE-CAUSE
1     <none>
2     kubectl set image deployment nginx-deployment nginx=nginx:1.9.1 --record=true
3     kubectl set image deployment nginx-deployment nginx=dotbalo/canary:v1 --record=true
4     kubectl set image deployment nginx-deployment nginx=dotbalo/canary:v2 --record=true

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

[root@k8s-master01 2.2.8.1]# kubectl rollout history deployment.v1.apps/nginx-deployment --revision=3
deployment.apps/nginx-deployment with revision #3
Pod Template:
 Labels:  app=nginx
  pod-template-hash=645959bf6b
 Annotations: kubernetes.io/change-cause: kubectl set image deployment nginx-deployment nginx=dotbalo/canary:v1 --record=true
 Containers:
  nginx:
  Image: dotbalo/canary:v1
  Port:  80/TCP
  Host Port: 0/TCP
  Environment: <none>
  Mounts: <none>
 Volumes: <none>

使用kubectl rollout undo回滚到上一个版本:

[root@k8s-master01 2.2.8.1]# kubectl rollout undo deployment.v1.apps/nginx-deployment
deployment.apps/nginx-deployment

再次查看更新历史,发现REVISION5回到了canary:v1:

[root@k8s-master01 2.2.8.1]# kubectl rollout history deployment/nginx-deployment
deployment.extensions/nginx-deployment
REVISION CHANGE-CAUSE
1     <none>
2     kubectl set image deployment nginx-deployment nginx=nginx:1.9.1 --record=true
4     kubectl set image deployment nginx-deployment nginx=dotbalo/canary:v2 --record=true
5     kubectl set image deployment nginx-deployment nginx=dotbalo/canary:v1 --record=true

使用--to-revision参数回到指定版本:

[root@k8s-master01 2.2.8.1]# kubectl rollout undo deployment/nginx-deployment --to-revision=2
deployment.extensions/nginx-deployment

扩展Deployment

当公司访问量变大,三个Pod已无法支撑业务时,可以对其进行扩展。

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

[root@k8s-master01 2.2.8.1]# kubectl scale deployment.v1.apps/nginx-deployment --replicas=5
deployment.apps/nginx-deployment scaled

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

[root@k8s-master01 2.2.8.1]# kubectl get po
NAME                READY  STATUS  RESTARTS  AGE
nginx-deployment-5f89547d9c-5r56b  1/1   Running  0     90s
nginx-deployment-5f89547d9c-htmn7  1/1   Running  0     25s
nginx-deployment-5f89547d9c-nwxs2  1/1   Running  0     99s
nginx-deployment-5f89547d9c-rpwlg  1/1   Running  0     25s
nginx-deployment-5f89547d9c-vlr5p  1/1   Running  0     95s

暂停和恢复Deployment更新

Deployment支持暂停更新,用于对Deployment进行多次修改操作。

使用kubectl rollout pause暂停Deployment更新:

[root@k8s-master01 2.2.8.1]# kubectl rollout pause deployment/nginx-deployment
deployment.extensions/nginx-deployment paused

然后对Deployment进行相关更新操作,比如更新镜像,然后对其资源进行限制:

[root@k8s-master01 2.2.8.1]# kubectl set image deployment.v1.apps/nginx-deployment nginx=nginx:1.9.1
deployment.apps/nginx-deployment image updated

[root@k8s-master01 2.2.8.1]# kubectl set resources deployment.v1.apps/nginx-deployment -c=nginx --limits=cpu=200m,memory=512Mi
deployment.apps/nginx-deployment resource requirements updated

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

[root@k8s-master01 2.2.8.1]# kubectl rollout history deployment.v1.apps/nginx-deployment
deployment.apps/nginx-deployment
REVISION CHANGE-CAUSE
1     <none>
5     kubectl set image deployment nginx-deployment nginx=dotbalo/canary:v1 --record=true
7     kubectl set image deployment nginx-deployment nginx=dotbalo/canary:v2 --record=true
8     kubectl set image deployment nginx-deployment nginx=dotbalo/canary:v2 --record=true

使用kubectl rollout resume恢复Deployment更新:

[root@k8s-master01 2.2.8.1]# kubectl rollout resume deployment.v1.apps/nginx-deployment
deployment.apps/nginx-deployment resumed

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

[root@k8s-master01 2.2.8.1]# kubectl get rs
NAME             DESIRED  CURRENT  READY  AGE
nginx-deployment-57895845b8  5     5     4    11s

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

[root@k8s-master01 2.2.8.1]# kubectl describe deploy nginx-deployment
Name:          nginx-deployment
Namespace:       default
CreationTimestamp:   Thu, 24 Jan 2019 15:15:15 +0800
Labels:         app=nginx
Annotations:      deployment.kubernetes.io/revision: 9
​            kubernetes.io/change-cause: kubectl set image deployment nginx-deployment nginx=dotbalo/canary:v2 --record=true
Selector:        app=nginx
Replicas:        5 desired | 5 updated | 5 total | 5 available | 0 unavailable
StrategyType:      RollingUpdate
MinReadySeconds:    0
RollingUpdateStrategy: 25% max unavailable, 25% max surge
Pod Template:
 Labels: app=nginx
 Containers:
  nginx:
  Image:   nginx:1.9.1
  Port:    80/TCP
  Host Port: 0/TCP

更新Deployment的注意事项

清理策略:

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

更新策略:

  • .spec.strategy.type==Recreate,表示重建,先删掉旧的Pod再创建新的Pod。

  • .spec.strategy.type==RollingUpdate,表示滚动更新,可以指定maxUnavailable和maxSurge来控制滚动更新过程。

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

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

StatefulSet

StatefulSet(有状态集)常用于部署有状态的且需要有序启动的应用程序。

StatefulSet的基本概念

StatefulSet主要用于管理有状态应用程序的工作负载API对象。比如在生产环境中,可以部署ElasticSearch集群、MongoDB集群或者需要持久化的RabbitMQ集群、Redis集群、Kafka集群和ZooKeeper集群等。

而StatefulSet创建的Pod一般使用Headless Service(无头服务)进行通信,和普通的Service的区别在于Headless Service没有ClusterIP,它使用的是Endpoint进行互相通信,Headless一般的格式为

statefulSetName-{0..N-1}.serviceName.namespace.svc.cluster. local。

说明:

  • serviceName为Headless Service的名字。

  • 0..N-1为Pod所在的序号,从0开始到N-1。

  • statefulSetName为StatefulSet的名字。

  • namespace为服务所在的命名空间。

  • .cluster.local为Cluster Domain(集群域)。

比如,一个Redis主从架构,Slave连接Master主机配置就可以使用不会更改的Master的Headless Service,例如Redis从节点(Slave)配置文件如下:

port 6379
slaveofredis-sentinel-master-ss-0.redis-sentinel-master-ss.public-service.svc.cluster.local 6379
tcp-backlog 511
timeout 0
tcp-keepalive 0
……

其中,redis-sentinel-master-ss-0.redis-sentinel-master-ss.public-service.svc.cluster.local是Redis Master的Headless Service。

StatefulSet组件

定义一个简单的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:
 serviceName: "nginx"
 replicas: 2
 template:
  metadata:
   labels:
     app: nginx
  spec:
   containers:
   - name: nginx
     image: nginx
     ports:
     - containerPort: 80
       name: web

其中,

  • kind: Service定义了一个名字为Nginx的Headless Service,创建的Service格式为nginx-0.nginx.default.svc.cluster.local,其他的类似,因为没有指定Namespace(命名空间),所以默认部署在default。

  • kind: StatefulSet定义了一个名字为web的StatefulSet,replicas表示部署Pod的副本数,本实例为2。

创建StatefulSet

创建StatefulSet:

[root@k8s-master01 2.2.7]# kubectl create -f sts-web.yaml 
service/nginx created
statefulset.apps/web created

[root@k8s-master01 2.2.7]# kubectl get sts
NAME  DESIRED  CURRENT  AGE
web  2     2     12s

[root@k8s-master01 2.2.7]# kubectl get svc
NAME     TYPE    CLUSTER-IP  EXTERNAL-IP  PORT(S)  AGE
kubernetes  ClusterIP  10.96.0.1  <none>    443/TCP  7d2h
nginx    ClusterIP  None     <none>    80/TCP  16s

[root@k8s-master01 2.2.7]# kubectl get po -l app=nginx
NAME  READY  STATUS  RESTARTS  AGE
web-0  1/1   Running  0     2m5s
web-1  1/1   Running  0     115s

StatefulSet扩容和缩容

和Deployment类似,可以通过更新replicas字段扩容/缩容StatefulSet,也可以使用kubectlscale或者kubectlpatch来扩容/缩容一个StatefulSet。

扩容

将上述创建的sts副本增加到5个(扩容之前必须保证有创建完成的静态PV,动态PV和emptyDir):

[root@k8s-master01 2.2.7]# kubectl scale sts web --replicas=5
statefulset.apps/web scaled

查看Pod状态:

[root@k8s-master01 2.2.7]# kubectl get po
NAME   READY  STATUS  RESTARTS  AGE
web-0  1/1   Running  0     2m58s
web-1  1/1   Running  0     2m48s
web-2  1/1   Running  0     116s
web-3  1/1   Running  0     79s
web-4  1/1   Running  0     53s

也可使用以下命令动态查看:

# kubectl get pods -w -l app=nginx
缩容

在一个终端动态查看:

[root@k8s-master01 2.2.7]# kubectl get pods -w -l app=nginx
NAME  READY  STATUS  RESTARTS  AGE
web-0  1/1   Running  0     4m37s
web-1  1/1   Running  0     4m27s
web-2  1/1   Running  0     3m35s
web-3  1/1   Running  0     2m58s
web-4  1/1   Running  0     2m32s

在另一个终端将副本数改为3:

[root@k8s-master01 ~]# kubectl patch sts web -p '{"spec":{"replicas":3}}'
statefulset.apps/web patched

此时可以看到第一个终端显示web-4和web-3的Pod正在被删除(或终止):

[root@k8s-master01 2.2.7]# kubectl get pods -w -l app=nginx
NAME  READY  STATUS  RESTARTS  AGE
web-0  1/1   Running  0     4m37s
web-1  1/1   Running  0     4m27s
web-2  1/1   Running  0     3m35s
web-3  1/1   Running  0     2m58s
web-4  1/1   Running  0     2m32s
web-0  1/1  Running  0   5m8s
web-0  1/1  Running  0   5m11s
web-4  1/1  Terminating  0   3m36s
web-4  0/1  Terminating  0   3m38s
web-4  0/1  Terminating  0   3m47s
web-4  0/1  Terminating  0   3m47s
web-3  1/1  Terminating  0   4m13s
web-3  0/1  Terminating  0   4m14s
web-3  0/1  Terminating  0   4m22s
web-3  0/1  Terminating  0   4m22s

更新策略

On Delete策略

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

RollingUpdate策略

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

比如Patch一个名称为web的StatefulSet来执行RollingUpdate更新:

[root@k8s-master01 2.2.7]# kubectl patch statefulset web -p '{"spec":{"updateStrategy":{"type":"RollingUpdate"}}}'
statefulset.apps/web patched

查看更改后的StatefulSet:

[root@k8s-master01 2.2.7]# kubectl get sts web -o yaml | grep -A 1 "updateStrategy"
 updateStrategy:
  type: RollingUpdate

然后改变容器的镜像进行滚动更新:

[root@k8s-master01 2.2.7]# kubectl patch statefulset web --type='json' -p='[{"op": "replace", "path": "/spec/template/spec/containers/0/image", "value":"dotbalo/canary:v1"}]'
statefulset.apps/web patched

如上所述,StatefulSet里的Pod采用和序号相反的顺序更新。在更新下一个Pod前,StatefulSet控制器会终止每一个Pod并等待它们变成Running和Ready状态。在当前顺序变成Running和Ready状态之前,StatefulSet控制器不会更新下一个Pod,但它仍然会重建任何在更新过程中发生故障的Pod,使用它们当前的版本。已经接收到请求的Pod将会被恢复为更新的版本,没有收到请求的Pod则会被恢复为之前的版本。

在更新过程中可以使用 kubectl rollout status sts/ 来查看滚动更新的状态:

[root@k8s-master01 2.2.7]# kubectl rollout status sts/web
Waiting for 1 pods to be ready...
waiting for statefulset rolling update to complete 1 pods at revision web-56b5798f76...
Waiting for 1 pods to be ready...
Waiting for 1 pods to be ready...
waiting for statefulset rolling update to complete 2 pods at revision web-56b5798f76...
Waiting for 1 pods to be ready...
Waiting for 1 pods to be ready...
statefulset rolling update complete 3 pods at revision web-56b5798f76...

查看更新后的镜像:

[root@k8s-master01 2.2.7]# for p in 0 1 2; do kubectl get po web-$p --template '{{range $i, $c := .spec.containers}}{{$c.image}}{{end}}'; echo; done
dotbalo/canary:v1
dotbalo/canary:v1
dotbalo/canary:v1
分段更新

StatefulSet可以使用RollingUpdate更新策略的partition参数来分段更新一个StatefulSet。分段更新将会使StatefulSet中其余的所有Pod(序号小于分区)保持当前版本,只更新序号大于等于分区的Pod,利用此特性可以简单实现金丝雀发布(灰度发布)或者分阶段推出新功能等。注:金丝雀发布是指在黑与白之间能够平滑过渡的一种发布方式。

比如我们定义一个分区"partition":3,可以使用patch直接对StatefulSet进行设置:

# kubectl patch statefulset web -p '{"spec":{"updateStrategy":{"type":"RollingUpdate","rollingUpdate":{"partition":3}}}}'
statefulset "web" patched

然后再次patch改变容器的镜像:

# kubectl patch statefulset web --type='json' -p='[{"op": "replace", "path": "/spec/template/spec/containers/0/image", "value":"k8s.gcr.io/nginx-slim:0.7"}]'
statefulset "web" patched

删除Pod触发更新:

#kubectl delete po web-2
pod "web-2" deleted

此时,因为Pod web-2的序号小于分区3,所以Pod不会被更新,还是会使用以前的容器恢复Pod。

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

# kubectl patch statefulset web -p '{"spec":{"updateStrategy":{"type":"RollingUpdate","rollingUpdate":{"partition":2}}}}'
statefulset "web" patched

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

[root@k8s-master01 2.2.7]# for p in 0 1 2; do kubectl get po web-$p --template '{{range $i, $c := .spec.containers}}{{$c.image}}{{end}}'; echo; done
dotbalo/canary:v1
dotbalo/canary:v1
dotbalo/canary:v2

删除StatefulSet

删除StatefulSet有两种方式,即级联删除和非级联删除。使用非级联方式删除StatefulSet时,StatefulSet的Pod不会被删除;使用级联删除时,StatefulSet和它的Pod都会被删除。

非级联删除

使用kubectldeletestsxxx删除StatefulSet时,只需提供--cascade=false参数,就会采用非级联删除,此时删除StatefulSet不会删除它的Pod:

[root@k8s-master01 2.2.7]# kubectl get po 
NAME  READY  STATUS  RESTARTS  AGE
web-0  1/1   Running  0     16m
web-1  1/1   Running  0     16m
web-2  1/1   Running  0     11m

[root@k8s-master01 2.2.7]# kubectl delete statefulset web --cascade=false
statefulset.apps "web" deleted

[root@k8s-master01 2.2.7]# kubectl get sts
No resources found.

[root@k8s-master01 2.2.7]# kubectl get po
NAME  READY  STATUS  RESTARTS  AGE
web-0  1/1   Running  0     16m
web-1  1/1   Running  0     16m
web-2  1/1   Running  0     11m

由于此时删除了StatefulSet,因此单独删除Pod时,不会被重建:

[root@k8s-master01 2.2.7]# kubectl get po
NAME  READY  STATUS  RESTARTS  AGE
web-0  1/1   Running  0     16m
web-1  1/1   Running  0     16m
web-2  1/1   Running  0     11m

[root@k8s-master01 2.2.7]# kubectl delete po web-0
pod "web-0" deleted

[root@k8s-master01 2.2.7]# kubectl get po
NAME  READY  STATUS  RESTARTS  AGE
web-1  1/1   Running  0     18m
web-2  1/1   Running  0     12m

当再次创建此StatefulSet时,web-0会被重新创建,web-1由于已经存在而不会被再次创建,因为最初此StatefulSet的replicas是2,所以web-2会被删除,如下(忽略AlreadyExists错误):

[root@k8s-master01 2.2.7]# kubectl create -f sts-web.yaml 
statefulset.apps/web created
Error from server (AlreadyExists): error when creating "sts-web.yaml": services "nginx" already exists
[root@k8s-master01 2.2.7]# kubectl get po
NAME  READY  STATUS  RESTARTS  AGE
web-0  1/1   Running  0     32s
web-1  1/1   Running  0     19m
级联删除

省略--cascade=false参数即为级联删除:

[root@k8s-master01 2.2.7]# kubectl delete statefulset web
statefulset.apps "web" deleted

[root@k8s-master01 2.2.7]# kubectl get po
No resources found.

也可以使用-f参数直接删除StatefulSet和Service(此文件将sts和svc写在了一起):

[root@k8s-master01 2.2.7]# kubectl delete -f sts-web.yaml 
service "nginx" deleted
Error from server (NotFound): error when deleting "sts-web.yaml": statefulsets.apps "web" not found

posted @ 2023-03-29 19:30  栩生  阅读(65)  评论(0)    收藏  举报