HAOJX

kubernetes的本地持久化存储--Local Persistent Volume解析

字数统计: 1.2k阅读时长: 4 min
2019/01/10 Share

Local Persistent Volume是用来做什么的

可以实现pod在本地的持久化存储, 而不需要依赖远程存储服务来提供持久化 , 即使这个pod再次被调度的时候 , 也能被再次调度到local pv所在的node

出现原因

既然有了hostPath Volume这种方式 , 为什么还要 再搞一个local PV呢 , 这是因为hostPath Volume这种方式并不适合在线上环境使用 , 原因如下:

  • 如果使用hostPath Volume这种方法 , 还得选择节点来调度
  • 需要事先创建好目录 , 而且还得注意权限的配置, 比如root用户创建的目录 , 普通用户就用不了了
  • 不能指定大小 , 可能 会面临磁盘随时被写满的危险 , 而且没有I/O隔离机制
  • statefulset不能使用hostPath Volume , 写好的Helm不能兼容hostPath Volume

Local Persistent Volume使用的场景:

  • 分布式数据库存储MongoDB , Cassandra数据库等等, 分布式系统文件GlusterFS , Ceph等等
  • 需要在本地磁盘进行大量缓存数据的应用 , 或者是为了加速Pod读取数据

Local Persistent Volume需要注意的地方是什么?

  • 一旦节点宕机 , 在上面的数据就会丢失 , 这需要使用Local Persistent Volume的应用要有数据恢复和备份能力
  • Local Persistent Volume对应的存储介质, 一定是一块额外挂载在 宿主机的磁盘或者块设备(意思是它不应用是宿主机根目录所使用的主硬盘 , ) 一定要一个PV一个盘 , 而且要提前准备好

例子

先创建本地磁盘对应的pv

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
apiVersion: v1
kind: PersistentVolume
metadata:
name: example-pv
spec:
capacity:
storage: 5Gi
volumeMode: Filesystem
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Delete
storageClassName: local-storage
local:
path: /mnt/disks/vol1
nodeAffinity:
required:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/hostname
operator: In
values:
- node-1

其中:

  • local.path写对应的磁盘路径
  • 必须指定对应的node , 用.spec.nodeAffinity 来对应的node
  • .spec.volumeMode可以是FileSystem(Default)和Block
  • 确保先运行了StorageClass (即下面写的文件)

再写对于的StorageClass文件

1
2
3
4
5
6
kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
name: local-storage
provisioner: kubernetes.io/no-provisioner
volumeBindingMode: WaitForFirstConsumer

其中:

  • provisioner是kubernetes.io/no-provisioner , 这是因为local pv不支持Dynamic Provisioning, 所以它没有办法在创建出pvc的时候, 自动创建对应pv
  • volumeBindingMode是WaitForFirstConsumer , WaitForFirstConsumer即延迟绑定 , 这样可以既可以保证推迟到调度的时候 , 再进行绑定 , 又可以保证调度到指定的pod上 , 其实WaitForFirstConsumer又2种: 一种是WaitForFirstConsumer , 一直是Immediate , 这里必须用延迟绑定模式

再创建一个pvc

1
2
3
4
5
6
7
8
9
10
11
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: example-local-claim
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 5Gi
storageClassName: local-storage

这里需要注意的地方就是storageClassName要写出我们之前自己创建的storageClassName的名字:local-storage

之后应用这个文件 , 使用命令kubectl get pvc可以看到他的状态是Pending , 这个时候虽然有了匹配的pv , 但是也不会进行绑定 , 依然在等待

之后我们写个pod应用这个pvc

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
kind: Pod
apiVersion: v1
metadata:
name: example-pv-pod
spec:
volumes:
- name: example-pv-storage
persistentVolumeClaim:
claimName: example-local-claim
containers:
- name: example-pv-container
image: nginx
ports:
- containerPort: 80
name: "http-server"
volumeMounts:
- mountPath: "/usr/share/nginx/html"
name: example-pv-storage

这里写的.spec.volumes 里的pvc , 要指定成刚刚我们写好的那个pvc

这样就部署好了一个local pv在pod上 , 这样即可pod没有了 , 再次再重新在这个node上创建, 写入的文件也能持久化的存储在特定位置

如何删除这个pv

一定要按照流程来 , 要不然会删除失败

  1. 删除使用这个pv的pod
  2. 从node上移除这个磁盘(按照一个pv一块盘)
  3. 删除pvc
  4. 删除pv

local volume static provisioner

如果这个pod不用这个pv了 还得删除, 挺麻烦的 , 官方给出一个static provisioner来管理这些pv

比如我们所有的磁盘都挂载到/mnt/disks目录下

那当static provisioner启动后 , 会通过 DaemonSet 来自动检测每个宿主机上的/mnt/disks目录 . 之后调用kubernetes API , 来为这些目录的每一个挂载 ,根据配置文件里的storageClassName, path, nodeAffinity, and capacity创建一个对应的pv对象来 , 至于说这个static provisioner的各种定义, 比如StorageClass名字, 挂载位置等等 , 都可以通过配置文件指定 , 而且当Pod结束并删除了使用local volume的PVC,它将自动清理该local mount上的所有文件, 然后删除对应的PersistentVolume object

具体的地址:

CATALOG
  1. 1. Local Persistent Volume是用来做什么的
  2. 2. 出现原因
  3. 3. Local Persistent Volume使用的场景:
  4. 4. Local Persistent Volume需要注意的地方是什么?
  5. 5. 例子
  6. 6. 如何删除这个pv
  7. 7. local volume static provisioner