此处将为大家介绍关于k8s中controller部署有状态应用StatefulSet的详细内容,并且为您解答有关k8s部署有状态服务的相关问题,此外,我们还将为您介绍关于07-K8S之Stateful
此处将为大家介绍关于k8s中controller部署有状态应用StatefulSet的详细内容,并且为您解答有关k8s部署有状态服务的相关问题,此外,我们还将为您介绍关于07-K8S之Statefulset控制器、k8s 1.25学习4 - 使用Deployment、StatefulSet部署应用、k8s StatefulSet、k8s StatefulSet控制器的有用信息。
本文目录一览:- k8s中controller部署有状态应用StatefulSet(k8s部署有状态服务)
- 07-K8S之Statefulset控制器
- k8s 1.25学习4 - 使用Deployment、StatefulSet部署应用
- k8s StatefulSet
- k8s StatefulSet控制器
k8s中controller部署有状态应用StatefulSet(k8s部署有状态服务)
k8s中controller部署有状态应用StatefulSet
- 无状态和有状态区别
- 部署有状态应用
- 创建了三个有状态应用,查看pod,有三个,每个都是唯一的名称。
- 查看创建的无头的service
- deployment和statefulset区别
- statefulset有唯一标识)
- 部署守护进程DaemonSet
- 实际操作
- 编写yaml文件:
- 删除StatefulSet创建的pod
- 删除svc中的服务
- 创建DaemonSet的pod
- 进入某一个pod里面查看日志
- Controller一次性任务JOB和定时任务CRONJOB
- 一次性任务 Job
- yaml文件
- 创建job任务
- 查看日志
- 删除job的yaml文件
- 定时任务
- 编写yaml文件
- 创建任务
- 查看pod信息
- 查看定时任务
- 查看日志
- 删除job
无状态和有状态区别
(1) 无状态:
- 认为pod都是一样的(副本内容一样)
- 没有顺序要求(先用哪一个pod)
- 不用考虑在哪一个node运行
- 随意进行伸缩和扩展
(2)有状态: - 上面因素都要考虑到
- 让每个pod都是独立的。保持pod的启动顺序和唯一性
-
- 唯一的网络标识符,持久存储
- 有序,比如MysqL主从
部署有状态应用
** 无头service也就是里面 ClusterIP:none
**
无头的service
创建了三个有状态应用,查看pod,有三个,每个都是唯一的名称。
查看创建的无头的service
kubectl get pods,service
kubectl get pods,svc
deployment和statefulset区别
statefulset有唯一标识)
根据主机名+按照一定的规则生成域名
规则:
** 每个pod有唯一的主机名 **
** 唯一域名,格式为主机名称.service名称。名称空间.svc.cluster.local
**
Nginx-statefulset-0.Nginx.default.svc.cluster.local
部署守护进程DaemonSet
它可以确保所有node运行同一个pod
- 在每一个node上运行同一个pod, 新加入的node也同样运行同一个pod
例子:在每个node节点安装数据采集工具(日志收集)
实际操作
编写yaml文件:
apiVersion: apps/v1
kind: DaemonSet
Metadata:
name: ds-test
labels:
app: filebeat
spec:
selector:
matchLabels:
app: filebeat
template:
Metadata:
labels:
app: filebeat
spec:
containers:
- name: logs
image: Nginx
ports:
- containerPort: 80
volumeMounts:
- name: varlog
mountPath: /tmp/log
volumes:
- name: varlog
hostPath:
path: /var/log
删除StatefulSet创建的pod
kubectl delete statefulset --all //删除所有statefulset创建的pod
删除svc中的服务
kubectl delete svc [pod名称] // 删除service中的pod服务
创建DaemonSet的pod
kubectl apply -f ds.yaml // 创建 pod
kubectl get pods //查看pods
可以看到创建完毕
进入某一个pod里面查看日志
kubectl exec -it [pod名称] /bin/bash
kubectl exec -it ds-test-fsl2w bash //进入pod新的终端
Controller一次性任务JOB和定时任务CRONJOB
一次性任务 Job
yaml文件
apiVersion: batch/v1
kind: Job
Metadata:
name: pi
spec:
template:
spec:
containers:
- name: pi
image: perl
command: ["perl", "-Mbignum=bpi","-wle","print bpi(2000)"]
restartPolicy: Never
backoffLimit: 4
创建job任务
如果使用create
创建job,无法进行滚动更新或者回滚,使用apply
就可以
kubectl create -f job.yaml // 如果使用`create`创建job,无法进行滚动更新或者回滚,使用`apply`就可以
kubectl get pods -o wide //查看pod具体信息 ,可知道job在node2节点上
kubectl get jobs //查看任务
docker images // 在node2节点上可以查看到pull下来的perl镜像
创建了任务
而且只完成一次。出现completed
查看job的信息
node2节点的perl镜像被下载完成
查看日志
kubectl logs [pod名称]
计算了pi,执行一次
删除job的yaml文件
再次查看job情况,会发现已经消失。
kubectl get jobs
定时任务
定时写出hello任务
编写yaml文件
[root@k8s-master01 ~]# cat cronjob.yaml
apiVersion: batch/v1beta1
kind: CronJob
Metadata:
name: hello
spec:
schedule: "*/1****"
jobTemplate:
##################CronJob#####################
spec:
template:
spec:
containers:
- name: hello
image: busyBox
args:
- /bin/sh
- -c
- date; echo He11o from the Kubernetes cluster
restartPolicy: OnFailure
创建任务
kubectl apply -f cronjob.yaml
查看pod信息
发现每隔一分钟执行一次hello
查看定时任务
kubectl get coronjobs
查看日志
kubectl logs [job名称]
kubectl logs hello-27242448--1-mm9kj // 查看日志
删除job
kubectl delete cornjob [名称] //删除job
kubectl delete cronjob hello // 删除了定时任务hello
07-K8S之Statefulset控制器
目录- Statefulset
- 1.Statefulset****概念
- 2.学习达到的目标
- 3.部署一个web应用
- 1.通过statefulset部署pod,并且观察pod创建的过程
- 2.顺序创建 Pod
- 3.StatefulSet 中的 Pod
- 4.检查 Pod 的顺序索引
- 5.使用稳定的网络身份标识
- 6.导入稳定的存储
- 4.部署和扩缩容
- 5.Statefulset的资源清单yaml文件书写规范
- 6.Pod 管理策略
- 7.OrderedReady Pod 管理
- 8.Parallel Pod 管理
- 9.更新策略
- 10.关于删除策略
- 11.滚动更新
- 12.分区
- 13.强制回滚
- 14.statefulSet 控制器搭建Redis:
- 15.statefulSet控制器搭建etcd集群:
Statefulset
1.Statefulset****概念
StatefulSet是为了解决有状态服务的问题(对应Deployments和replicasets是为无状态服务)而设计,其应用场景包括
1.稳定的持久化存储,即Pod重新调度后还是能访问到相同的持久化数据,基于PVC来实现
2.稳定的网络标志,即Pod重新调度后其PodName和HostName不变,基于Headless Service(即没有Cluster IP的Service)来实现
3.有序部署,有序扩展,即Pod是有顺序的,在部署或者扩展的时候要依据定义的顺序依次进行(即从0到N-1,在下一个Pod运行之前的所有Pod必须都是Running和Ready状态),基于init containers来实现
4.有序收缩,有序删除(即从N-1到0)
5.有序的滚动更新
从上面的应用场景可以发现,StatefulSet由以下几个部分组成:
1.通过Headless Service生成可解析的DNS记录
2.通过volumeClaimTemplates创建pvc和对应的pv绑定
3.定义StatefulSet来创建pod
和Deployment相同的是,StatefulSet管理了基于相同容器定义的一组 Pod。但和 Deployment不同的是,StatefulSet 为它们的每个 Pod 维护了一个固定的ID。这些 Pod 是基于相同的声明来创建的,但是不能相互替换:无论怎么调度,每个 Pod 都有一个永久不变的ID。StatefulSet和其他控制器使用相同的工作模式。你在StatefulSet对象中定义你期望的状态,然后StatefulSet的控制器就会通过各种更新来达到那种你想要的状态。
StatefulSet中每个Pod的DNS格式为statefulSetName-{0..N-1}.serviceName.namespace.svc.cluster.local,其中
1.serviceName为Headless Service的名字
2.0..N-1为Pod所在的序号,从0开始到N-1
3.statefulSetName为StatefulSet的名字
4.namespace为服务所在的namespace,Headless Servic和StatefulSet必须在相同的namespace
5..svc.cluster.local为Cluster Domain
2.学习达到的目标
1.如何创建StatefulSet?
2.通过StatefulSet怎样管理它的Pod?
3.如何删除 StatefulSet?
4.如何对StatefulSet进行扩容/缩容?
5.如何更新一个 StatefulSet的Pod
3.部署一个web应用
作为开始,使用如下示例创建一个StatefulSet。它和StatefulSets概念中的示例相似。它创建了一个Headless Service的Nginx用来发布 StatefulSet web中的Pod的IP地址。
[root@master01 statefulset-controller]# cat statefulset-pod.yaml
kubectl apply -f statefulset-pod.yaml
apiVersion: v1
kind: Service
Metadata:
name: Nginx
labels:
app: Nginx
spec:
ports:
- port: 80
name: web
clusterIP: ""
selector:
app: Nginx
---
apiVersion: apps/v1
kind: StatefulSet
Metadata:
name: web
spec:
selector:
matchLabels:
app: Nginx
serviceName: "Nginx"
replicas: 2
template:
Metadata:
labels:
app: Nginx
spec:
containers:
- name: Nginx
image: Nginx:1.20
ports:
- containerPort: 80
name: web
volumeMounts:
- name: www
mountPath: /usr/share/Nginx/html
# - name: busyBox
# image: busyBox:latest
# command: ["/bin/sh","-c","sleep 3600"]
volumeClaimTemplates:
- Metadata:
name: www
spec:
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 2Gi
注:为什么要使用volumeClaimTemplate
对于有状态应用都会用到持久化存储,比如MysqL主从,由于主从数据库的数据是不能存放在一个目录下的,每个MysqL节点都需要有自己独立的存储空间。而在deployment中创建的存储卷是一个共享的存储卷,多个pod使用同一个存储卷,它们数据是同步的,而statefulset定义中的每一个pod都不能使用同一个存储卷,这就需要使用volumeClainTemplate,当在使用statefulset创建pod时,会自动生成一个PVC,从而请求绑定一个PV,每一个pod都有自己专用的存储卷。Pod、PVC和PV对应的关系图如下:
1.通过statefulset部署pod,并且观察pod创建的过程
你需要使用两个终端窗口。在第一个终端中,使用kubectl get来查看 StatefulSet的Pods的创建情况。
kubectl get pods -w -l app=Nginx
在另一个终端中,使用 kubectl apply -f statefulset.yaml来创建定义在statefulset.yaml中的 Headless Service 和StatefulSet。
kubectl apply -f statefulset.yaml
上面的命令创建了两个 Pod,每个都运行了一个Nginx web 服务器。获取Nginx Service 和web StatefulSet来验证是否成功的创建了它们。
查看service
kubectl get service Nginx
NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE
Nginx None <none> 80/TCP 12s
查看statefulset
kubectl get statefulset web
显示如下:
NAME READY AGE
web 2/2 20m
2.顺序创建 Pod
对于一个拥有 N 个副本的 StatefulSet,Pod 被部署时是按照 {0..N-1}的序号顺序创建的。在第一个终端中使用 kubectl get 检查输出。这个输出最终将看起来像下面的样子。
kubectl get pods -w -l app=Nginx
NAME READY STATUS RESTARTS AGE
web-0 0/1 Pending 0 0s
web-0 0/1 Pending 0 0s
web-0 0/1 ContainerCreating 0 0s
web-0 1/1 Running 0 19s
web-1 0/1 Pending 0 0s
web-1 0/1 Pending 0 0s
web-1 0/1 ContainerCreating 0 0s
web-1 1/1 Running 0 18s
请注意在web-0 Pod处于Running和Ready 状态后web-1 Pod才会被启动。
3.StatefulSet 中的 Pod
StatefulSet 中的 Pod 拥有一个唯一的顺序索引和稳定的网络身份标识
4.检查 Pod 的顺序索引
获取 StatefulSet 的 Pod。
kubectl get pods -l app=Nginx
NAME READY STATUS RESTARTS AGE
web-0 1/1 Running 0 1m
web-1 1/1 Running 0 1m
如同StatefulSets 概念中所提到的, StatefulSet中的Pod拥有一个具有黏性的、独一无二的身份标志。这个标志基于StatefulSet控制器分配给每个 Pod的唯一顺序索引。 Pod的名称的形式为<statefulset name>-<ordinal index>。web StatefulSet 拥有两个副本,所以它创建了两个 Pod:web-0 和 web-1
5.使用稳定的网络身份标识
每个Pod都拥有一个基于其顺序索引的稳定的主机名(statefulset创建的pod的主机名由statefulset的名称和有序索引组成)。使用kubectl exec 在每个 Pod 中执行hostname
for i in 0 1; do kubectl exec web-$i -- sh -c 'hostname'; done
显示如下:
web-0
web-1
使用kubectl run运行一个提供nslookup命令的容器,该命令来自于dnsutils包。通过对Pod的主机名执行nslookup,你可以检查他们在集群内部的DNS地址。
kubectl run -i --tty --image busyBox:latest dns-test --restart=Never --rm /bin/sh
nslookup web-0.Nginx.default.svc.cluster.local.
kubectl exec -it web-1 -- /bin/bash
apt-get install dnsutils -y
nslookup web-0.Nginx.default.svc.cluster.local
或者在容器外部使用dig解析:
dig -t A web-0.Nginx.default.svc.cluster.local @10.96.0.10
在一个终端中查看 StatefulSet 的 Pod。
kubectl get pod -w -l app=Nginx
在另一个终端中使用 kubectl delete 删除 StatefulSet 中所有的 Pod。
kubectl delete pod -l app=Nginx
pod "web-0" deleted
pod "web-1" deleted
等待 StatefulSet 重启它们,并且两个 Pod 都变成 Running 和 Ready 状态。
kubectl get pod -w -l app=Nginx
NAME READY STATUS RESTARTS AGE
web-0 0/1 ContainerCreating 0 0s
NAME READY STATUS RESTARTS AGE
web-0 1/1 Running 0 2s
web-1 0/1 Pending 0 0s
web-1 0/1 Pending 0 0s
web-1 0/1 ContainerCreating 0 0s
web-1 1/1 Running 0 34s
使用 kubectl exec 和 kubectl run 查看 Pod 的主机名和集群内部的 DNS 表项
for i in 0 1; do kubectl exec web-$i -- sh -c 'hostname'; done
web-0
web-1
web-2
kubectl exec -it web-1 -- /bin/bash
apt-get install dnsutils -y
#安装nslookup命令的的
nslookup web-0.Nginx.default.svc.cluster.local
Pod 的序号、主机名、SRV 条目和记录名称没有改变,但和 Pod 相关联的 IP 地址可能发生了改变。这就是为什么不要在其他应用中使用 StatefulSet 中的 Pod的IP 地址进行连接,这点很重要。如果你需要查找并连接一个 StatefulSet的活动成员,你应该查询Headless Service 的CNAME。CNAME 相关联的 SRV 记录只会包含 StatefulSet 中处于 Running 和 Ready 状态的 Pod。如果你的应用已经实现了用于测试 liveness 和 readiness 的连接逻辑,你可以使用 Pod 的 SRV 记录(web-0.Nginx.default.svc.cluster.local, web-1.Nginx.default.svc.cluster.local)。因为他们是稳定的,并且当你的 Pod 的状态变为 Running 和 Ready 时,你的应用就能够发现它们的地址。
域名对应的表格:
6.导入稳定的存储
获取web-0 和 web-1 的 PersistentVolumeClaims
kubectl get pvc -l app=Nginx
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
www-web-0 Bound v1 1Gi RWO 50m
www-web-1 Bound v4 2Gi RWO,RWX 50m
www-web-2 Bound v5 5Gi RWO,RWX 50m
StatefulSet 控制器创建了三个 PersistentVolumeClaims,绑定到三个PersistentVolumes。
Nginx web 服务器默认会加载位于 /usr/share/Nginx/html/index.html 的 index 文件。StatefulSets spec 中的 volumeMounts 字段保证了 /usr/share/Nginx/html 文件夹由一个 PersistentVolume 支持。
将Pod的主机名写入它们的index.html文件并验证 Nginx web 服务器使用该主机名提供服务。
for i in 0 1; do kubectl exec web-$i -- sh -c 'echo $(hostname) > /usr/share/Nginx/html/index.html'; done
for i in 0 1; do kubectl exec -it web-$i -- curl localhost; done
web-0
web-1
请注意,如果你看见上面的 curl 命令返回了 403 Forbidden 的响应,你需要像这样修复使用 volumeMounts (due to a bug when using hostPath volumes)挂载的目录的权限:
for i in 0 1 2; do kubectl exec web-$i -- chmod 755 /usr/share/Nginx/html; done
在你重新尝试上面的 curl 命令之前。
4.部署和扩缩容
kubectl scale sts web --replicas=4
kubectl patch sts myapp -p ‘{“spec”:{“replicas”:2}}’ # 通过打补丁的方式扩缩容。
1.对于包含N个副本的StatefulSet,当部署Pod时,它们是依次创建的,顺序为 0..N-1。
2.当删除 Pod 时,它们是逆序终止的,顺序为 N-1..0。
3.在将缩放操作应用到Pod之前,它前面的所有Pod 必须是 Running 和 Ready 状态。
4.在 Pod 终止之前,所有的继任者必须完全关闭。
StatefulSet 不应将 pod.Spec.TerminationGracePeriodSeconds 设置为 0。这种做法是不安全的,要强烈阻止。
更多的解释请参考 强制删除 StatefulSet Pod。
在上面的 Nginx 示例被创建后,会按照 web-0、web-1的顺序部署Pod。在 web-0 进入 Running 和 Ready 状态前不会部署 web-1。在 web-1 进入 Running 和 Ready 状态前不会部署 web-2。如果 web-1 已经处于 Running 和 Ready 状态,而 web-2 尚未部署,在此期间发生了 web-0 运行失败,那么 web-2 将不会被部署,要等到 web-0 部署完成并进入 Running 和 Ready 状态后,才会部署 web-2。如果用户想将示例中的 StatefulSet 收缩为 replicas=1
,首先被终止的是 web-2。在 web-2 没有被完全停止和删除前,web-1 不会被终止。当 web-2 已被终止和删除、web-1 尚未被终止,如果在此期间发生 web-0 运行失败,那么就不会终止 web-1,必须等到 web-0 进入 Running 和 Ready 状态后才会终止 web-1。
5.Statefulset的资源清单yaml文件书写规范
1.Pod selector
你必须设置StatefulSet的.spec.selector字段,使之匹配其在.spec.template.Metadata.labels中设置的标签。在Kubernetes 1.8版本之前,被忽略.spec.selector字段会获得默认设置值。在 1.8和以后的版本中,未指定匹配的Pod 选择器将在创建 StatefulSet 期间导致验证错误。
2.Pod Identity(pod标识)
StatefulSet Pod 具有唯一的标识,该标识包括顺序标识、稳定的网络标识和稳定的存储。该标识和Pod是绑定的,不管它被调度在哪个节点上。
3.有序索引
对于具有N个副本的StatefulSet,StatefulSet 中的每个 Pod 将被分配一个整数序号,从 0 到 N-1,该序号在StatefulSet 上是唯一的。
4.稳定的网络ID
1)StatefulSet 中的每个Pod根据StatefulSet的名称和Pod的序号派生出它的主机名。组合主机名的格式为$(StatefulSet 名称)-$(序号)。上例将会创建名称分别为 web-0、web-1的Pod。 StatefulSet 可以使用headless 服务控制它的Pod的网络域。管理域的这个服务的格式为: $(服务名称).$(命名空间).svc.cluster.local,其中cluster.local是集群域。 一旦每个 Pod 创建成功,就会得到一个匹配的 DNS 子域,格式为:$(pod 名称).$(所属服务的 DNS 域名),其中所属服务由 StatefulSet的serviceName域来设定。
2)下面给出一些选择集群域、服务名、StatefulSet 名、及其怎样影响 StatefulSet 的 Pod 上的 DNS 名称的示例:
注意: 集群域会被设置为 cluster.local,除非有其他配置。
5.稳定的存储
1)Kubernetes 为每个 VolumeClaimTemplate 创建一个 PersistentVolume。在上面的 Nginx 示例中,每个 Pod 将会得到基于 StorageClass my-storage-class 提供的 1 Gib 的 PersistentVolume。如果没有声明 StorageClass,就会使用默认的 StorageClass。当一个 Pod 被调度(重新调度)到节点上时,它的 volumeMounts 会挂载与其 PersistentVolumeClaims 相关联的 PersistentVolume。请注意,当 Pod 或者 StatefulSet 被删除时,与 PersistentVolumeClaims 相关联的 PersistentVolume 并不会被删除。要删除它必须通过手动方式来完成。
2)Pod 名称标签
3)当StatefulSet控制器创建 Pod 时,它会添加一个标签statefulset.kubernetes.io/pod-name,该标签设置为Pod名称。这个标签允许您给 StatefulSet 中的特定 Pod 绑定一个 Service。
6.Pod 管理策略
在 Kubernetes 1.7 及以后的版本中,StatefulSet 允许你不要求其排序保证,同时通过它的 .spec.podManagementPolicy 域保持其唯一性和身份保证。 在 Kubernetes 1.7 及以后的版本中,StatefulSet 允许您放宽其排序保证,同时通过它的 .spec.podManagementPolicy 域保持其唯一性和身份保证。
7.OrderedReady Pod 管理
OrderedReady Pod 管理是 StatefulSet 的默认设置。它实现了上面描述的功能。
8.Parallel Pod 管理
Parallel Pod 管理让 StatefulSet 控制器并行的启动或终止所有的 Pod,启动或者终止其他 Pod 前,无需等待 Pod 进入 Running 和 ready 或者完全停止状态。
9.更新策略
在Kubernetes 1.7及以后的版本中,StatefulSet 的.spec.updateStrategy 字段让你可以配置和禁用掉自动滚动更新Pod的容器、标签、资源请求或限制、以及注解。
10.关于删除策略
OnDelete 更新策略实现了 1.6 及以前版本的历史遗留行为。当 StatefulSet 的 .spec.updateStrategy.type 设置为 OnDelete 时,它的控制器将不会自动更新 StatefulSet 中的 Pod。用户必须手动删除Pod以便让控制器创建新的 Pod,以此来对StatefulSet的 .spec.template 的变动作出反应。
11.滚动更新
RollingUpdate 更新策略对 StatefulSet 中的 Pod 执行自动的滚动更新。在没有声明 .spec.updateStrategy 时,RollingUpdate 是默认配置。 当 StatefulSet 的 .spec.updateStrategy.type 被设置为 RollingUpdate 时,StatefulSet 控制器会删除和重建 StatefulSet 中的每个 Pod。 它将按照与 Pod 终止相同的顺序(从最大序号到最小序号)进行,每次更新一个 Pod。它会等到被更新的 Pod 进入 Running 和 Ready 状态,然后再更新其前身。
12.分区
# 打补丁方式修改pod partition序号大于或等于3的进行升级
kubectl patch sts web -p '{"spec":{"updateStrategy":{"rollingUpdate":{"partition":3}}}}'
Kubectl describe sts web # 查看partition字段
kubectl patch sts web -p ‘{“spec”:{“template”:{“spec”:{“containers[0]”:{“image”:”Nginx:1.21”}}}}}’
containers[0]:一个pod中可能有多个容器,containers是一个容器列表,所以我们要指定修改哪一个容器的镜像版本。
或者:
kubectl set image sts/web Nginx=Nginx:1.21
kubectl get sts -o wide # 查看sts镜像版本是否被修改成功
# 查看web-3的pod的镜像是否改变
kubectl describe pod web-3
# 而web-0,1,2的镜像还是Nginx:1.20
kubectl describe pod web-2
@H_5_301@
这就实现了金丝雀发布,如果发现pod web-3在使用新镜像没有问题,将pod web-0,1,2的镜像全部升级到Nginx:1.21
kubectl patch sts web -p '{"spec":{"updateStrategy":{"rollingUpdate":{"partition":0}}}}'
通过声明 .spec.updateStrategy.rollingUpdate.partition 的方式,RollingUpdate 更新策略可以实现分区。如果声明了一个分区,当 StatefulSet 的 .spec.template 被更新时,所有序号大于等于该分区序号的 Pod 都会被更新。所有序号小于该分区序号的 Pod 都不会被更新,并且,即使他们被删除也会依据之前的版本进行重建。如果StatefulSet的 .spec.updateStrategy.rollingUpdate.partition 大于它的 .spec.replicas,对它的 .spec.template 的更新将不会传递到它的 Pod。 在大多数情况下,您不需要使用分区,但如果您希望进行阶段更新、执行金丝雀或执行分阶段展开,则这些分区会非常有用。
13.强制回滚
在默认 Pod 管理策略(OrderedReady) 时使用 滚动更新 ,可能进入需要人工干预才能修复的损坏状态。
如果更新后 Pod 模板配置进入无法运行或就绪的状态(例如,由于错误的二进制文件或应用程序级配置错误),StatefulSet 将停止回滚并等待。
在这种状态下,仅将 Pod 模板还原为正确的配置是不够的。由于已知问题,StatefulSet 将继续等待损坏状态的 Pod 准备就绪(永远不会发生),然后再尝试将其恢复为正常工作配置。
恢复模板后,还必须删除 StatefulSet 尝试使用错误的配置来运行的 Pod。这样,StatefulSet 才会开始使用被还原的模板来重新创建 Pod。
以上还是用无状态应用模拟的sts pod,而在实际使用statefulSet管理有状态应用并没这么简单,比如管理redis集群,etcd集群:
14.statefulSet 控制器搭建Redis:
参考博客:https://www.cnblogs.com/kuku0223/p/10906003.html
15.statefulSet控制器搭建etcd集群:
Cat etcd-statefulSet.yaml
apiVersion: apps/v1
kind: StatefulSet
Metadata:
name: etcd
labels:
app: etcd
spec:
serviceName: etcd
# changing replicas value will require a manual etcdctl member remove/add
# command (remove before decreasing and add after increasing)
replicas: 3
selector:
matchLabels:
app: etcd-member
template:
Metadata:
name: etcd
labels:
app: etcd-member
spec:
containers:
- name: etcd
image: elcolio/etcd
ports:
- containerPort: 2379
name: client
- containerPort: 2380
name: peer
env:
- name: CLUSTER_SIZE
value: "3"
- name: SET_NAME
value: "etcd"
volumeMounts:
- name: data
mountPath: /var/run/etcd
command:
- "/bin/sh"
- "-ecx"
- |
IP=$(hostname -i)
PEERS=""
for i in $(seq 0 $((${CLUSTER_SIZE} - 1))); do
PEERS="${PEERS}${PEERS:+,}${SET_NAME}-${i}=http://${SET_NAME}:2380"
done
# start etcd. If cluster is already initialized the `--initial-*` options will be ignored.
exec etcd --name $(HOSTNAME) \
--listen-peer-urls http://${IP}:2380 \
--listen-client-urls http://$(IP):2379,http://127.0.0.1:2379 \
--advertise-client-urls http://${HOSTNAME}.${SET_NAME}:2379 \
--initial-advertise-peer-urls http://${HOSTNAME}.${SET_NAME}:2380 \
--initial-cluster-token etcd-cluster-1 \
--initial-cluster ${PEERS} \
--initial-cluster-state new \
--data-dir /var/run/etcd/default.etcd
volumeClaimTemplates:
- Metadata:
name: data
spec:
storageClassName: gluster-dynamic
accessModes:
- "ReadWriteOnce"
resources:
requests:
storage: 1Gi
k8s 1.25学习4 - 使用Deployment、StatefulSet部署应用
k8s集群中apiserver是无状态的,可以有多台同时工作
Controller-Manager、scheduler是有状态的,会选举出一个master节点工作
#查看主节点
kubectl get leases -n kube-system
CoreDNS:Service路由解析
#显示和操作IP路由表
route -n
kubectl run mynginx --image=nginx
kubectl exec -it mynginx -- sh
#nameserver指向dns的IP
cat /etc/resolv.conf
exit
kubectl get svc -A | grep dns
kubectl delete pod mynginx
Pod常用命令
每个Pod包含一个Pause容器
Pause容器是Pod的父容器,负责僵尸进程的回收管理,通过Pause容器使同一个Pod里的容器共享存储、网络、PID、IPC等
#查看k8s.io命名空间内的静态容器
ctr -n k8s.io container ls
ctr -n k8s.io task ls
https://kubernetes.io/zh-cn/docs/concepts/workloads/pods/
Pod官方文档
使用文件创建Pod
#输出Pod的yaml文件,不会自动创建Pod
kubectl run nginx --image=nginx:1.15.12 -oyaml --dry-run=client > pod.yaml
apiVersion: v1
kind: Pod
metadata:
labels:
run: nginx
name: nginx
spec:
containers:
- image: nginx:1.15.12
name: nginx
kubectl apply -f pod.yaml
查看yaml文件格式中的版本号
kubectl api-resources | grep pod
kubectl api-resources | grep deployment
覆盖镜像中entrypoint命令
apiVersion: v1
kind: Pod
metadata:
labels:
run: nginx
name: nginx
spec:
containers:
- image: nginx:1.15.12
name: nginx
command: ["sleep", "10"] #entrypoint
#查看帮忙文档
kubectl explain Pod.spec.containers
#command覆盖镜像中entrypoint
#args覆盖镜像中CMD中的参数
Pod镜像拉取策略
imagePullPolicy: IfNotPresent # 可选,镜像拉取策略,IfNotPresent、Never、IfNotPresent
Pod重启策略
#默认Always #OnFailure:容器执行entrypoint命令后,以不为0的状态码终止,则自动重启该容器
restartPolicy: Always #Always、OnFailure、Never
Pod的三种探针
startupProbe:判断容器内的应用程序是否已经启动
livenessProbe:探测容器是否在运行;如果不满足健康条件,根据Pod中设置的restartPolicy(重启策略)来判断,Pod是否要进行重启操作
readinessProbe:探测容器内的程序是否健康,即判断容器是否为就绪(Ready)状态;不可用将从Service的Endpoints中移除
kubectl get svc -n kube-system
kubectl describe svc metrics-server -n kube-system
kubectl get pods -n kube-system -owide | grep metrics
kubectl get endpoints metrics-server -n kube-system
程序如果启动比较慢,需要使用startupProbe探针
只有等startupProbe检测通过了之后,才会开始检测livenessProbe、readinessProbe
应用启动时间大于30秒,就需要配置startupProbe,这样livenessProbe、readinessProbe的间隔检查时间就可以配置小一些了
vi nginx-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
containers:
- name: nginx
image: nginx:1.15.12
imagePullPolicy: IfNotPresent
command:
- sh
- -c
- sleep 30; nginx -g "daemon off;"
startupProbe:
tcpSocket:
port: 80
initialDelaySeconds: 10 # 初始化时间
timeoutSeconds: 2 # 超时时间
periodSeconds: 5 # 检测间隔
successThreshold: 1 # 检查成功为2次表示就绪
failureThreshold: 5 # 检测失败1次表示未就绪
readinessProbe:
httpGet:
path: /index.html
port: 80
scheme: HTTP
initialDelaySeconds: 10 # 初始化时间, 健康检查延迟执行时间
timeoutSeconds: 2 # 超时时间
periodSeconds: 5 # 检测间隔
successThreshold: 1 # 检查成功为2次表示就绪
failureThreshold: 2 # 检测失败1次表示未就绪
livenessProbe: # 可选,健康检查
exec: # 端口检测方式
command:
- sh
- -c
- pgrep nginx
initialDelaySeconds: 10 # 初始化时间
timeoutSeconds: 2 # 超时时间
periodSeconds: 5 # 检测间隔
successThreshold: 1 # 检查成功为 2 次表示就绪
failureThreshold: 2 # 检测失败 1 次表示未就绪
ports:
- containerPort: 80
restartPolicy: Never
kubectl apply -f nginx-pod.xml
kubectl delete -f nginx-pod.xml
preStop容器停止前执行指令
vi pod-preStop.yaml
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
containers:
- name: nginx
image: nginx:1.15.12
imagePullPolicy: IfNotPresent
lifecycle:
preStop:
exec:
command:
- sh
- -c
- sleep 10
ports:
- containerPort: 80
restartPolicy: Never
kubectl apply -f pod-preStop.yaml
kubectl delete -f pod-preStop.yaml
无状态应用管理Deployment
Replication Controller可确保Pod副本数达到期望值,即确保一个Pod或一组同类Pod总是可用
ReplicaSet是支持基于集合的标签选择器的下一代Replication Controller
它主要用作Deployment协调创建、删除和更新Pod,和Replication Controller唯一的区别是,ReplicaSet支持标签选择器
#生成deployment模板
kubectl create deploy nginx --image=nginx:1.15.12-alpine --replicas=3 -oyaml --dry-run=client > nginx-deploy.yaml
kubectl apply -f nginx-deploy.yaml
kubectl get deploy
kubectl get rs
kubectl get pod
kubectl delete pod nginx-b7599c689-qchww
kubectl get pod
查看整个Deployment创建的状态
kubectl rollout status deployment/nginx
kubectl get deploy
kubectl get rs -l app=nginx
kubectl get pods --show-label
更新Deployment
kubectl set image deployment nginx nginx=nginx:1.13 --record
kubectl rollout status deployment/nginx
kubectl describe deploy nginx
回滚Deployment
#查看历史版本
kubectl rollout history deployment nginx
#查看某一个版本的信息
kubectl rollout history deployment nginx --revision=3
#回滚到上一个版本
kubectl rollout undo deployment nginx
#回滚到指定版本
kubectl rollout undo deployment nginx --to-revision=3
扩容
kubectl scala deployment nginx --replicas=5
暂停和恢复Deployment更新
kubectl rollout pause deployment nginx
#更新配置信息,但不重启pod
kubectl set image deployment nginx nginx=1.15.12-alpine --record
kubectl set resources deployment nginx -c=nginx --limits=cpu=200m,memory=512Mi
#恢复pod,自动更新
kubectl rollout resume deployment nginx
kubectl get rs
Deployment更新策略
.spec.strategy.type==RollingUpdate,默认滚动更新
.spec.strategy.rollingUpdate.maxUnavailable,指定在回滚更新时最大不可用的Pod数量,默认为25%
.spec.strategy.rollingUpdate.maxSurge可以超过期望值的最大Pod数,默认为25%(一次启动多个副本,最大限制数量)
StatefulSet部署有状态应用
#StatefulSet服务域名格式:StatefulSetName-0.ServiceName.Namepace.svc.cluster.local
web-0.nginx.default.svc.cluster.local
StatefulSet需要创建一个Service对外提供服务
vi statefulset.yaml
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:
selector:
matchLabels:
app: nginx # has to match .spec.template.metadata.labels
serviceName: "nginx"
replicas: 3 # by default is 1
minReadySeconds: 10 # by default is 0
template:
metadata:
labels:
app: nginx # has to match .spec.selector.matchLabels
spec:
terminationGracePeriodSeconds: 10
containers:
- name: nginx
image: nginx:1.15.12-alpine
ports:
- containerPort: 80
name: web
创建
kubectl apply -f statefulset.yaml
kubectl rollout status sts web
kubectl get pods
kubectl get sts
Pod创建时按顺序一个一个单独创建,缩容时按倒序一个一个接着关闭
kubectl exec -it web-2 --sh
curl web-0.nginx.default.svc.cluster.local
nslookup web-0.nginx.default.svc.cluster.local
扩容
kubectl scale sts web --replicas=5
kubectl get pods
StatefulSet更新策略
RollingUpdate默认滚动更新
分段更新partition
updateStrategy:
rollingUpdate:
partition: 0
type: RollingUpdate
partition默认值为0,表示更新后缀大于等于0的Pod;如果配置为3,则表示只更新后缀大于等于3的Pod,而小于3的Pod不会更新;可以用于灰度测试
删除sts
kubectl delete sts web
kubectl get sts
kubectl get pod
#删除default命名空间中的所有pod
kubectl delete pod --all
守护进程集DaemonSet
每个节点上可以有一个守护进程集
kubectl get ds -n kube-system
#DaemonSet的yaml与Deployment类似,只是少了副本这一个参数
#删除replicas: 3,修改kind: DaemonSet
cp nginx-deploy.yaml nginx-ds.yaml
kubectl apply -f nginx-ds.yaml
kubectl get ds
kubectl get pods
查看node节点上的label
kubectl get node --show-labels
#node节点上增加label
kubectl label node k8s-node2 k8s-node3 disktype=ssd
kubectl get node --show-labels
指定节点部署Pod:.spec.template.spec.nodeSelector
#节点选择器
nodeSelector:
disktype: ssd
kubectl apply -f nginx-ds.yaml
kubectl get pods -owide
kubectl get ds -oyaml
kubectl get ds
kubectl rollout status ds/nginx
kubectl rollout history daemonset nginx
kubectl rollout undo daemonset nginx
kubectl get controllerrevision
kubectl delete -f nginx-ds.yaml
HPA自动扩缩容
kubectl get apiservices | grep autoscaling
kbuectl create deployment hpa-nginx --image=nginx:1.15.12-alpine --dry-run=client -oyaml > hpa-nginx.yaml
1颗CPU是1000m
创建一个deploy,限制CPU资源为10m
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: hpa-nginx
name: hpa-nginx
spec:
replicas: 1
selector:
matchLabels:
app: hpa-nginx
template:
metadata:
labels:
app: hpa-nginx
spec:
containers:
- image: nginx:1.15.12-alpine
name: nginx
resources:
requests:
cpu: 10m
创建
kubectl apply -f hpa-nginx.yaml
kubectl get deploy
#创建Service
kubectl expose deploy hpa-nginx --port=80
kubectl get svc
curl http://10.96.226.0
kubectl top pods
创建hpa
#CPU使用率超过10%时开始扩容
kubectl autoscale deploy hpa-nginx --cpu-percent=10 --min=1 --max=10
kubectl get hpa
kubectl get hpa -oyaml
压测
kubectl get svc
#增大访问压力
while true; do wget -q -O - http://10.96.226.0 > /dev/null; done
kubectl top pods
kubectl logs -f hpa-nginx-54c8954b44-j5spv
kubectl top pods
kubectl get hpa
kubectl delete -f hpa-nginx.yaml
Label标签选择器
Label可以对k8s的一些对象进行分组,用于区分同样的资源不同的分组
Selector可以根据资源的标签查询出精确的对象信息
一般不修改Pod的标签,常修改Node的标签
kubectl get pods --show-labels
kubectl get pods -l app=nginx
kubectl get nodes --show-labels
kubectl get nodes -l disktype=ssd
kubectl get svc -n kube-system --show-labels
给节点打标签
kubectl label node k8s-node2 region=sz
kubectl get node -l region=sz
#yaml使用nodeSelector选择部署在指定的节点上
spec:
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
nodeSelector:
region: sz
获取label中disktype为nginx或者ssd的数据
kubectl get nodes -l ''disktype in (nginx, ssd)'' --show-labels
#匹配多个条件
kubectl get nodes -l ''region!=sz, disktype in (nginx, ssd)'' --show-labels
#匹配是否存在标签
kubectl get nodes -l region
修改标签
kubectl label node k8s-node2 region=sh --overwrite
#批量修改标签
kubectl label node -l region region=wh --overwrite
删除标签
kubectl label node k8s-node2 region-
k8s StatefulSet
StatefulSet
StatefulSet 是为了解决有状态服务的问题(对应 Deployments 和 ReplicaSets 是为无状态服务而设计),其应用场景包括
- 稳定的持久化存储,即 Pod 重新调度后还是能访问到相同的持久化数据,基于 PVC 来实现
- 稳定的网络标志,即 Pod 重新调度后其 PodName 和 HostName 不变,基于 Headless Service(即没有 Cluster IP 的 Service)来实现
- 有序部署,有序扩展,即 Pod 是有顺序的,在部署或者扩展的时候要依据定义的顺序依次依次进行(即从 0 到 N-1,在下一个 Pod 运行之前所有之前的 Pod 必须都是 Running 和 Ready 状态),基于 init containers 来实现
- 有序收缩,有序删除(即从 N-1 到 0)
从上面的应用场景可以发现,StatefulSet 由以下几个部分组成:
- 用于定义网络标志(DNS domain)的 Headless Service
- 用于创建 PersistentVolumes 的 volumeClaimTemplates
- 定义具体应用的 StatefulSet
StatefulSet 中每个 Pod 的 DNS 格式为 statefulSetName-{0..N-1}.serviceName.namespace.svc.cluster.local
,其中
serviceName
为 Headless Service 的名字0..N-1
为 Pod 所在的序号,从 0 开始到 N-1statefulSetName
为 StatefulSet 的名字namespace
为服务所在的 namespace,Headless Servic 和 StatefulSet 必须在相同的 namespace.cluster.local
为 Cluster Domain,
简单示例
以一个简单的 nginx 服务 web.yaml 为例:
--- apiVersion: v1 kind: Service metadata: name: nginx labels: app: nginx spec: ports: - port: 80 name: web clusterIP: None selector: app: nginx --- apiVersion: apps/v1beta1 kind: StatefulSet metadata: name: web spec: serviceName: "nginx" replicas: 2 template: metadata: labels: app: nginx spec: containers: - name: nginx image: gcr.io/google_containers/nginx-slim:0.8 ports: - containerPort: 80 name: web volumeMounts: - name: www mountPath: /usr/share/nginx/html volumeClaimTemplates: - metadata: name: www annotations: volume.alpha.kubernetes.io/storage-class: anything spec: accessModes: [ "ReadWriteOnce" ] resources: requests: storage: 1Gi
$ kubectl create -f web.yaml service "nginx" created statefulset "web" created # 查看创建的headless service和statefulset $ kubectl get service nginx NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE nginx None <none> 80/TCP 1m $ kubectl get statefulset web NAME DESIRED CURRENT AGE web 2 2 2m # 根据volumeClaimTemplates自动创建PVC(在GCE中会自动创建kubernetes.io/gce-pd类型的volume) $ kubectl get pvc NAME STATUS VOLUME CAPACITY ACCESSMODES AGE www-web-0 Bound pvc-d064a004-d8d4-11e6-b521-42010a800002 1Gi RWO 16s www-web-1 Bound pvc-d06a3946-d8d4-11e6-b521-42010a800002 1Gi RWO 16s # 查看创建的Pod,他们都是有序的 $ kubectl get pods -l app=nginx NAME READY STATUS RESTARTS AGE web-0 1/1 Running 0 5m web-1 1/1 Running 0 4m # 使用nslookup查看这些Pod的DNS $ kubectl run -i --tty --image busybox dns-test --restart=Never --rm /bin/sh / # nslookup web-0.nginx Server: 10.0.0.10 Address 1: 10.0.0.10 kube-dns.kube-system.svc.cluster.local Name: web-0.nginx Address 1: 10.244.2.10 / # nslookup web-1.nginx Server: 10.0.0.10 Address 1: 10.0.0.10 kube-dns.kube-system.svc.cluster.local Name: web-1.nginx Address 1: 10.244.3.12 / # nslookup web-0.nginx.default.svc.cluster.local Server: 10.0.0.10 Address 1: 10.0.0.10 kube-dns.kube-system.svc.cluster.local Name: web-0.nginx.default.svc.cluster.local Address 1: 10.244.2.10
还可以进行其他的操作
# 扩容 $ kubectl scale statefulset web --replicas=5 # 缩容 $ kubectl patch statefulset web -p ''{"spec":{"replicas":3}}'' # 镜像更新(目前还不支持直接更新image,需要patch来间接实现) $ kubectl patch statefulset web --type=''json'' -p=''[{"op": "replace", "path": "/spec/template/spec/containers/0/image", "value":"gcr.io/google_containers/nginx-slim:0.7"}]'' # 删除StatefulSet和Headless Service $ kubectl delete statefulset web $ kubectl delete service nginx # StatefulSet删除后PVC还会保留着,数据不再使用的话也需要删除 $ kubectl delete pvc www-web-0 www-web-1
zookeeper
另外一个更能说明 StatefulSet 强大功能的示例为 zookeeper.yaml。
--- apiVersion: v1 kind: Service metadata: name: zk-headless labels: app: zk-headless spec: ports: - port: 2888 name: server - port: 3888 name: leader-election clusterIP: None selector: app: zk --- apiVersion: v1 kind: ConfigMap metadata: name: zk-config data: ensemble: "zk-0;zk-1;zk-2" jvm.heap: "2G" tick: "2000" init: "10" sync: "5" client.cnxns: "60" snap.retain: "3" purge.interval: "1" --- apiVersion: policy/v1beta1 kind: PodDisruptionBudget metadata: name: zk-budget spec: selector: matchLabels: app: zk minAvailable: 2 --- apiVersion: apps/v1beta1 kind: StatefulSet metadata: name: zk spec: serviceName: zk-headless replicas: 3 template: metadata: labels: app: zk annotations: pod.alpha.kubernetes.io/initialized: "true" scheduler.alpha.kubernetes.io/affinity: > { "podAntiAffinity": { "requiredDuringSchedulingRequiredDuringExecution": [{ "labelSelector": { "matchExpressions": [{ "key": "app", "operator": "In", "values": ["zk-headless"] }] }, "topologyKey": "kubernetes.io/hostname" }] } } spec: containers: - name: k8szk imagePullPolicy: Always image: gcr.io/google_samples/k8szk:v1 resources: requests: memory: "4Gi" cpu: "1" ports: - containerPort: 2181 name: client - containerPort: 2888 name: server - containerPort: 3888 name: leader-election env: - name : ZK_ENSEMBLE valueFrom: configMapKeyRef: name: zk-config key: ensemble - name : ZK_HEAP_SIZE valueFrom: configMapKeyRef: name: zk-config key: jvm.heap - name : ZK_TICK_TIME valueFrom: configMapKeyRef: name: zk-config key: tick - name : ZK_INIT_LIMIT valueFrom: configMapKeyRef: name: zk-config key: init - name : ZK_SYNC_LIMIT valueFrom: configMapKeyRef: name: zk-config key: tick - name : ZK_MAX_CLIENT_CNXNS valueFrom: configMapKeyRef: name: zk-config key: client.cnxns - name: ZK_SNAP_RETAIN_COUNT valueFrom: configMapKeyRef: name: zk-config key: snap.retain - name: ZK_PURGE_INTERVAL valueFrom: configMapKeyRef: name: zk-config key: purge.interval - name: ZK_CLIENT_PORT value: "2181" - name: ZK_SERVER_PORT value: "2888" - name: ZK_ELECTION_PORT value: "3888" command: - sh - -c - zkGenConfig.sh && zkServer.sh start-foreground readinessProbe: exec: command: - "zkOk.sh" initialDelaySeconds: 15 timeoutSeconds: 5 livenessProbe: exec: command: - "zkOk.sh" initialDelaySeconds: 15 timeoutSeconds: 5 volumeMounts: - name: datadir mountPath: /var/lib/zookeeper securityContext: runAsUser: 1000 fsGroup: 1000 volumeClaimTemplates: - metadata: name: datadir annotations: volume.alpha.kubernetes.io/storage-class: anything spec: accessModes: [ "ReadWriteOnce" ] resources: requests: storage: 20Gi
kubectl create -f zookeeper.yaml
详细的使用说明见 zookeeper stateful application。
StatefulSet 注意事项
- 还在 beta 状态,需要 kubernetes v1.5 版本以上才支持
- 所有 Pod 的 Volume 必须使用 PersistentVolume 或者是管理员事先创建好
- 为了保证数据安全,删除 StatefulSet 时不会删除 Volume
- StatefulSet 需要一个 Headless Service 来定义 DNS domain,需要在 StatefulSet 之前创建好
- 目前 StatefulSet 还没有 feature complete,比如更新操作还需要手动 patch。
更多可以参考 Kubernetes 文档。
原文:https://github.com/rootsongjc/kubernetes-handbook/blob/master/architecture/statefulset.md
k8s StatefulSet控制器
StatefulSet控制器
@H_301_8@无状态应用与有状态应用StatefulSet 是用来管理有状态应用的控制器。
参考: https://kubernetes.io/zh/docs/concepts/workloads/controllers/statefulset/
无状态应用: 如Nginx
- 请求本身包含了响应端为响应这一请求所需的全部信息。每一个请求都像首次执行一样,不会依赖之前的数据进行响应。
- 不需要持久化的数据
- 无状态应用的多个实例之间互不依赖,可以无序的部署、删除或伸缩
有状态应用: 如MysqL
@H_301_8@StatefulSet的特点
- 前后请求有关联与依赖
- 需要持久化的数据
- 有状态应用的多个实例之间有依赖,不能相互替换:无论怎么调度,每个 Pod 都有一个永久不变的 ID。
@H_301_8@StatefulSet的YAML组成
- 稳定的、唯一的网络标识符。 (通过headless服务实现)
- 稳定的、持久的存储。 (通过PV,PVC,storageclass实现)
- 有序的、优雅的部署和缩放。
- 有序的、自动的滚动更新。
需要三个组成部分:
- headless service: 实现稳定,唯一的网络标识
- statefulset类型资源: 写法和deployment几乎一致,就是类型不一样
- volumeClaimTemplate : 指定存储卷
Nginx+statefulset+nfs案例
@H_301_8@一、创建StatefulSet应用参考: https://kubernetes.io/zh/docs/tutorials/stateful-application/basic-stateful-set/
温馨提示:做此实验前要先创建好pv,pvc等,可参考博客 https://blog.51cto.com/u_13760351/2639942
1.创建statelfulset应用
(来调用名为managed-nfs-storage的storageclass,以实现动态供给)
vim Nginx-storageclass-nfs.yml
apiVersion: v1
kind: Service
Metadata:
name: 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
volumeMounts:
- name: www
mountPath: /usr/share/Nginx/html
volumeClaimTemplates:
- Metadata:
name: www
spec:
accessModes: [ "ReadWriteOnce" ]
storageClassName: "managed-nfs-storage" # 与前面定义的storageclass名称对应
resources:
requests:
storage: 1Gi
kubectl apply -f Nginx-storageclass-nfs.yml
kubectl get statefulsets # 可以简写成sts
kubectl get pods |grep web
自动产生了3个pv
kubectl get pv
自动产生了3个PVC
kubectl get pvc |grep web
在nfs服务器(这里为hostos)的共享目录中发现自动产生了3个子目录
[root@hostos ~]# ls /data/
3个子目录默认都为空目录
[root@hostos ~]# tree /data/
1.在3个pod中其中一个创建一个主页文件
kubectl exec -it web-0 -- /bin/sh
/ # echo "haha" > /usr/share/Nginx/html/index.html
/ # exit
在nfs服务器上发现文件被创建到了对应的目录中
[root@hostos ~]# tree /data/
[root@hostos ~]# cat /data/default-www-web-0-pvc-2436b20d-1be3-4c2e-87a9-5533e5c5e2c6/index.html
2.删除web-0这个pod,再验证
kubectl delete pod web-0
kubectl get pods |grep web #因为控制器的原因,再拉起web-0这个pod
kubectl exec -it web-0 -- cat /usr/share/Nginx/html/index.html
新拉起的pod仍然是相同的存储数据
[root@hostos ~]# cat /data/nfs/default-www-web-0-pvc-2436b20d-1be3-4c2e-87a9-5533e5c5e2c6/index.html
nfs服务器上的数据还在
3.结论: 说明数据可持久化
@H_301_8@五、验证pod唯一名称回顾域名格式:
service: <service name>.<namespace name>.svc.cluster.local.
pod: <PodName>.<service name>.<namespace name>.svc.cluster.local.
可以看到在 web-0这个pod中,nslookup查询service的域名,直接解析成了3个pod的域名
kubectl exec -it web-0 -- /bin/sh
/ # nslookup Nginx.default.svc.cluster.local.
ping这三个pod的域名都可以ping通
/ # ping web-0.Nginx.default.svc.cluster.local.
/ # ping web-1.Nginx.default.svc.cluster.local
/ # ping ping web-2.Nginx.default.svc.cluster.local
补充: 当pod被删除后,重新拉起来,pod-IP可能会变,但上面的pod域名仍然可以ping通
1.扩容
kubectl scale sts web --replicas=4
kubectl get pods
有序地扩展了一个pod,名称为web-3
2.裁剪
kubectl scale sts web --replicas=1
kubectl get pods |grep web
先裁剪web-3,再裁剪web-2,最后裁剪web-1,只留下web-0
MysqL-statefulset-nfs案例
@H_301_8@一、编写statefulsetvim statefulset-MysqL-nfs.yaml
apiVersion: v1
kind: Service
Metadata:
name: MysqL-svc
spec:
clusterIP: None # 无头服务
ports:
- port: 3306
protocol: TCP
targetPort: 3306
selector:
app: MysqL
---
apiVersion: apps/v1
kind: StatefulSet
Metadata:
name: MysqL
spec:
serviceName: MysqL-svc # 与上面服务名一致
replicas: 1 # 副本数为1就OK,这里不做MysqL集群
selector:
matchLabels:
app: MysqL
template:
Metadata:
labels:
app: MysqL
spec:
containers:
- name: c1
image: MysqL:5.7
env:
- name: MysqL_ROOT_PASSWORD # MysqL5.7的镜像必须要设置一下MysqL的root密码
value: "123456"
- name: MysqL_DATABASE # 给它建一个库名为daniel,用于验证
value: daniel
volumeMounts:
- name: MysqL-data
mountPath: /var/lib/MysqL
volumeClaimTemplates:
- Metadata:
name: MysqL-data
spec:
accessModes: [ "ReadWriteOnce" ]
storageClassName: "managed-nfs-storage"
resources:
requests:
storage: 3Gi
@H_301_8@二、应用YAML
@H_301_8@三、验证资源kubectl apply -f statefulset-MysqL-nfs.yaml
kubectl get pods |grep MysqL
kubectl get sts |grep MysqL
kubectl get pv |grep MysqL
kubectl get pvc |grep MysqL
1.进入容器
kubectl exec -it MysqL-0 -- /bin/bash
root@MysqL-0:/# MysqL -p123456
MysqL> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| daniel | # 这里daneil库就是帮我们创建的
| MysqL |
| performance_schema |
| sys |
+--------------------+
5 rows in set (0.01 sec)
MysqL> exit
2.验证nfs上的数据
[root@hostos ~]# ls /data/default-MysqL-data-MysqL-0-pvc-f936d526-f473-4b88-a0e6-b94a19b95fe6
删除MysqL-0这个pod,会帮我们再次启动,并且数据还是用原来的数据
今天的关于k8s中controller部署有状态应用StatefulSet和k8s部署有状态服务的分享已经结束,谢谢您的关注,如果想了解更多关于07-K8S之Statefulset控制器、k8s 1.25学习4 - 使用Deployment、StatefulSet部署应用、k8s StatefulSet、k8s StatefulSet控制器的相关知识,请在本站进行查询。
本文标签: