K8S学习之Statefulset
Statefulset概念应用场景包括1、稳定的持久化存储,即Pod重新调度后还是能访问到相同的持久化数据,基于PVC来实现2、稳定的网络标志,即Pod重新调度后其PodName和HostName不变,基于Headless Service(即没有Cluster IP的Service)来实现3、有序部署,有序扩展,即Pod是有顺序的,在部署或者扩展的时候要依据定义的顺序依次进行(即从0到N-1,在下
Statefulset概念
应用场景包括
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由以下几个部分组成
1、通过Headless Service(clusterIP: None)生成可解析的DNS记录
2、通过volumeClaimTemplates创建pvc和对应的pv绑定
3、定义StatefulSet来创建pod
和 Deployment不同的是,StatefulSet 为它们的每个 Pod 维护了一个固定的ID。这些 Pod 是基于相同的声明来创建的,但是不能相互替换:无论怎么调度,每个 Pod 都有一个永久不变的ID。
StatefulSet中每个Pod的DNS格式
statefulSetName-{0…N-1}.serviceName.namespace.svc.cluster.local
1、statefulSetName为StatefulSet的名字
2、0…N-1为Pod所在的序号,从0开始到N-1
3、serviceName为Headless Service的名字
4、namespace为服务所在的namespace,Headless Servic和StatefulSet必须在相同的namespace
5、.svc.cluster.local为Cluster Domain
部署一个web应用
这里headless与statefulset写到一个yaml里了
[root@master ~]# vim 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
serviceName: "nginx"
replicas: 3
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
name: web
volumeMounts:
- name: www
mountPath: /usr/share/nginx/html
volumeClaimTemplates:
- metadata:
name: www
spec:
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 1Gi
查看pod的生成,可以看到是顺序性的创建(删除时是倒序删除,-w可能不方便验证)。
[root@master ~]# kubectl apply -f statefulset.yaml
[root@master ~]# kubectl get pod -l app=nginx -w 新开窗口便于观察
[root@master ~]# kubectl get statefulsets.apps
NAME READY AGE
web 3/3 14s
[root@master ~]# kubectl get pod -l app=nginx
NAME READY STATUS RESTARTS AGE
web-0 1/1 Running 0 18s
web-1 1/1 Running 0 15s
web-2 1/1 Running 0 12s
[root@master ~]# kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
www-web-0 Bound v1 1Gi RWO 8s
www-web-1 Bound v4 4Gi RWO,RWX 5s
www-web-2 Bound v5 5Gi RWO,RWX 2s
[root@master ~]# kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
v1 1Gi RWO Retain Bound default/www-web-0
v4 4Gi RWO,RWX Retain Bound default/www-web-1
v5 5Gi RWO,RWX Retain Bound default/www-web-2
为什么要使用volumeClaimTemplate
对于有状态应用都会用到持久化存储,比如mysql主从,由于主从数据库的数据是不能存放在一个目录下的,每个mysql节点都需要有自己独立的存储空间。而在deployment中创建的存储卷是一个共享的存储卷,多个pod使用同一个存储卷,它们数据是同步的。statefulset定义中的每一个pod都不能使用同一个存储卷,这就需要使用volumeClainTemplate,当在使用statefulset创建pod时,会自动生成一个PVC,从而请求绑定一个PV,每一个pod都有自己专用的存储卷。
我们可以进入到statefulset的容器内查看hostname,命名符合前面所提到的StatefulSet中每个Pod的DNS格式 ,statefulset名-序号。
[root@master ~]# kubectl exec -it web-0 -- /bin/bash
root@web-0:/# hostname
web-0
或者不进入
[root@master ~]# kubectl exec web-0 -- /bin/bash -c "hostname"
web-0
用nslookup来验证StatefulSet中每个Pod的DNS格式
[root@master ~]# kubectl exec -it web-0 -- /bin/bash
root@web-0:/# apt-get update
root@web-0:/# apt-get -y install dnsutils
root@web-0:/# nslookup web-0.nginx.default.svc.cluster.local
Server: 10.96.0.10
Address: 10.96.0.10#53
Name: web-0.nginx.default.svc.cluster.local
Address: 10.244.1.88
root@web-0:/# nslookup web-1.nginx.default.svc.cluster.local
Server: 10.96.0.10
Address: 10.96.0.10#53
Name: web-1.nginx.default.svc.cluster.local
Address: 10.244.1.89
root@web-0:/# nslookup web-2.nginx.default.svc.cluster.local
Server: 10.96.0.10
Address: 10.96.0.10#53
Name: web-2.nginx.default.svc.cluster.local
Address: 10.244.1.90
根据上面的解析地址,来对比一下pod的地址,确认StatefulSet的DNS命名格式。
[root@master ~]# kubectl get pod -owide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED
web-0 1/1 Running 0 3h40m 10.244.1.88 node1 <none>
web-1 1/1 Running 0 3h40m 10.244.1.89 node1 <none>
web-2 1/1 Running 0 3h40m 10.244.1.90 node1 <none>
安装inetutils-ping来ping一下域名和IP10.96.0.10,会发现ping不同IP,服务是通过域名来实现的
root@web-0:/# apt-get -y install inetutils-ping
root@web-0:/# ping web-0.nginx.default.svc.cluster.local
PING web-0.nginx.default.svc.cluster.local (10.244.1.88): 56 data bytes
64 bytes from 10.244.1.88: icmp_seq=0 ttl=64 time=0.042 ms
64 bytes from 10.244.1.88: icmp_seq=1 ttl=64 time=0.103 ms
root@web-0:/# ping 10.96.0.10
PING 10.96.0.10 (10.96.0.10): 56 data bytes
^C--- 10.96.0.10 ping statistics ---卡死
写入index.html,访问域名,来查看服务指向
[root@master ~]# kubectl get pv v1 -oyaml
spec:
nfs:
path: /data/volume_test/v1
[root@master ~]# echo v5 >/data/volume_test/v5/index.html
[root@master ~]# echo v4 >/data/volume_test/v4/index.html
[root@master ~]# echo v1 >/data/volume_test/v1/index.html
[root@master ~]# curl 10.244.1.88
v1
[root@master ~]# curl 10.244.1.89
v4
[root@master ~]# curl 10.244.1.90
v5
这个域名在节点上访问时访问不到的,必须进入到容器内才能访问到
[root@master ~]# curl web-0.nginx.default.svc.cluster.local
curl: (6) Could not resolve host: web-0.nginx.default.svc.cluster.local; Unknown error
[root@master ~]# ping web-0.nginx.default.svc.cluster.local
ping: web-0.nginx.default.svc.cluster.local: Name or service not known
[root@master ~]# kubectl exec -it web-0 -- /bin/bash
root@web-0:/# curl web-0.nginx.default.svc.cluster.local
v1
root@web-0:/# curl web-1.nginx.default.svc.cluster.local
v4
root@web-0:/# curl web-2.nginx.default.svc.cluster.local
v5
部署和扩缩容
1、对于包含N个副本的StatefulSet,当部署Pod时,它们是依次创建的,顺序为 0…N-1。
2、当删除 Pod 时,它们是逆序终止的,顺序为 N-1…0。
3、在将缩放操作应用到Pod之前,它前面的所有Pod 必须是 Running 和 Ready 状态。
4、在 Pod 终止之前,所有的继任者必须完全关闭。
Statefulset的资源清单yaml文件书写规范
1、Pod selector
你必须设置StatefulSet的.spec.selector字段,使之匹配其在.spec.template.metadata.labels中设置的标签。
2、pod标识
StatefulSet Pod 具有唯一的标识,该标识包括顺序标识、稳定的网络标识和稳定的存储。该标识和Pod是绑定的,不管它被调度在哪个节点上。DNS命名
3、有序索引
对于具有N个副本的StatefulSet,StatefulSet 中的每个 Pod 将被分配一个整数序号,从 0 到 N-1,该序号在StatefulSet 上是唯一的。
4、稳定的网络ID
1)StatefulSet 中的每个Pod根据StatefulSet的名称和Pod的序号派生出它的主机名。组合主机名的格式为
(
S
t
a
t
e
f
u
l
S
e
t
名
称
)
−
(StatefulSet 名称)-
(StatefulSet名称)−(序号)。上例将会创建名称分别为 web-0、web-1的Pod。 StatefulSet 可以使用headless 服务控制它的Pod的网络域。管理域的这个服务的格式为:
(
服
务
名
称
)
.
(服务名称).
(服务名称).(命名空间).svc.cluster.local,其中cluster.local是集群域。 一旦每个 Pod 创建成功,就会得到一个匹配的 DNS 子域,格式为:
(
p
o
d
名
称
)
.
(pod 名称).
(pod名称).(所属服务的 DNS 域名),其中所属服务由 StatefulSet的serviceName域来设定。
2)下面给出一些选择集群域、服务名、StatefulSet 名、及其怎样影响 StatefulSet 的 Pod 上的 DNS 名称的示例:
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。
更多推荐
所有评论(0)