linux怎么查看本机内存大小
189
2022-10-28
kubernetes(十一) 存储& statefulset控制器
数据持久化
Volume
kubernetes中的volume提供了在容器中挂载外部存储的能力 pod需要设置卷来源(spec.volume)和挂载点(spec.containers.volumeMounts)两个信息来使用对应的Volume 官方文档: pod间数据的共享
$ vim pod_emptydir.yml apiVersion: v1 kind: Pod metadata: name: mypod spec: containers: - name: write image: centos command: ["bash","-c","for i in {1..100};do echo $i >> /data/hello;sleep 1;done"] volumeMounts: - name: data mountPath: /data - name: read image: centos command: ["bash","-c","tail -f /data/hello"] volumeMounts: - name: data mountPath: /data volumes: - name: data emptyDir: {} $ kubectl logs mypod -c read -f #指定容器读 $ kubectl exec -it mypod -c read -- sh #-c 进入指定的容器 $ kubectl get pod -o wide #查看调度节点 $ cd /var/lib/kubelet/pods/ #进入调度节点的kubelet目录 $ docker ps | grep mypod # 查看pod对应的数据目录 $ cd /var/lib/kubelet/pods/1e6cab01-c048-4bb2-ae47-fccf581741d4/volumes/kubernetes.io~empty-dir #就可以看到对应的卷数据
hostPath
挂载node文件系统上的文件或者目录到Pod中的容器
应用场景: pod中容器需要访问宿主机文件
$ vim vim pod_hostpath.yml apiVersion: v1 kind: Pod metadata: name: my-pod spec: containers: - name: busybox image: busybox args: - /bin/sh - -c - sleep 36000 volumeMounts: - name: data mountPath: /data volumes: - name: data hostPath: path: /tmp type: Directory $ kubectl apply -f pod_hostpath.yml $ kubectl exec my-pod -- ls /data
NFS共享存储的使用
环境准备 准备一台nfs服务器(192.168.56.18),然后与k8s集群都安装nfs-utils
$ vim /etc/exports /ifs/kubernetes *(rw,no_root_squash) $ systemctl restart nfs $ showmount -e
挂载nfs到k8s集群
$ mount -t nfs 192.168.56.18:/ifs/kubernetes /mnt
生成模板
$ kubectl create deploy web --image=nginx --dry-run -o yaml > deploy_nfs.yml $ vim deploy_nfs.yml apiVersion: apps/v1 kind: Deployment metadata: labels: app: web name: web spec: replicas: 1 selector: matchLabels: app: web strategy: {} template: metadata: labels: app: web spec: containers: - image: nginx name: nginx resources: {} volumeMounts: - name: data mountPath: /usr/share/nginx/html volumes: - name: data nfs: server: 192.168.56.18 path: /ifs/kubernetes $ kubectl apply -f deploy_nfs.yml $ kubectl get pod && kubectl exec -it web-xxxx bash root@web-587c9fb4bd-9r7r4:/# cd /usr/share/nginx/html root@web-587c9fb4bd-9r7r4:/usr/share/nginx/html# echo "aa" > index.html $ kubectl scale deploy web --replicas=3 #扩容 $ kubectl expose deploy web --port=80 --target-port=80 --type=NodePort
PV
pv的静态供给
kubernetes支持持久卷的存储插件: cd /ifs/kubernetes/ && mkdir pv01 pv02 pv03 # 这是在nfs服务器上执行(192.168.56.18) ##### 接下来在k8s master上操作 $ vim pv01.yml apiVersion: v1 kind: PersistentVolume metadata: name: pv01 spec: capacity: storage: 3Gi accessModes: - ReadWriteMany nfs: path: /ifs/kubernetes/pv01 server: 192.168.56.18 $ kubectl apply -f pv01.yml $ kubectl get pv #查看pv ####### pod使用pv $ vim pod_pv.yml apiVersion: v1 kind: Pod metadata: name: my-pod spec: containers: - name: my-pod image: nginx ports: - containerPort: 80 volumeMounts: - name: www mountPath: /usr/share/nginx/html/ volumes: - name: www persistentVolumeClaim: claimName: my-pvc --- apiVersion: v1 kind: PersistentVolumeClaim metadata: name: my-pvc spec: accessModes: - ReadWriteMany resources: requests: storage: 1Gi $ kubectl apply -f pod_pv.yml $ kubectl get pv,pvc #发现pv绑定到my-pv #### 数据测试 $ kubectl exec -it my-pod -- bash root@my-pod:/# cd /usr/share/nginx/html/ root@my-pod:/usr/share/nginx/html# echo "hello" > index.html ### nfs服务器查看数据 $ ls /ifs/kubernetes/pv01/ index.html
pv动态供给
pv动态供给NFS
由于K8S不支持NFS动态供给,还需要先安装上图中的nfs-client-provisioner插件:
# cd nfs-client # vi deployment.yaml # 修改里面NFS地址和共享目录为你的 # kubectl apply -f . # kubectl get pods
测试
$ vim pod_pvc01.yml apiVersion: v1 kind: Pod metadata: name: my-pod spec: containers: - name: nginx image: nginx:latest ports: - containerPort: 80 volumeMounts: - name: www mountPath: /usr/share/nginx/html volumes: - name: www persistentVolumeClaim: claimName: my-pvc --- apiVersion: v1 kind: PersistentVolumeClaim metadata: name: my-pvc spec: storageClassName: "managed-nfs-storage" accessModes: - ReadWriteMany resources: requests: storage: 1Gi
这次会自动创建5GPV并与PVC绑定。
kubectl get pv,pvc
测试方法同上,进入到容器中/usr/share/nginx/html(PV挂载目录)目录下创建一个文件测试。
再切换到NFS服务器,会发现下面目录,该目录是自动创建的PV挂载点。进入到目录会发现刚在容器创建的文件。
$ ls /ifs/kubernetes/default-my-pvc-pvc-ab48e34d-398d-4f31-b46b-93ff0853b29d
有状态应用部署
StatefulSet控制器概述
StatefulSet:
部署有状态应用 解决Pod独立生命周期,保持Pod启动顺序和唯一性
稳定,唯一的网络标识符,持久存储 有序,优雅的部署和扩展、删除和终止 有序,滚动更新
应用场景:数据库主从,消息中间件kafka集群,redis集群等
稳定的网络ID
说起StatefulSet稳定的网络标识符,不得不从Headless说起了
标准Service:
apiVersion: v1 kind: Service metadata: name: my-service spec: selector: app: nginx ports: - protocol: TCP port: 80 targetPort: 9376
无头Service(Headless Service)
apiVersion: v1 kind: Service metadata: name: my-service spec: clusterIP: None selector: app: nginx ports: - protocol: TCP port: 80 targetPort: 9376
标准Service与无头Service区别是clusterIP: None,
这表示创建Service不要为我(Headless Service)分配Cluster IP,因为我不需要。
为什么标准Service需要?
这就是无状态和有状态的控制器设计理念了,无状态的应用Pod是完全对等的,提供相同的服务,可以在飘移在任意节点,例如Web。而像一些分布式应用程序,例如zookeeper集群、etcd集群、mysql主从,每个实例都会维护着一种状态,每个实例都各自的数据,并且每个实例之间必须有固定的访问地址(组建集群),这就是有状态应用。所以有状态应用是不能像无状态应用那样,创建一个标准Service,然后访问ClusterIP负载均衡到一组Pod上。这也是为什么无头Service不需要ClusterIP的原因,它要的是能为每个Pod固定一个”身份“。
举例说明:
vim stateful_nginx.yml apiVersion: v1 kind: Service metadata: name: headless-svc spec: clusterIP: None selector: app: nginx ports: - protocol: TCP port: 80 targetPort: 80 --- apiVersion: apps/v1 kind: StatefulSet metadata: name: web spec: selector: matchLabels: app: nginx serviceName: "headless-svc" replicas: 3 template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx ports: - containerPort: 80 name: web
相比之前讲的yaml,这次多了一个serviceName: “nginx”字段,这就告诉StatefulSet控制器要使用nginx这个headless service来保证Pod的身份。
[root@centos7-node4 statefulset]# kubectl get pods NAME READY STATUS RESTARTS AGE nfs-client-provisioner-75f9fd7b57-67jtk 1/1 Running 0 121m web-0 1/1 Running 0 72s web-1 1/1 Running 0 55s web-2 0/1 ContainerCreating 0 45s
每个pod的名称就是statefulSet的序列号获取主机名称的
[root@centos7-node4 ~]# kubectl exec web-0 -- hostname web-0 [root@centos7-node4 ~]# kubectl exec web-1 -- hostname web-1
不过,相信你也已经注意到了,尽管 web-0.nginx 这条记录本身不会变,但它解析到的 Pod 的 IP 地址,并不是固定的。这就意味着,对于“有状态应用”实例的访问,你必须使用 DNS 记录或者 hostname 的方式,而绝不应该直接访问这些 Pod 的 IP 地址。
以下是Cluster Domain,Service name,StatefulSet名称以及它们如何影响StatefulSet的Pod的DNS名称的一些选择示例。
Cluster Domain | Service (ns/name) | StatefulSet (ns/name) | StatefulSet Domain | Pod DNS | Pod Hostname |
---|---|---|---|---|---|
cluster.local | default/nginx | default/web | nginx.default.svc.cluster.local | web-{0..N-1}.nginx.default.svc.cluster.local | web-{0..N-1} |
cluster.local | foo/nginx | foo/web | nginx.foo.svc.cluster.local | web-{0..N-1}.nginx.foo.svc.cluster.local | web-{0..N-1} |
kube.local | foo/nginx | foo/web | nginx.foo.svc.kube.local | web-{0..N-1}.nginx.foo.svc.kube.local | web-{0..N-1} |
稳定的存储
StatefulSet的存储卷使用VolumeClaimTemplate创建,称为卷申请模板,当StatefulSet使用VolumeClaimTemplate 创建一个PersistentVolume时,同样也会为每个Pod分配并创建一个编号的PVC。
实例:
$ vim stateful_pvc.yml apiVersion: apps/v1 kind: StatefulSet metadata: name: web spec: selector: matchLabels: app: nginx serviceName: "headless-svc" replicas: 3 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: "managed-nfs-storage" resources: requests: storage: 1Gi
查看占用存储卷的情况
kubectl get pv,pvc NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE persistentvolume/pvc-3c5fc93f-e90f-45d1-992f-6589c4901d1b 1Gi RWO Delete Bound default/ managed-nfs-storage 100s persistentvolume/pvc-60c524ff-bae9-4195-bf57-828e20e43ac8 1Gi RWO Delete Bound default/ managed-nfs-storage 119s persistentvolume/pvc-83963bb0-a0fb-481b-9a00-d9dc75f3e60b 1Gi RWO Delete Bound default/ managed-nfs-storage 86s NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE persistentvolumeclaim/ Bound pvc-60c524ff-bae9-4195-bf57-828e20e43ac8 1Gi RWO managed-nfs-storage 119s persistentvolumeclaim/ Bound pvc-3c5fc93f-e90f-45d1-992f-6589c4901d1b 1Gi RWO managed-nfs-storage 100s persistentvolumeclaim/ Bound pvc-83963bb0-a0fb-481b-9a00-d9dc75f3e60b 1Gi RWO managed-nfs-storage 86s
结果得知,StatefulSet为每个Pod分配专属的PVC及编号。每个PVC绑定对应的 PV,从而保证每一个 Pod 都拥有一个独立的 Volume。
在这种情况下,删除Pods或StatefulSet时,它所对应的PVC和PV不会被删除。所以,当这个Pod被重新创建出现之后,Kubernetes会为它找到同样编号的PVC,挂载这个PVC对应的Volume,从而获取到以前保存在 Volume 里的数据。
小结
StatefulSet与Deployment区别:有身份的!
有状态应用参考 https://github.com/operator-framework/awesome-operators
身份三要素:
域名 主机名 存储(PVC)
这里为你准备了一个etcd集群,来感受下有状态部署: https://github.com/lizhenliang/k8s-statefulset/tree/master/etcd
版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。
发表评论
暂时没有评论,来抢沙发吧~