1. Statefulset 控制器
StatefulSet 是为了管理有状态服务的问题而设计的。
1.1 什么叫有状态服务?
StatefulSet 是有状态的集合,管理有状态的服务,它所管理的 Pod 的名称不能随意变化。数据
持久化的目录也是不一样,每一个 Pod 都有自己独有的数据持久化存储目录。比如 MySQL 主
从、redis 集群等。
1.2 什么叫无状态服务?
RC、Deployment、DaemonSet 都是管理无状态的服务,它们所管理的 Pod 的 IP、名字,启
停顺序等都是随机的。个体对整体无影响,所有 pod 都是共用一个数据卷的,部署的 tomcat 就是无状态的服务,tomcat 被删除,在启动一个新的 tomcat,加入到集群即可,跟 tomcat 的名
字无关。
1.3 StatefulSet 的组成
1. Headless Service:用来定义 pod 网路标识,生成可解析的 DNS 记录
2. volumeClaimTemplates:存储卷申请模板,创建 pvc,指定 pvc 名称大小,自动创建pvc,且 pvc 由存储类供应。
3. StatefulSet:管理 pod 的
扩展:什么是 Headless service?
Headless service 不分配 clusterIP,headless service 可以通过解析 service 的 DNS,返回所
有 Pod 的 dns 和 ip 地址 (statefulSet 部署的 Pod 才有 DNS),普通的 service,只能通过解析
service 的 DNS 返回 service 的 ClusterIP。
为什么要用 headless service(没有 service ip 的 service)?
在使用 Deployment 时,创建的 Pod 名称是没有顺序的,是随机字符串,在用 statefulset 管理
pod 时要求 pod 名称必须是有序的 ,每一个 pod 不能被随意取代,pod 重建后 pod 名称还是
一样的。因为 pod IP 是变化的,所以要用 Pod 名称来识别。pod 名称是 pod 唯一性的标识符,
必须持久稳定有效。这时候要用到无头服务,它可以给每个 Pod 一个唯一的名称。
为什么要用 volumeClaimTemplate?
对于有状态应用都会用到持久化存储,比如 mysql 主从,由于主从数据库的数据是不能存放在一
个目录下的,每个 mysql 节点都需要有自己独立的存储空间。而在 deployment 中创建的存储卷
是一个共享的存储卷,多个 pod 使用同一个存储卷,它们数据是同步的,而 statefulset 定义中
的每一个 pod 都不能使用同一个存储卷,这就需要使用 volumeClainTemplate,当在使用
statefulset 创建 pod 时,volumeClainTemplate 会自动生成一个 PVC,从而请求绑定一个
PV,每一个 pod 都有自己专用的存储卷。
Pod、PVC 和 PV 对应的关系图如下:
2. Statefulset 资源清单文件编写技巧
kubectl explain statefulset.spec #可以通过帮助查看
#官网查看:https://kubernetes.io/zh-cn/docs/tutorials/stateful-application/basic-stateful-set/
3. Statefulset 使用案例:部署 web 站点
3.1 创建存储类
cat > class-web.yaml << EOF
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: nfs-web
provisioner: example.com/nfs
EOF
[root@k8s-master web]# kubectl get storageclass|grep nfs-web
nfs-web example.com/nfs Delete Immediate false 67s
[root@k8s-master web]#
3.2 创建 Statefulset控制器资源清单
cat > statefulset.yaml << EOF
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
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"]
storageClassName: "nfs-web"
resources:
requests:
storage: 1Gi
EOF
[root@k8s-master web]# kubectl get pods #看到了Statefulset控制器创建的2个pod
NAME READY STATUS RESTARTS AGE
pod/web-0 1/1 Running 0 2m38s
pod/web-1 1/1 Running 0 2m20s
[root@k8s-master web]# kubectl get svc #查看 headless service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 21d
nginx ClusterIP None <none> 80/TCP 6m54s
[root@k8s-master web]#
[root@k8s-master web]# kubectl get statefulset
NAME READY AGE
web 2/2 5m10s
[root@k8s-master nfs_pro]# kubectl get pv #查看pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pvc-4bdf1ade-c083-4d69-be7b-a8062a637a4e 1Gi RWO Delete Bound default/www-web-0 nfs-web 14m
pvc-577e9608-3018-4ea9-afeb-fcd1bbfd7a73 1Gi RWO Delete Bound default/www-web-1 nfs-web 13m
[root@k8s-master nfs_pro]#
[root@k8s-master web]# kubectl get pvc #查看pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
www-web-0 Bound pvc-4bdf1ade-c083-4d69-be7b-a8062a637a4e 1Gi RWO nfs-web 11m
www-web-1 Bound pvc-577e9608-3018-4ea9-afeb-fcd1bbfd7a73 1Gi RWO nfs-web 10m
[root@k8s-master nfs_pro]#
[root@k8s-master nfs_pro]# pwd #此目录是nfs的共享目录
/data/nfs_pro
[root@k8s-master nfs_pro]# ll #看到了两个pod绑定的pvc目录
total 0
drwxrwxrwx 2 root root 6 Apr 22 16:04 default-www-web-0-pvc-4bdf1ade-c083-4d69-be7b-a8062a637a4e
drwxrwxrwx 2 root root 6 Apr 22 16:05 default-www-web-1-pvc-577e9608-3018-4ea9-afeb-fcd1bbfd7a73
[root@k8s-master nfs_pro]#
[root@k8s-master nfs_pro]# for i in 0 1; do kubectl exec web-$i -- sh -c 'hostname';done #查看 pod 主机名
web-0
web-1
[root@k8s-master nfs_pro]#
#通过上面可以看到创建的 pod 是有序的