deployment, daemonset, job无状态,但是数据库集群的相关服务一般都是有状态的
1) 每个pod有唯一网络标识,可用于发现集群内其他成员.
每个结点有固定id,集群中成员可通过该id互相发现并通信。集群规模固定。
2) statefulset控制的pod启停顺序是受控的,操作第n个pod时,
前n-1个pod已经是运行且准备好的状态
3) statefuleset中的pod采用持久化存储卷,通过PV/PVC来实现,
删除pod默认不会删除与statefulset相关的存储卷。
4) statefulset搭配使用headless service,在statefulset中要
声明其属于哪个headless service。
headless service没有Cluster IP,解析headless service的DNS域名,
返回的是该service对应的全部pod的endpoint列表。
5) 每个satefulset的pod的域名格式如下:
$(podname).(headless server name)
FQDN: $(podname).(headless server name).namespace.svc.cluster.local
deployment的名字是随机的,无法产生固定身份id,并且pod的ip是运行才会产生的。
集群中的pod需要挂接共享存储。
1) 持久化存储,pod重新调度后: 还能访问到相同的持久化数据,基于pvc实现
2) 稳定的网络标志,pod重新调度后:其podname和hostname不变,基于headless service(无cluster ip)
3) 有序部署,pod按照顺序启动,按照从0到N-1顺序
4) 逆序删除,删除pod,按照从N-1到0的顺序
headless service + 用于创建PersistentVolumes的volumeClaimTemplates + 定语具体应用的statefulset
statefulsetName-{0...N-1}.serviceName.namespace.svc.cluster.local
解释:
serviceName: 是headless service名字
statefulsetName:是statefuleSet的名字
namespace: 是服务锁在的namespace, headless service和statefulset必须在同一个namespace下面
.cluster.local: 是cluster domain
注意:
1)StatefulSet 在节点丢失之后不迁移到其它节点,是 work as design
2)删除statefulset不会删除与该statefulset相关联的volume
3)给pod的存储是通过PersistentVolume Provisioner根据请求的storage class进行配置。
下面的代码来自: kubernetes-handbook
apiVersion: v1
kind: Service
metadata:
name: nginx
labels:
app: nginx
spec:
ports:
- port:80
name: web
clusterIP: None
selector:
app: nginx
分析:
headless service最重要的就是clusterIP为None
---
apiVersion: apps/v1beta1
kind: StatefulSet
metadata:
name: web
spec:
serviceName: "nginx"
replicas: 3
template:
metadata:
labels:
app: nginx
spec:
terminationGracePeriodSeconds: 10
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.beta.kubernetes.io/storage-class: anything
spec:
accessModes: [ "ReadWriteOnce" ]
resources:
requests:
storage: 1Gi
分析:
1) statefulset与deployment的最大区别就是:
多了
serviceName: "nginx"字段,
该字段作用就是与nginx这个headless service建立联系
2) statefulset必须提供pvc
上述例子中即为:
volumeClaimTemplates:
- metadata:
name: www
annotations:
volume.beta.kubernetes.io/storage-class: anything
spec:
accessModes: [ "ReadWriteOnce" ]
resources:
requests:
storage: 1Gi
pod的ip会在重建后发生变化,而statefulset需要能稳定标识pod的名称,
而headless service恰好可以给每个pod唯一的名称。
volumeClaimTemplate: 卷申请模板,为每个pod生成不同pvc,并绑定pv,从而实现每个pod自己的存储,
对于statefulset应用场景,例如mongodb集群这种分布式集群,数据不一样,各个结点
不能使用同一存储卷,之后再利用该集群本身机制去进行数据同步更新等。
如果是deployment中的pod定义的存储卷,所有副本集共用一个存储卷,因为基于模板。
无法实现有状态应用自身的特性(即有状态应用在每个结点上数据不一样,需要有各自的存储区域)。
原因是pod如果发生故障会飘移到其他结点上,pod ip发生变化。所以不能基于pod ip通信,
而是需要一个固定的标识来通信,而这种pod域名满足固定标示的特点,可以被用于服务之间通信。
headless service的域名为:
其中cluster.local指的是集群的域名
pvc的命名规则如下:
上面volumeClaimTemplates.name>为www, pod名称=web-[0-2]
则pvc名称为:
www-web-0, www-web-1, www-web-2。
需要包含: api版本,类型,元数据(名称,标签),spec规格: 端口列表(每个端口,名称) , clusterIP, selector
apiVersion
内容如下:
---
apiVersion: v1
kind: Service
metadata:
name: nginx
labels:
app: nginx
spec:
ports:
- port: 80
name: web
selector:
app: nginx
clusterIP: None
执行命令:
kubectl create -f myservice.yaml
查看:
kubectl get svc -n openstack
输出结果:
[root@localhost statefulset_demo_code]# kubectl get svc -n default
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1
nginx ClusterIP None
需要包含: api版本, 类型,元数据(statefulset的名称),
spec规格: 服务名称,副本数,
模板: 元数据(标签列表),
spec:容器列表: 容器名称,镜像,端口列表(容器端口), 挂载点列表(每个挂载名,挂载路径),
卷申请模板列表: 元数据(名称,注释),spec规格(访问模式,资源列表:请求列表(存储))
7.2.1) 查询系统中已有的storageclass
[root@localhost statefulset_demo_code]# kubectl get storageclass
NAME PROVISIONER AGE
standard (default) k8s.io/minikube-hostpath 91d
7.2.2) 内容如下:
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: web
spec:
selector:
matchLabels:
app: nginx # has to match .spec.template.metadata.labels
serviceName: "nginx" #声明它属于哪个Headless Service.
replicas: 3 # by default is 1
template:
metadata:
labels:
app: nginx # has to match .spec.selector.matchLabels
spec:
terminationGracePeriodSeconds: 10
containers:
- name: nginx
image: k8s.gcr.io/nginx-slim:0.8
ports:
- containerPort: 80
name: web
volumeMounts:
- name: www
mountPath: /usr/share/nginx/html
volumeClaimTemplates: #可看作pvc的模板
- metadata:
name: www
spec:
accessModes: [ "ReadWriteOnce" ]
storageClassName: "standard" #存储类名,改为集群中已存在的
resources:
requests:
storage: 1Gi
注意:
将上述storageClassName后面的"standard"替换为步骤
7.2.1中查询到的系统已有的storageclass
7.2.3) 执行命令
kubectl create -f mystatefulset.yaml
输出结果如下
statefulset.apps/web created
[root@localhost statefulset_demo_code]# kubectl get statefulset -n default
NAME READY AGE
web 3/3 5m53s
[root@localhost statefulset_demo_code]# kubectl get pods -n default
NAME READY STATUS RESTARTS AGE
web-0 1/1 Running 0 6m12s
web-1 1/1 Running 0 5m6s
web-2 1/1 Running 0 5m1s
查看pvc
[root@localhost statefulset_demo_code]# kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
www-web-0 Bound pvc-ac506022-91a8-11e9-9cb2-08002753dff7 1Gi RWO standard 8m3s
www-web-1 Bound pvc-d40397e2-91a8-11e9-9cb2-08002753dff7 1Gi RWO standard 6m57s
www-web-2 Bound pvc-d675f485-91a8-11e9-9cb2-08002753dff7 1Gi RWO standard 6m52s
其中pvc名称符合:
查看endpoints
[root@localhost statefulset_demo_code]# kubectl get ep
NAME ENDPOINTS AGE
kubernetes 192.168.99.103:8443 91d
nginx 172.17.0.7:80,172.17.0.8:80,172.17.0.9:80 35m
statefulset用于有状态服务,例如数据库集群,pod启动有先后顺序。
需要挂载pv到pvc来做永久数据存储。
参考:
[1] kubernetes权威指南:从docker到kubernetes实践纪念版.pdf
[2] kubernetes-handbook
[3] https://www.cnblogs.com/hixiaowei/p/9783560.html
[4] https://blog.51cto.com/newfly/2140004