前言:
kubernetes有很多的控制器,比如 replicasets(简称rs),replicationcontrollers(简称rc),Deployment(简称deploy),DaemonSets(简称ds),StateFulSets(简称sts),那么,rs,rc是基本的pod控制器,这个就不说了,底层控制器,和deploy深度绑定。deploy和ds相对其它的控制器来说就非常常用了,基本的部署工作都是由这两个控制器完成,而sts由于它的自身特点导致它的使用范围不是特别的宽,但也是一个极为重要的控制器,需要我们能够熟练使用此控制器。
StateFulSets的基本概念:
StatefulSet本质上是Deployment的一种变体,在v1.9版本中已成为GA版本,它为了解决有状态服务的问题,它所管理的Pod拥有固定的Pod名称,启停顺序,在StatefulSet中,Pod名字称为网络标识(hostname),还必须要用到共享存储。
在Deployment中,与之对应的服务是service,而在StatefulSet中与之对应的headless service,headless service,即无头服务,与service的区别就是它没有Cluster IP,解析它的名称时将返回该Headless Service对应的全部Pod的Endpoint列表。
除此之外,StatefulSet在Headless Service的基础上又为StatefulSet控制的每个Pod副本创建了一个DNS域名,这个域名的格式为:
FQDN:$(podname).(headless server name).namespace.svc.cluster.local
StateFulSets的构成方式:
pod部署清单,部署方式指定为StateFulSets;
Headless Service:用来定义Pod网络标识( DNS domain);(这个无头service的作用是可以体现StateFulSet控制器的稳定的网络特性,不是非必须的,可用可不用)
volumeClaimTemplates :存储卷申请模板,创建PVC,指定pvc名称大小,将自动创建pvc,且pvc必须由存储类供应(这个是体现StateFulSet控制器的稳定的存储特性,不是非必须的,可用可不用)
StateFulSets的特点:
Pod一致性:包含次序(启动、停止次序)、网络一致性。此一致性与Pod相关,与被调度到哪个node节点无关;
稳定的次序:对于N个副本的StatefulSet,每个Pod都在[0,N)的范围内分配一个数字序号,且是唯一的;
稳定的网络:Pod的hostname模式为( s t a t e f u l s e t 名 称 ) − (statefulset名称)-(statefulset名称)−(序号);
稳定的存储:通过VolumeClaimTemplate为每个Pod创建一个PV。删除、减少副本,不会删除相关的卷。
OK,以上是StateFulSets的基本介绍,下面就由两个部署实例来说明如何使用StateFulSets控制器并说明它的具体特点。
在正式的使用StateFulSets方式部署之前,建议先部署一个nfs-client-provisioner插件,使得集群内部能够动态的分配pv,nfs-client-provisioner插件部署见我的博客:
kubernetes学习之持久化存储StorageClass(4)_晚风_END的博客-CSDN博客
一,
StateFulSets方式部署nginx
首先,确认我的nfs插件已经安装好了,也就是动态存储插件可用了:
StorageClass的名称是managed-nfs-storage
[root@k8s-master nfs]# k get sc NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE managed-nfs-storage (default) fuseim.pri/ifs Delete Immediate true 6h9m
部署使用StateFulSet控制器的nginx的清单文件:
cat << EOF > nginx-sts.yaml apiVersion: apps/v1 kind: StatefulSet metadata: name: web namespace: web spec: selector: matchLabels: app: nginx #必须匹配 .spec.template.metadata.labels serviceName: "nginx" #声明它属于哪个Headless Service. replicas: 3 #副本数 template: metadata: labels: app: nginx # 必须配置 .spec.selector.matchLabels spec: terminationGracePeriodSeconds: 10 containers: - name: nginx image: nginx:1.20 ports: - containerPort: 80 name: web volumeMounts: - name: nginx-pvc mountPath: /usr/share/nginx/html volumeClaimTemplates: #可看作pvc的模板 - metadata: name: nginx-pvc spec: accessModes: [ "ReadWriteOnce" ] storageClassName: "managed-nfs-storage" #存储类名,改为集群中已存在的 resources: requests: storage: 1Gi EOF
无头service:
cat << EOF > nginx-svc.yaml apiVersion: v1 kind: Service metadata: name: nginx namespace: web labels: app: nginx spec: ports: - port: 80 name: web clusterIP: None selector: app: nginx EOF
查看pod的情况(注意,这些pod的名称是web+递增的数字组成的,如果扩容名称按顺序增加,那么一个稳定的pod名称的意义在于集群内的DNS将会有一个稳定的解析,pod无论怎么改变):
[root@k8s-master nfs-sc]# k get po -n web -owide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES web-0 1/1 Running 0 6s 10.244.0.7 k8s-master <none> <none> web-1 1/1 Running 0 5s 10.244.2.9 k8s-node2 <none> <none> web-2 1/1 Running 0 3s 10.244.1.7 k8s-node1 <none> <none>
查看pv和pvc的情况:
[root@k8s-master nfs-sc]# k get pv,pvc -n web NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE persistentvolume/pvc-a7b73ac0-d881-4c96-9fdb-e8d71f60d848 1Gi RWO Delete Bound web/nginx-pvc-web-1 managed-nfs-storage 40m persistentvolume/pvc-dabd8050-77f6-4655-8434-dac2f9a077eb 1Gi RWO Delete Bound web/nginx-pvc-web-2 managed-nfs-storage 40m persistentvolume/pvc-eb159490-353c-4aea-9412-10056a29911d 1Gi RWO Delete Bound web/nginx-pvc-web-0 managed-nfs-storage 40m NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE persistentvolumeclaim/nginx-pvc-web-0 Bound pvc-eb159490-353c-4aea-9412-10056a29911d 1Gi RWO managed-nfs-storage 40m persistentvolumeclaim/nginx-pvc-web-1 Bound pvc-a7b73ac0-d881-4c96-9fdb-e8d71f60d848 1Gi RWO managed-nfs-storage 40m persistentvolumeclaim/nginx-pvc-web-2 Bound pvc-dabd8050-77f6-4655-8434-dac2f9a077eb 1Gi RWO managed-nfs-storage 40m
查看service的情况:
[root@k8s-master nfs-sc]# k get svc -n web NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE nginx ClusterIP None <none> 80/TCP 42m
此时,进入nfs的存储目录可以看到有三个文件夹,以pod名称开始:
[root@k8s-master nfs-sc]# ls web-nginx-pvc-web-* web-nginx-pvc-web-0-pvc-eb159490-353c-4aea-9412-10056a29911d: web-nginx-pvc-web-1-pvc-a7b73ac0-d881-4c96-9fdb-e8d71f60d848: web-nginx-pvc-web-2-pvc-dabd8050-77f6-4655-8434-dac2f9a077eb
在每个目录下建立nginx的首页测试文件:
[root@k8s-master nfs-sc]# echo "wo shi web-0" >web-nginx-pvc-web-0-pvc-eb159490-353c-4aea-9412-10056a29911d/index.html [root@k8s-master nfs-sc]# echo "wo shi web-1" >web-nginx-pvc-web-1-pvc-a7b73ac0-d881-4c96-9fdb-e8d71f60d848/index.html [root@k8s-master nfs-sc]# echo "wo shi web-2" >web-nginx-pvc-web-2-pvc-dabd8050-77f6-4655-8434-dac2f9a077eb/index.html
查看pod的IP:
[root@k8s-master nfs-sc]# k get po -n web -owide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES web-0 1/1 Running 0 34m 10.244.1.6 k8s-node1 <none> <none> web-1 1/1 Running 0 34m 10.244.2.8 k8s-node2 <none> <none> web-2 1/1 Running 0 34m 10.244.0.6 k8s-master <none> <none>
访问测试页面:
[root@k8s-master nfs-sc]# curl 10.244.1.6 wo shi web-0 [root@k8s-master nfs-sc]# curl 10.244.2.8 wo shi web-1 [root@k8s-master nfs-sc]# curl 10.244.0.6 wo shi web-2
删除pod,重新生成pod以改变它们的IP,测试看看nginx的首页文件还能否访问到:
可以看到,pod的IP如何改变不影响它对外提供服务,因为volume存储是不变的,
[root@k8s-master nfs-sc]# k delete pod web-0 web-1 web-2 -n web pod "web-0" deleted pod "web-1" deleted pod "web-2" deleted [root@k8s-master nfs-sc]# k get po -n web -owide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES web-0 1/1 Running 0 6s 10.244.0.7 k8s-master <none> <none> web-1 1/1 Running 0 5s 10.244.2.9 k8s-node2 <none> <none> web-2 1/1 Running 0 3s 10.244.1.7 k8s-node1 <none> <none> [root@k8s-master nfs-sc]# curl 10.244.0.7 wo shi web-0 [root@k8s-master nfs-sc]# curl 10.244.2.9 wo shi web-1 [root@k8s-master nfs-sc]# curl 10.244.1.7 wo shi web-2
二,
StateFulSet方式部署MySQL
建立相关namespace,名字叫database:
cat > mysql-sts-ns.yaml <<EOF apiVersion: v1 kind: Namespace metadata: name: database EOF
部署MySQL的清单文件:
cat > mysql-sts.yaml <<EOF apiVersion: apps/v1 kind: StatefulSet metadata: name: mysql namespace: database spec: selector: matchLabels: app: mysql #必须匹配 .spec.template.metadata.labels serviceName: "mysql" #声明它属于哪个Headless Service. replicas: 3 #副本数 template: metadata: labels: app: mysql # 必须配置 .spec.selector.matchLabels spec: terminationGracePeriodSeconds: 10 containers: - name: mysql image: mysql:5.7.23 ports: - containerPort: 3306 name: mysql env: - name: MYSQL_ROOT_PASSWORD value: "123456" volumeMounts: - name: mysql-pvc mountPath: /var/lib/mysql volumeClaimTemplates: #可看作pvc的模板 - metadata: name: mysql-pvc spec: accessModes: [ "ReadWriteOnce" ] storageClassName: "managed-nfs-storage" #存储类名,改为集群中已存在的 resources: requests: storage: 1Gi EOF
部署完成后,查看pod的大体信息:
[root@k8s-master ~]# k get pod,pv,pvc -n database -owide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES pod/mysql-0 1/1 Running 0 38m 10.244.2.10 k8s-node2 <none> <none> pod/mysql-1 1/1 Running 0 38m 10.244.0.8 k8s-master <none> <none> pod/mysql-2 1/1 Running 0 37m 10.244.0.9 k8s-master <none> <none> NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE VOLUMEMODE persistentvolume/pvc-46e7893f-3b66-4899-ae13-f1400eb1ff7f 1Gi RWO Delete Bound database/mysql-pvc-mysql-2 managed-nfs-storage 37m Filesystem persistentvolume/pvc-96748d04-0e1c-4b70-8c93-baf6a1d857d3 1Gi RWO Delete Bound database/mysql-pvc-mysql-1 managed-nfs-storage 38m Filesystem persistentvolume/pvc-a7b73ac0-d881-4c96-9fdb-e8d71f60d848 1Gi RWO Delete Bound web/nginx-pvc-web-1 managed-nfs-storage 4h40m Filesystem persistentvolume/pvc-b939521e-1e4b-4ba4-92b7-94f96cdba9a1 1Gi RWO Delete Bound database/mysql-pvc-mysql-0 managed-nfs-storage 38m Filesystem persistentvolume/pvc-dabd8050-77f6-4655-8434-dac2f9a077eb 1Gi RWO Delete Bound web/nginx-pvc-web-2 managed-nfs-storage 4h40m Filesystem persistentvolume/pvc-eb159490-353c-4aea-9412-10056a29911d 1Gi RWO Delete Bound web/nginx-pvc-web-0 managed-nfs-storage 4h40m Filesystem NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE VOLUMEMODE persistentvolumeclaim/mysql-pvc-mysql-0 Bound pvc-b939521e-1e4b-4ba4-92b7-94f96cdba9a1 1Gi RWO managed-nfs-storage 38m Filesystem persistentvolumeclaim/mysql-pvc-mysql-1 Bound pvc-96748d04-0e1c-4b70-8c93-baf6a1d857d3 1Gi RWO managed-nfs-storage 38m Filesystem persistentvolumeclaim/mysql-pvc-mysql-2 Bound pvc-46e7893f-3b66-4899-ae13-f1400eb1ff7f 1Gi RWO managed-nfs-storage 37m Filesystem
测试:
首先安装一哈MySQL的客户端:
yum install mariadb -y
登录进数据库后,依次按pod名称建立相应的数据库名称以作标识(本例就做了一个):
账号是root,密码是123456
[root@k8s-master ~]# mysql -uroot -p -h10.244.2.10 Enter password: Welcome to the MariaDB monitor. Commands end with ; or \g. Your MySQL connection id is 2 Server version: 5.7.23 MySQL Community Server (GPL) Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. MySQL [(none)]> create database mysql-0; ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '-0' at line 1 MySQL [(none)]> create database mysql0; Query OK, 1 row affected (0.01 sec)
删除MySQL的相关pod,等待重建pod完成后,再次进入数据库查看前面建立的数据库标识是否存在:
可以看到,删除原pod后,重新建立了pod,pod的IP改变了,但登录进去后,标识用的数据库还是存在的。
[root@k8s-master ~]# k delete pod mysql-0 mysql-1 mysql-2 -n database pod "mysql-0" deleted pod "mysql-1" deleted pod "mysql-2" deleted [root@k8s-master ~]# k get po -n database -owide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES mysql-0 1/1 Running 0 49s 10.244.2.11 k8s-node2 <none> <none> mysql-1 1/1 Running 0 40s 10.244.0.10 k8s-master <none> <none> mysql-2 1/1 Running 0 38s 10.244.0.11 k8s-master <none> <none> [root@k8s-master ~]# mysql -uroot -p123456 -h10.244.2.11 Welcome to the MariaDB monitor. Commands end with ; or \g. Your MySQL connection id is 2 Server version: 5.7.23 MySQL Community Server (GPL) Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. MySQL [(none)]> show databases; +--------------------+ | Database | +--------------------+ | information_schema | | mysql | | mysql0 | | performance_schema | | sys | +--------------------+ 5 rows in set (0.03 sec)
总结:
StateFulSet控制器的两个显著特点,一,按顺序创建,pod名称包含有自增数字,这使得它的域名是可以固定的。二,由StateFulSet控制器通过StorageClass控制器来控制volume持久存储卷和pod的名称一一对应,从而使得pod更加的稳定。
其实,说人话就是StateFulSet控制器使得pod能够形成一组pod,这一组pod能够进行一定的序列化。因此,StateFulSet控制器常常使用在比较复杂的需要一定序列化特点的集群搭建方面,比如,MySQL主从复制集群,redis集群的部署基础都是StateFulSet控制器。