深入剖析Kubernetes学习笔记:StatefulSet(19)
一、如果你并不知道有哪些 Volume 类型可以用,要怎么办呢?
1、如果你并不知道有哪些 Volume 类型可以用,要怎么办呢?
1、一窍不通
2、暴露公司基础设施秘密的风险
比如,下面这个例子,就是一个声明了 Ceph RBD 类型 Volume 的 Pod:
apiVersion: v1 kind: Pod metadata: name: rbd spec: containers: - image: kubernetes/pause name: rbd-rw volumeMounts: - name: rbdpd mountPath: /mnt/rbd volumes: - name: rbdpd rbd: monitors: - '10.16.154.78:6789' - '10.16.154.82:6789' - '10.16.154.83:6789' pool: kube image: foo fsType: ext4 readOnly: true user: admin keyring: /etc/ceph/keyring imageformat: "2" imagefeatures: "layering"
这也是为什么,在后来的演化中,Kubernetes 项目引入了一组叫作 Persistent Volume Claim(PVC)和 Persistent Volume(PV)的 API 对象,大大降低了用户声明和使用持久化 Volume 的门槛。
二、有了 PVC 之后,一个开发人员想要使用一个 Volume,只需要简单的两步即可
1、第一步:定义一个 PVC,声明想要的 Volume 的属性:
kind: PersistentVolumeClaim apiVersion: v1 metadata: name: pv-claim spec: accessModes: - ReadWriteOnce resources: requests: storage: 1Gi
在这个 PVC 对象里,不需要任何关于 Volume 细节的字段,只有描述性的属性和定义。
2、第二步:在应用的 Pod 中,声明使用这个 PVC:
apiVersion: v1 kind: Pod metadata: name: pv-pod spec: containers: - name: pv-container image: nginx ports: - containerPort: 80 name: "http-server" volumeMounts: - mountPath: "/usr/share/nginx/html" name: pv-storage volumes: - name: pv-storage persistentVolumeClaim: claimName: pv-claim
3、这些符合条件的 Volume 又是从哪里来的呢?
答案是,它们来自于由运维人员维护的 PV(Persistent Volume)对象。接下来,我们一起看一个常见的 PV 对象的 YAML 文件:
kind: PersistentVolume apiVersion: v1 metadata: name: pv-volume labels: type: local spec: capacity: storage: 10Gi rbd: monitors: - '10.16.154.78:6789' - '10.16.154.82:6789' - '10.16.154.83:6789' pool: kube image: foo fsType: ext4 readOnly: true user: admin keyring: /etc/ceph/keyring imageformat: "2" imagefeatures: "layering"
4、“接口”和“实现
PVC 和 PV 的设计
避免“扯皮”
5、volumeClaimTemplates
而 PVC、PV 的设计,也使得 StatefulSet 对存储状态的管理成为了可能。我们还是以上一篇文章中用到的 StatefulSet 为例(你也可以借此再回顾一下《深入理解 StatefulSet(一):拓扑状态》中的相关内容):
apiVersion: apps/v1 kind: StatefulSet metadata: name: web spec: serviceName: "nginx" replicas: 2 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx:1.9.1 ports: - containerPort: 80 name: web volumeMounts: - name: www mountPath: /usr/share/nginx/html volumeClaimTemplates: - metadata: name: www spec: accessModes: - ReadWriteOnce resources: requests: storage: 1Gi
字段
PVC和POD编号一致
PVC 与 PV 的绑定
所以,我们在使用 kubectl create 创建了 StatefulSet 之后,就会看到 Kubernetes 集群里出现了两个 PVC:
$ kubectl create -f statefulset.yaml $ kubectl get pvc -l app=nginx NAME STATUS VOLUME CAPACITY ACCESSMODES AGE www-web-0 Bound pvc-15c268c7-b507-11e6-932f-42010a800002 1Gi RWO 48s www-web-1 Bound pvc-15c79307-b507-11e6-932f-42010a800002 1Gi RWO 48s
<PVC 名字 >-<StatefulSet 名字 >-< 编号 >
三、验证一下上述 Volume 的分配情况:
我们前面已经讲到过,这个 StatefulSet 创建出来的所有 Pod,都会声明使用编号的 PVC。比如,在名叫 web-0 的 Pod 的 volumes 字段,它会声明使用名叫 www-web-0 的 PVC,从而挂载到这个 PVC 所绑定的 PV。
所以,我们就可以使用如下所示的指令,在 Pod 的 Volume 目录里写入一个文件,来验证一下上述 Volume 的分配情况:
$ for i in 0 1; do kubectl exec web-$i -- sh -c 'echo hello $(hostname) > /usr/share/nginx/html/index.html'; done
如上所示,通过 kubectl exec 指令,我们在每个 Pod 的 Volume 目录里,写入了一个 index.html 文件。这个文件的内容,正是 Pod 的 hostname。比如,我们在 web-0 的 index.html 里写入的内容就是 "hello web-0"。
此时,如果你在这个 Pod 容器里访问“http://localhost”
,你实际访问到的就是 Pod 里 Nginx 服务器进程,而它会为你返回 /usr/share/nginx/html/index.html 里的内容。这个操作的执行方法如下所示:
如上所示,通过 kubectl exec 指令,我们在每个 Pod 的 Volume 目录里,写入了一个 index.html 文件。这个文件的内容,正是 Pod 的 hostname。比如,我们在 web-0 的 index.html 里写入的内容就是 "hello web-0"。
此时,如果你在这个 Pod 容器里访问“http://localhost”
,你实际访问到的就是 Pod 里 Nginx 服务器进程,而它会为你返回 /usr/share/nginx/html/index.html 里的内容。这个操作的执行方法如下所示:
$ for i in 0 1; do kubectl exec -it web-$i -- curl localhost; done hello web-0 hello web-1
现在,关键来了。
如果你使用 kubectl delete 命令删除这两个 Pod,这些 Volume 里的文件会不会丢失呢?
$ kubectl delete pod -l app=nginx pod "web-0" deleted pod "web-1" deleted
# 在被重新创建出来的 Pod 容器里访问 http://localhost $ kubectl exec -it web-0 -- curl localhost hello web-0
这是怎么做到的呢?
1、恢复这个 Pod 的过程
2、需要注意的是
3、StatefulSet 创建 Pod 的标准流程。
通过这种方式,Kubernetes 的 StatefulSet 就实现了对应用存储状态的管理。
详细梳理一下
1、首先
2、其次
3、最后
四、小结
1、StatefulSet 的设计思想
2、编号
实际上,在下一篇文章的“有状态应用”实践环节,以及后续的讲解中,你就会逐渐意识到,StatefulSet 可以说是 Kubernetes 中作业编排的“集大成者”。
因为,几乎每一种 Kubernetes 的编排功能,都可以在编写 StatefulSet 的 YAML 文件时被用到。