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(标签)标记Podspec:表示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

浙公网安备 33010602011771号