vlambda博客
学习文章列表

k8s攻略之有状态服务StatefulSet

有状态服务:比较常见的mongo复制集,redis cluster,rabbitmq cluster等等。使用StatefulSet 进行创建。

无状态服务:相互之前都是独立的,很适合用横向扩充来增加服务的资源量。通常使用Deployment、DaemonSet进行创建。很多无状态应用也通过 StatefulSet 来管理

  • 创建pv

root@node1:~# cat web-pv.yaml # mkdir -p /nfs_dir/{web-pv0,web-pv1}apiVersion: v1kind: PersistentVolumemetadata: name: web-pv0 labels: type: web-pv0spec: capacity: storage: 1Gi accessModes: - ReadWriteOnce persistentVolumeReclaimPolicy: Retain storageClassName: my-storage-class nfs: path: /nfs_dir/web-pv0 server: 10.0.1.201---apiVersion: v1kind: PersistentVolumemetadata: name: web-pv1 labels: type: web-pv1spec: capacity: storage: 1Gi accessModes: - ReadWriteOnce persistentVolumeReclaimPolicy: Retain storageClassName: my-storage-class nfs: path: /nfs_dir/web-pv1 server: 10.0.1.201
[root@node-1 wgw-tmp]# kubectl apply -f web-pv01.yaml persistentvolume/web-pv0 createdpersistentvolume/web-pv1 created[root@node-1 wgw-tmp]# kubectl get pvNAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGEpv1 1Gi RWO Recycle Bound default/pvc1 nfs 20hweb-pv0 1Gi RWO Retain Available my-storage-class 10sweb-pv1 1Gi RWO Retain Available my-storage-class 10s

2、创建pvc

这一步可以省去让其自动创建,这里手动创建是为了让大家能更清楚在sts里面pvc的创建过程。这一步非常非常的关键,因为如果创建的PVC的名称和StatefulSet中的名称没有对应上,那么StatefulSet中的Pod就肯定创建不成功.
我们在这里创建了一个叫做www-web-0和www-web-1的PVC,这个名字是不是很奇怪, 而且在这个yaml里并没有提到PV的名字,所以PV和PVC是怎么bound起来的呢? 是通过labels标签下的key:value键值对来进行匹配的, 我们在创建PV时指定了label的键值对,在PVC里通过selector可以指定label。然后再回到这个PVC的名称定义:www-web-0,为什么叫这样一个看似有规律的名字呢,这里需要看看下面创建StatefulSet中的yaml,首先我们看到StatefulSet的name叫web,设置的replicas为2个,volumeMounts和volumeClaimTemplates的name必须相同,为www,所以StatefulSet创建的第一个Pod的name应该为web-0,第二个为web-1。这里StatefulSet中的Pod与PVC之间的绑定关系是通过名称来匹配的,即:
PVC_name = volumeClaimTemplates_name + "-" + pod_namewww-web-0 = www + "-" + web-0www-web-1 = www + "-" + web-1
编写pvc的yaml文件
root@node1:~# cat web-pvc.yaml kind: PersistentVolumeClaimapiVersion: v1metadata: name: www-web-0spec: accessModes: - ReadWriteOnce resources: requests: storage: 1Gi storageClassName: my-storage-class selector: matchLabels: type: web-pv0---kind: PersistentVolumeClaimapiVersion: v1metadata: name: www-web-1spec: accessModes: - ReadWriteOnce resources: requests: storage: 1Gi storageClassName: my-storage-class selector: matchLabels: type: web-pv1

创建pvc

[root@node-1 wgw-tmp]# kubectl apply -f web-pvc.yaml persistentvolumeclaim/www-web-0 createdpersistentvolumeclaim/www-web-1 created[root@node-1 wgw-tmp]# [root@node-1 wgw-tmp]# [root@node-1 wgw-tmp]# kubectl get pvcNAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGEpvc-sc Pending nfs-boge 20hpvc1 Bound pv1 1Gi RWO nfs 20hwww-web-0 Bound web-pv0 1Gi RWO my-storage-class 15swww-web-1 Bound web-pv1 1Gi RWO my-storage-class 15s

3、创建Service 和 StatefulSet

在上一步中我们已经创建了名为www-web-0的PVC了,接下来创建一个service和statefulset,service的名称可以随意取,但是statefulset的名称已经定死了,为web,并且statefulset中的volumeClaimTemplates_name必须为www,volumeMounts_name也必须为www。只有这样,statefulset中的pod才能通过命名来匹配到PVC,否则会创建失败。
root@node1:~# cat web.yaml apiVersion: v1kind: Servicemetadata: name: web-headless labels: app: nginxspec: ports: - port: 80 name: web clusterIP: None selector: app: nginx---
apiVersion: v1kind: Servicemetadata: name: web labels: app: nginxspec: ports: - port: 80 name: web selector: app: nginx
---apiVersion: apps/v1kind: StatefulSetmetadata: name: webspec: selector: matchLabels: app: nginx # has to match .spec.template.metadata.labels serviceName: "nginx" replicas: 2 # by default is 1 template: metadata: labels: app: nginx # has to match .spec.selector.matchLabels spec: terminationGracePeriodSeconds: 10 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" ] storageClassName: "my-storage-class" resources: requests: storage: 1Gi
创建service及StatefulSet
kubectl apply -f web05.yaml service/web-headless unchangedservice/web createdstatefulset.apps/web created
kubectl get serviceNAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGEkubernetes ClusterIP 10.68.0.1 <none> 443/TCP 114dmysvc ClusterIP 10.68.164.5 <none> 80/TCP 10dnginx ClusterIP 10.68.50.26 <none> 80/TCP 7d22hweb ClusterIP 10.68.55.99 <none> 80/TCP 96sweb-headless ClusterIP None <none> 80/TCP 2m19s
[root@node-1 wgw-tmp]# kubectl get statefulsets.apps -o wideNAME READY AGE CONTAINERS IMAGESweb 2/2 2m20s nginx nginx
# kubectl get pod -o wideweb-0 1/1 Running 0 3m10s 172.20.139.79 10.0.1.203 <none> <none>web-1 1/1 Running 0 3m8s 172.20.139.78 10.0.1.203 <none> <none>

校验

[root@node-1 web-pv0]# echo "this is web-0" > index.html[root@node-1 web-pv0]# echo "this is web-1" > ../web-pv1/index.html[root@node-1 web-pv0]# curl 172.20.139.78 this is web-1[root@node-1 web-pv0]# curl 172.20.139.79this is web-0# 请求service地址,发现可以实现负载均衡。[root@node-1 web-pv0]# curl 10.68.55.99this is web-0[root@node-1 web-pv0]# curl 10.68.55.99wgw frist comeing[root@node-1 web-pv0]# curl 10.68.55.99this is web-1