ITPub博客

首页 > 数据库 > 数据库开发技术 > kubernetes Statefulset控制器

kubernetes Statefulset控制器

原创 数据库开发技术 作者:DevOps和k8s全栈技术 时间:2020-04-03 14:40:45 0 删除 编辑

温馨提示:文章是基于原理+实践而成,可关注或者收藏,日后或许会用到~~


什么是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)

StatefulSet由哪几部分组成?

从上面的应用场景可以发现,StatefulSet由以下几个部分组成

1.通过Headless Service生成可解析的DNS记录2.通过volumeClaimTemplates创建pvc和对应的pv绑定3.定义StatefulSet来创建pod

StatefulSet的yaml文件组成?

StatefulSet中每个Pod的DNS格式为statefulSetName-{0..N-1}.serviceName.namespace.svc.cluster.local,其中

1.serviceName为Headless Service的名字2.0..N-1为Pod所在的序号,从0开始到N-13.statefulSetName为StatefulSet的名字4.namespace为服务所在的namespace,Headless Servic和StatefulSet必须在相同的namespace5..cluster.local为Cluster Domain

学习Statefulset之后需要掌握如下

1.如何创建 StatefulSet2.通过StatefulSet 怎样管理它的 Pod3.如何删除 StatefulSet4.如何对 StatefulSet 进行扩容/缩容5.如何更新一个 StatefulSet 的 Pod

部署一个web应用

作为开始,使用如下示例创建一个StatefulSet。它创建了一个Headless Service nginx 用来发布StatefulSet web中的Pod的IP地址。

cat  statefulset.yaml

apiVersion: v1kind: Servicemetadata:  name: nginx  labels:    app: nginxspec:  ports:  - port: 80    name: web  clusterIP: None  selector:    app: nginx---apiVersion: apps/v1beta1kind: StatefulSetmetadata:  name: webspec:  serviceName: "nginx"  replicas: 2  template:    metadata:      labels:        app: nginx    spec:      containers:      - name: nginx        image: nginx        ports:        - containerPort: 80          name: web        volumeMounts:        - name: www          mountPath: /usr/share/nginx/html  volumeClaimTemplates:  - metadata:      name: www    spec:      accessModes: [ "ReadWriteOnce" ]      resources:        requests:          storage: 1Gi

为什么要使用volumeClaimTemplate?

对于有状态应用都会用到持久化存储,比如mysql主从,由于主从数据库的数据是不能存放在一个目录下的,每个mysql节点都需要有自己独立的存储空间。而在deployment中创建的存储卷是一个共享的存储卷,多个pod使用同一个存储卷,它们数据是同步的,而statefulset定义中的每一个pod都不能使用同一个存储卷,这就需要使用volumeClainTemplate,当在使用statefulset创建pod时,会自动生成一个PVC,从而请求绑定一个PV,每一个pod都有自己专用的存储卷。Pod、PVC和PV对应的关系图如下:

通过statefulset部署pod,并且观察pod创建的过程

你需要使用两个终端窗口。在第一个终端中,使用kubectl get 来查看 StatefulSet的Pods的创建情况。

kubectl get pods -w -l app=nginx

在另一个终端中,使用 

kubectl  apply  -f  statefulset.yaml

来创建定义在statefulset.yaml 中的 Headless Service 和 StatefulSet。

上面的命令创建了两个Pod,每个都运行了一个NGINX web 服务器。获取 nginxService和web StatefulSet来验证是否成功的创建了它们。

1.查看service

kubectl get service nginx

显示如下:

NAME      CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE

nginx           None         <none>        80/TCP    12s

2.查看statefulset

kubectl get statefulset

显示如下:

NAME      DESIRED   CURRENT   AGE

web             2              1              20s

顺序创建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才会被启动。

StatefulSet中的Pod

StatefulSet 中的 Pod 拥有一个唯一的顺序索引和稳定的网络身份标识

检查 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>。webStatefulSet 拥有两个副本,所以它创建了两个 Pod:web-0 和 web-1

使用稳定的网络身份标识

每个Pod都拥有一个基于其顺序索引的稳定的主机名(statefulset创建的pod的主机名由statefulset的名称和有序索引组成),使用kubectl exec 在每个Pod中执行hostname

for i in 0 1; do kubectl exec web-$i -- sh -c 'hostname'; doneweb-0web-1

使用kubectl run运行一个提供nslookup命令的容器,该命令来自于dnsutils包。通过对Pod的主机名执行nslookup,你可以检查他们在集群内部的DNS地址。

kubectl exec -it  web-1 -- /bin/bashapt-get  install  dns-utils -y nslookup web-0.nginx.default.svc.cluster.local

在一个终端中查看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 时,你的应用就能够发现它们的地址。

域名对应的表格:

导入稳定的存储

获取 web-0 和 web-1 的 PersistentVolumeClaims

kubectl get pvc -l app=nginx

显示如下:

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 2 ; do kubectl exec web-$i -- sh -c 'echo $(hostname) > /usr/share/nginx/html/index.html'; don

for i in 0 1 2; do kubectl exec -it web-$i -- curl localhost; done

显示如下:

web-0

web-1

请注意,如果你看见上面的 curl 命令返回了403 Forbidden的响应,你需要像修改挂载的目录的权限:

for i in 01 2; do kubectl exec web-$i -- chmod 755 /usr/share/nginx/html; done

修改之后重新尝试上面的 curl 命令。


想要了解kubernetes更多知识和生产案例,获取免费视频,可按如下方式获取 哈~~~

微信:luckylucky421302




原文作者:DevOps和k8s全栈技术;如有侵权,请联系管理员删除。

请登录后发表评论 登录
全部评论
云计算架构师、阿里云开发者社区专家博主、腾讯云架构师北京同盟成员、Linux基金会开源软件学园2023、2024年度优秀讲师,在中国计算机学会(CCF)任职人工智能与模式识别委员和计算机应用委员、中国科普作家协会会员,清华大学出版社出版的畅销书《Kubernetes从入门到DevOps企业应用实战》作者。

注册时间:2017-10-15

  • 博文量
    127
  • 访问量
    61683