一、StatefulSet
1、StatefulSet介绍
StatefulSet是用于在Kubernetes集群中管理有状态应用的一种资源对象,比如Mysql、MongoDB等。有状态应用是指依赖持久性存储并且在集群重启后仍然保持状态的应用。StatefulSet可以确保有状态应用在集群中的唯一性和稳定性。
StatefulSet通过为每个Pod分配一个唯一的网络标识符和持久性存储卷来管理有状态应用。每个Pod在创建和销毁时,都会保留相同的标识符和存储卷,以便保持应用状态的连续性。与Deployment资源对象相比,StatefulSet具有以下特点: 1. 稳定的唯一标识符:每个Pod都有一个稳定的网络标识符,以便于进行有状态应用的服务发现和网络访问。 2. 有序的部署和扩展:根据定义的顺序,StatefulSet会逐个创建和删除Pod,确保有状态应用的顺序部署和扩展。 3. 稳定的持久化存储:每个Pod都会被分配一个独立的持久化存储卷,并且在Pod删除后存储卷不会被立即删除,以便于保留应用的数据。
在使用StatefulSet时,还可以配合其他Kubernetes资源对象如Service对象和VolumeClaimTemplates(后续会补充这些知识)来实现对有状态应用的服务发现和存储管理。
1.1、创建StatefulSet
apiVersion: v1
kind: Service #类型为Service
metadata: #元数据
name: nginx #名称
labels:
app: nginx #标签值
spec: #特别描述
selector: #标签
app: nginx #标签值
ports:
- port: 80 #端口
name: web #端口名称
clusterIP: None
---
apiVersion: apps/v1 #版本
kind: StatefulSet #statefulSet
metadata: #元数据
name: web #名称
spec:
selector:
matchLabels: #标签匹配
app: nginx #标签值,对应上面的标签
serviceName: "nginx" #上面定义的service那么的值
replicas: 3 #副本数
template: #模板
metadata:
labels:
app: nginx #标签值
spec:
containers: #容器
- name: nginx #容器名称
image: nginx:1.21.4 #镜像信息
ports:
- containerPort: 80 #暴露的端口
name: web
#创建资源
kubectl create -f web.yaml
#查看StatefulSet
kubectl get statefulset
#简写方式
kubectl get sts
#查看pod
kubectl get po
#创建busybox容器
kubectl run -it --image busybox:1.28.4 dns-test --rm /bin/sh
#进入容器查看网络
nslookup web-0.nginx
nslookup web-1.nginx
结论 :
- deployment创建的pod是根据随机字符串命名的,statefulSet是按照[0…N-1]顺序命名的。
- StatefulSet在Headless Service的基础上又为StatefulSet控制的每个Pod副本创建了一个DNS域名,这个域名的格式为:<pod名称>.<service名称>.<namespace名称>.svc.cluster.local。
2、StatefulSet扩容与缩容
#扩容,增加副本数
kubectl scale sts web --replicas=5
#修改配置文件
kubectl edit sts web
#或者
kubectl patch sts web -p '{"spec":{"replicas":5}}'
#缩容 减少副本数
kubectl scale sts web --replicas=3
#修改配置文件
kubectl edit sts web
#或者
kubectl patch sts web -p '{"spec":{"replicas":1}}'
3、StatefulSet更新策略
3.1、滚动更新
- RollingUpdate(默认):按顺序逐个更新Pod。新的Pod会在更新前先启动,待新Pod运行正常后,再删除旧的Pod。这种策略适用于需要保证应用持续可用性的情况。
- OnDelete:只有在旧的Pod被手动删除时才会启动新的Pod进行更新。这种策略适用于需要手动控制更新时机的情况,例如应用需要完成一些特定操作后才能进行更新。
- Partition:将每个Pod分成多个更新分区。每个分区内的Pod会按RollingUpdate策略进行更新,而不同分区的Pod则可以并行更新。这种策略适用于需要控制并行度的情况,例如更新影响范围较大时,可以将Pod分成多个分区以减轻更新对应用的影响。总之,Partition更新策略可以与RollingUpdate策略结合使用,通过划分多个更新分区并逐个更新Pods,以控制并行度和确保应用的稳定运行。其他更新策略,如OnDelete策略,不能与Partition更新策略一起使用。
从上图可以看出 StatefulSet是按照顺序滚动更新的。
3.2 、利用滚动更新实现灰度发布
apiVersion: v1
kind: Service #类型为Service
metadata: #元数据
name: nginx #名称
labels:
app: nginx #标签值
spec: #特别描述
selector: #标签
app: nginx #标签值
ports:
- port: 80 #端口
name: web #端口名称
clusterIP: None
---
apiVersion: apps/v1 #版本
kind: StatefulSet #statefulSet
metadata: #元数据
name: web #名称
spec:
selector:
matchLabels: #标签匹配
app: nginx #标签值,对应上面的标签
serviceName: "nginx" #上面定义的service那么的值
replicas: 3 #副本数
template: #模板
metadata:
labels:
app: nginx #标签值
spec:
containers: #容器
- name: nginx #容器名称
image: nginx:1.21.4 #镜像信息
ports:
- containerPort: 80 #暴露的端口
name: web
updateStrategy: #更新策略
rollingUpdate: #滚动更新
partition: 1 #只有大于等于该值的容器会更新
type: RollingUpdate
#创建资源
kubectl create -f web-gray.yaml
#修改镜像地址,将镜像版本修改为1.22.0
kubectl edit sts web
#分别查看镜像描述
kubectl describe po web-0
kubectl describe po web-1
kubectl describe po web-2
结论:只有大于等于partition配置的值的容器发生了更新。
3.3、删除更新
apiVersion: v1
kind: Service #类型为Service
metadata: #元数据
name: nginx #名称
labels:
app: nginx #标签值
spec: #特别描述
selector: #标签
app: nginx #标签值
ports:
- port: 80 #端口
name: web #端口名称
clusterIP: None
---
apiVersion: apps/v1 #版本
kind: StatefulSet #statefulSet
metadata: #元数据
name: web #名称
spec:
selector:
matchLabels: #标签匹配
app: nginx #标签值,对应上面的标签
serviceName: "nginx" #上面定义的service那么的值
replicas: 3 #副本数
template: #模板
metadata:
labels:
app: nginx #标签值
spec:
containers: #容器
- name: nginx #容器名称
image: nginx:1.21.4 #镜像信息
ports:
- containerPort: 80 #暴露的端口
name: web
updateStrategy: #更新策略
# rollingUpdate: #滚动更新
# partition: 1 #只有大于等于该值的容器会更新
type: OnDelete #删除更新
#创建资源
kubectl create -f web-ondelete.yaml
#修改镜像地址,将镜像版本修改为1.22.0
kubectl edit sts web
#查看版本信息
kubectl rollout history statefulset/web --revision=2
#查看描述,发现pod并没有更新
kubectl describe po web-0
#删除po web-0
kubectl delete po web-0
#查看po
kubectl get po
#查看描述
kubectl describe po web-0
结论:StatefulSet删除策略在把容器删除后,重新启动的容器才会发生更新。
4、StatefulSet级联删除
#默认为级联删除,即删掉StatefulSet的时候会级联着将Pod删除
kubectl delete sts web
#非级联删除
kubectl delete sts web --cascade=false
二、DaemonSet
1、DaemonSet使用场景
DaemonSet默认会在每个节点都调度一个Pod,一般这种应用场景为
- 在每个Node上都运行一个GlusterFS存储或者Ceph存储的Daemon进程。
- 在每个节点上都运行一个日志采集程序,例如Fluentd或者Logstach。
- 在每个节点都运行一个性能监控程序,采集Node的运行性能。
DaemonSet的Pod调度可以使用NodeSelector或者NodeAffinity(节点亲和性)来指定调度到相应的Node节点。
2、演示fluentd容器调度
apiVersion: apps/v1 #版本
kind: DaemonSet #类型为DaemonSet
metadata: #元数据
name: fluentd-log #名称
spec: #描述
selector: #选择器
matchLabels: #匹配标签
app: fluentd-log #标签值
template: #模板
metadata: #元数据
labels:
app: fluentd-log #标签值
spec:
nodeSelector:
role: micro_service #节点选择器,只有有这个标签的节点会运行改pod
containers: #容器
- name: fluentd-es #容器名称
image: fluentd:v1.17.1-1.0 #镜像地址
env: #环境变量配置
- name: FLUENTD_ARGS #环境便令key
value: -q #环境变量的值
volumeMounts: #加载数据卷,避免数据丢失
- mountPath: /var/lib/docker/containers #容器内地址
name: containers #数据卷名称
- mountPath: /var/log
name: var-log
volumes: #存储数据卷
- name: containers #数据卷的名称
hostPath: #主机路径与node共享目录
path: /var/lib/docker/containers #node中共享目录
- name: var-log
hostPath:
path: /var/log
#创建资源 ,可以看到部署到了有标签的节点
kubectl create -f fluentd.yaml
#查看pod
kubectl get po -o wide
#给节点打标签
kubectl label no node2 role=micro_service
三、自动扩/缩容 Horizontal Pod Autoscaler(HPA)
1、HPA工作原理
通过Metrics Server持续采集所有Pod副本的指标数据实现。HPA 控制器通过Metrics Server的API获取这些数据,基于用户定义的扩缩容规则进行计算得到目标Pod的副本数,当目标副本数与当前副本数不一致时,HPA控制器就向Pod的副本控制器(Deployment、ReplicaSet)发起scale操作,调整Pod的副本数完成扩缩容。
当存在以下情况时,副本数不会参与扩缩容的计算。
- Pod正在被删除,将不会计入目标副本数量。
- Pod的当前指标值无法获取,例如容器没有指定资源中的request和limit属性。
- Pod未达到Ready状态时,也暂时不会纳入目标副本数范围。
2、创建HPA
2.1、创建资源
apiVersion: v1 #版本号
kind: Namespace #类型为namespace
metadata: #元数据
name: wssnail-deploy #命名空间名称
---
apiVersion: apps/v1 #版本
kind: Deployment #类型为Deployment
metadata: #元数据
labels: #标签
app: my-nginx
name: my-nginx-deploy
namespace: wssnail-deploy #命名空间
spec: #描述
replicas: 1 #副本数量
revisionHistoryLimit: 10 #历史版本限制,用来回退,如果设置为0则没有回退
selector: #选择器
matchLabels: #按招标前匹配
app: my-nginx #标签的值
strategy:
rollingUpdate: #滚动更新策略
maxSurge: 25% #控制滚动更新过程中副本总数的超过期望值的上限。maxSurge 可以是具体的整数,也可以是百分百,向上取整。maxSurge 默认值为 25%,比如期望值是10,那么最大的副本数就是10+10*25%(向上取整)=13
maxUnavailable: 1 #不可用的副本相占期望值的最大比例。 maxUnavailable 可以是具体的整数,也可以是百分百,向下取整。maxUnavailable 默认值为 25%。比如期望值是10,那么副本数至少要为10-10*25%(向下取整)=8才认为是健康。
type: RollingUpdate #滚动更新 可选值 Recreate 、RollingUpdate 默认为RollingUpdate
template:
metadata:
labels:
app: my-nginx
spec: #容器描述
terminationGracePeriodSeconds: 30 #宽限时间
nodeSelector: #节点选择
role: micro_service #通过添加标签控制到那个节点上
containers:
- name: nginx-container
image: nginx:1.21.4
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
name: nginx-port
protocol: TCP
#创建资源
kubectl create -f my-nginx-deploy.yaml
2.2、添加资源限制替换配置文件
apiVersion: v1 #版本号
kind: Namespace #类型为namespace
metadata: #元数据
name: wssnail-deploy #命名空间名称
---
apiVersion: apps/v1 #版本
kind: Deployment #类型为Deployment
metadata: #元数据
labels: #标签
app: my-nginx
name: my-nginx-deploy
namespace: wssnail-deploy #命名空间
spec: #描述
replicas: 1 #副本数量
revisionHistoryLimit: 10 #历史版本限制,用来回退,如果设置为0则没有回退
selector: #选择器
matchLabels: #按招标前匹配
app: my-nginx #标签的值
strategy:
rollingUpdate: #滚动更新策略
maxSurge: 25% #控制滚动更新过程中副本总数的超过期望值的上限。maxSurge 可以是具体的整数,也可以是百分百,向上取整。maxSurge 默认值为 25%,比如期望值是10,那么最大的副本数就是10+10*25%(向上取整)=13
maxUnavailable: 1 #不可用的副本相占期望值的最大比例。 maxUnavailable 可以是具体的整数,也可以是百分百,向下取整。maxUnavailable 默认值为 25%。比如期望值是10,那么副本数至少要为10-10*25%(向下取整)=8才认为是健康。
type: RollingUpdate #滚动更新 可选值 Recreate 、RollingUpdate 默认为RollingUpdate
template:
metadata:
labels:
app: my-nginx
spec: #容器描述
terminationGracePeriodSeconds: 30 #宽限时间
nodeSelector: #节点选择
role: micro_service #通过添加标签控制到那个节点上
containers:
- name: nginx-container
image: nginx:1.21.4
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
name: nginx-port
protocol: TCP
resources:
limits:
memory: 170Mi
cpu: 200m
requests:
cpu: 100m
memory: 70Mi
#替换配置文件,注意这里的类型为Deployment
kubectl replace -f my-nginx-deploy.yaml
2.3、安装 Metrics Server
#安装wget工具
yum install wget -y
#下载资源文件重命名
wget https://github.com/kubernetes-sigs/metrics-server/releases/download/v0.7.1/components.yaml -O metrics-server-components.yaml
#更新镜像地址
sed -i 's/registry.k8s.io\/metrics-server/registry.cn-hangzhou.aliyuncs.com\/google_containers/g' metrics-server-components.yaml
#修改配置文件中的启动参数
#添加这一条,允许http
- --kubelet-insecure-tls
#修改这一条
- --kubelet-preferred-address-types=InternalIP,Hostname,InternalDNS,ExternalDNS,ExternalIP
完整的配置文件如下metrics-server-components.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
labels:
k8s-app: metrics-server
name: metrics-server
namespace: kube-system
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
labels:
k8s-app: metrics-server
rbac.authorization.k8s.io/aggregate-to-admin: "true"
rbac.authorization.k8s.io/aggregate-to-edit: "true"
rbac.authorization.k8s.io/aggregate-to-view: "true"
name: system:aggregated-metrics-reader
rules:
- apiGroups:
- metrics.k8s.io
resources:
- pods
- nodes
verbs:
- get
- list
- watch
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
labels:
k8s-app: metrics-server
name: system:metrics-server
rules:
- apiGroups:
- ""
resources:
- nodes/metrics
verbs:
- get
- apiGroups:
- ""
resources:
- pods
- nodes
verbs:
- get
- list
- watch
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
labels:
k8s-app: metrics-server
name: metrics-server-auth-reader
namespace: kube-system
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: extension-apiserver-authentication-reader
subjects:
- kind: ServiceAccount
name: metrics-server
namespace: kube-system
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
labels:
k8s-app: metrics-server
name: metrics-server:system:auth-delegator
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: system:auth-delegator
subjects:
- kind: ServiceAccount
name: metrics-server
namespace: kube-system
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
labels:
k8s-app: metrics-server
name: system:metrics-server
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: system:metrics-server
subjects:
- kind: ServiceAccount
name: metrics-server
namespace: kube-system
---
apiVersion: v1
kind: Service
metadata:
labels:
k8s-app: metrics-server
name: metrics-server
namespace: kube-system
spec:
ports:
- name: https
port: 443
protocol: TCP
targetPort: https
selector:
k8s-app: metrics-server
---
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
k8s-app: metrics-server
name: metrics-server
namespace: kube-system
spec:
selector:
matchLabels:
k8s-app: metrics-server
strategy:
rollingUpdate:
maxUnavailable: 0
template:
metadata:
labels:
k8s-app: metrics-server
spec:
containers:
- args:
- --cert-dir=/tmp
- --secure-port=10250
- --kubelet-preferred-address-types=InternalIP,Hostname,InternalDNS,ExternalDNS,ExternalIP
- --kubelet-use-node-status-port
- --metric-resolution=15s
- --kubelet-insecure-tls
image: registry.cn-hangzhou.aliyuncs.com/google_containers/metrics-server:v0.7.1
imagePullPolicy: IfNotPresent
livenessProbe:
failureThreshold: 3
httpGet:
path: /livez
port: https
scheme: HTTPS
periodSeconds: 10
name: metrics-server
ports:
- containerPort: 10250
name: https
protocol: TCP
readinessProbe:
failureThreshold: 3
httpGet:
path: /readyz
port: https
scheme: HTTPS
initialDelaySeconds: 20
periodSeconds: 10
resources:
requests:
cpu: 100m
memory: 200Mi
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
readOnlyRootFilesystem: true
runAsNonRoot: true
runAsUser: 1000
seccompProfile:
type: RuntimeDefault
volumeMounts:
- mountPath: /tmp
name: tmp-dir
nodeSelector:
kubernetes.io/os: linux
priorityClassName: system-cluster-critical
serviceAccountName: metrics-server
volumes:
- emptyDir: {}
name: tmp-dir
---
apiVersion: apiregistration.k8s.io/v1
kind: APIService
metadata:
labels:
k8s-app: metrics-server
name: v1beta1.metrics.k8s.io
spec:
group: metrics.k8s.io
groupPriorityMinimum: 100
insecureSkipTLSVerify: true
service:
name: metrics-server
namespace: kube-system
version: v1beta1
versionPriority: 100
#创建资源
kubectl apply -f metrics-server-components.yaml
#检查资源
kubectl get po --all-namespaces |grep metrics
#查看容器
kubectl top po -n wssnail-deploy
2.3、创建HPA
2.3.1、命令行创建
#创建hpa, 表示cpu占有内存达到20%,最小副本是2个,最大副本数是5个
kubectl autoscale deploy my-nginx-deploy -n wssnail-deploy --cpu-percent=20 --min=2 --max=5
#删除hpa
kubectl delete hpa my-nginx-deploy -n wssnail-deploy
#查看hpa
kubectl get hpa -n wssnail-deploy
#查询po
kubectl get po -n wssnail-deploy
#监控Po
kubectl top po my-nginx-deploy-7d5966946d-g8clq -n wssnail-deploy
2.3.2、基于autoscaling/V1
apiVersion: autoscaling/v1 #版本
kind: HorizontalPodAutoscaler #类型
metadata: #元数据
name: my-hpa
namespace: wssnail-deploy #要和创建管理的deploy命名空间一致
spec:
minReplicas: 2 # 设定最小pod数量
maxReplicas: 5 # 设定最大pod数量
targetCPUUtilizationPercentage: 20 # cpu使用率 达到20% 开始弹性扩容
scaleTargetRef: #目标作用对象,可以使Deployment、ReplicationController、ReplicaSet
apiVersion: apps/v1 #版本
kind: Deployment # 指定要控制的nginx信息
name: my-nginx-deploy #deploy的名称
#创建资源
kubectl create -f nginx-hpa.yaml
#查看hpa
kubectl get hpa -n wssnail-deploy
#查询pod
kubectl get po -n wssnail-deploy
#监控Po
kubectl top po my-nginx-deploy-7d5966946d-g8clq -n wssnail-deploy
2.3.3、基于autoscaling/v2
apiVersion: autoscaling/v2 #版本
kind: HorizontalPodAutoscaler
metadata:
name: my-hpa
namespace: wssnail-deploy #命名空间
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: my-nginx-deploy #deploy的名称
minReplicas: 2 #最小副本数
maxReplicas: 5 #最大副本数
behavior:
scaleUp: #扩容
stabilizationWindowSeconds: 0 #稳定窗口 当用于扩缩的指标不断波动时,稳定窗口用于限制副本计数的波动
policies:
- type: Percent #每15秒百分百运行副本数,直到达到hpa平衡
value: 100
periodSeconds: 15
- type: Pods #每15秒扩容4个Pod,直到达到hpa平衡
value: 4
periodSeconds: 15
scaleDown: #缩容
stabilizationWindowSeconds: 300 # 稳定窗口时间
policies:
- type: Percent #每分钟限制删除Pod的速率为10%
value: 10
periodSeconds: 60
- type: Pods #每分钟删除的pod 数不超过5个
value: 5
periodSeconds: 60
selectPolicy: Min
metrics:
- type: Resource #资源
resource:
name: cpu
target:
type: Utilization #cpu使用率
averageUtilization: 20 #CPU平均使用率
#创建资源
kubectl create -f nginx-hpa-v2.yaml
#查看hpa
kubectl get hpa -n wssnail-deploy
#查看pod
kubectl get po -n wssnail-deploy
#监控Pod
kubectl top po my-nginx-deploy-7d5966946d-g8clq -n wssnail-deploy
#监控node
kubectl top no
2.3.4、演示扩容缩容
创建一个service对外暴露端口
apiVersion: v1
kind: Service
metadata:
name: hpa-svc
namespace: wssnail-deploy #命名空间
spec:
selector:
app: my-nginx #对应deploy的标签值
ports:
- protocol: TCP
port: 80
targetPort: 80
type: NodePort
#创建资源
kubectl create -f hpa-svc.yaml
#查看svc
kubectl get svc -n wssnail-deploy
使用JMeter进行压测
#打开hpa监控信息
kubectl get hpa -n wssnail-deploy -w
#pod
kubectl get po -n wssnail-deploy -w