k8s之存储卷及pvc

一、概述

因为pod是有生命周期的,pod一重启,里面的数据就没了,所以我们需要数据持久化存储,在k8s中,存储卷不属于容器,而是属于pod,也就是说同一个pod中的容器可以共享一个存储卷,存储卷可以是宿主机上的目录,也可以是挂载在宿主机上的外部设备。

1.1、存储卷类型:
  • emptyDIR存储卷:pod一重启,存储卷也删除,这叫emptyDir存储卷,一般用于当做临时空间或缓存关系;

  • hostPath存储卷:宿主机上目录作为存储卷,这种也不是真正意义实现了数据持久性;

  • SAN(iscsi)或NAS(nfs、cifs):网络存储设备;

  • 分布式存储:ceph,glusterfs,cephfs,rbd;

  • 云存储:亚马逊的EBS,Azure Disk,阿里云,关键数据一定要有异地备份;

emptyDIR存储卷:
vim podtest/pod-vol-demo.yaml
apiVersion: v1
kind: Pod
metadata:
  name: pod-demo
  namespace: default
  labels:
    app: myapp
    tier: frontend
spec:
  containers:
  - name: myapp
    image: ikubernetes/myapp:v2
    imagePullPolicy: IfNotPresent
    ports:
    - name: http
      containerPort: 80
    volumeMounts:
    - name: html
      mountPath: /usr/share/nginx/html
  - name: busybox
    image: busybox:latest
    imagePullPolicy: IfNotPresent
    volumeMounts:
    - name: html
      mountPath: /data/
    command: ["/bin/sh"]
    args: ["-c","while true;do echo $(date) >> /data/index.html; sleep 10;done"]
  volumes:
  - name: html
    emptyDir: {}


volumeMounts:把哪个存储卷挂到pod中的哪个目录下;
emptyDir:不设置意味着对这个参数下的两个选项不做限制;
hostPath:使用宿主机上目录作为存储卷
kubectl explain pods.spec.volumes.hostPath.type
DirectoryOrCreate:要挂载的路径是一个目录,不存在就创建目录;
Directory:宿主机上必须实现存在目录,如果不存在就报错;
FileOrCreate:表示挂载的是文件,如果不存在就创建;
File:表示要挂载的文件必须事先存在,否则就报错.
 
cat pod-hostpath-vol.yaml
apiVersion: v1
kind: Pod
metadata:
  name: pod-vol-hostpath
  namespace: default
spec:
  containers:
  - name: myapp
    image: ikubernetes/myapp:v2
    volumeMounts:
    - name: html
      mountPath: /usr/share/nginx/html/
  volumes:
  - name: html
    hostPath:
      path: /data/pod/volume1
      type: DirectoryOrCreate
 
hostPath:宿主机上的目录;
volumes的名字可以随便取,这是存储卷的名字,但是上面的volumeMounts指定时,
name必须和存储卷的名字一致,这样两者才建立了联系;
nfs做共享存储
这里为了方便,把master节点当做nfs存储,三个节点均执行:

yum -y install nfs-utils  # 然后在master上启动nfs
mkdir /data/volumes
cat /etc/exports
/data/volumes 10.0.0.0/16(rw,no_root_squash)
systemctl start nfs

在node1和node2上试挂载
mount -t nfs k8s-master:/data/volumes /mnt
cat pod-vol-nfs.yaml
apiVersion: v1
kind: Pod
metadata:
  name: pod-vol-nfs
  namespace: default
spec:
  containers:
  - name: myapp
    image: ikubernetes/myapp:v2
    volumeMounts:
    - name: html
      mountPath: /usr/share/nginx/html/
  volumes:
  - name: html
    nfs:
      path: /data/volumes
      server: k8s-master
 
kubectl apply -f pod-vol-nfs.yaml
此时不管pod被建立在哪个节点上,对应节点上是不存放数据的,数据都在nfs主机上
pvc和pv

用户只需要挂载pvc到容器中而不需要关注存储卷采用何种技术实现。pvc和pv的关系与pod和node关系类似,前者消耗后者的资源,pvc可以向pv申请指定大小的存储资源并设置访问模式。

mark

在定义pod时,我们只需要说明我们要一个多大的存储卷就行了,pvc存储卷必须与当前namespace的pvc建立直接绑定关系,pvc必须与pv建立绑定关系,而pv是真正的某个存储设备上的空间.

一个pvc和pv是一一对应关系,一旦一个pv被一个pvc绑定了,那么这个pv就不能被其他pvc绑定了,一个pvc是可以被多个pod所访问的,pvc在名称空间中,pv是集群级别的

mark

将master作为存储节点,创建挂载目录

cd /data/volumes && mkdir v{1,2,3,4,5}
cat  /etc/exports
/data/volumes/v1 10.0.0.0/16(rw,no_root_squash)
/data/volumes/v2 10.0.0.0/16(rw,no_root_squash)
/data/volumes/v3 10.0.0.0/16(rw,no_root_squash)
exportfs -arv
showmount -e

kubectl explain pv.spec.nfs
accessModes模式有:
ReadWriteOnce:单路读写,可以简写为RWO;
ReadOnlyMany:多路只读,可以简写为ROX;
ReadWriteMany:多路读写,可以简写为RWX
 
# 先将存储设备定义为pv
cat pv-demo.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv001 # 定义pv时不用加名称空间,因为pv是集群级别
  labels:
    name: pv001
spec:
  nfs:
    path: /data/volumes/v1
    server: k8s-master
  accessModes: ["ReadWriteMany","ReadWriteOnce"]
  capacity: # 分配磁盘空间大小
    storage: 3Gi
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv002
  labels:
    name: pv002
spec:
  nfs:
    path: /data/volumes/v2
    server: k8s-master
  accessModes: ["ReadWriteOnce"]
  capacity:
    storage: 5Gi
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv003
  labels:
    name: pv003
spec:
  nfs:
    path: /data/volumes/v3
    server: k8s-master
  accessModes: ["ReadWriteMany","ReadWriteOnce"]
  capacity:
    storage: 8Gi
 
kubectl apply -f pv-demo.yaml

kubectl get pv
NAME      CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS  
pv001     3Gi        RWO,RWX        Retain           Available
pv002     5Gi        RWO            Retain           Available
pv003     8Gi        RWO,RWX        Retain           Available

回收策略:

如果某个pvc在pv里面存数据了,后来pvc删了,那么pv里面的数据怎么处理?

  • reclaim_policy:即pvc删了,但pv里面的数据不删除,还保留着;
  • recycle:即pvc删了,那么就把pv里面的数据也删了;
  • delete:即pvc删了,那么就把pv也删了;
# 创建pvc的清单文件
kubectl explain pods.spec.volumes.persistentVolumeClaim
cat pod-vol-pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim # 简称pvc
metadata:
  name: mypvc
  namespace: default # pvc和pod在同一个名称空间
spec:
  accessModes: ["ReadWriteMany"] # 一定是pv策略的子集
  resources:
    requests:
      storage: 7Gi # 申请一个大小至少为7G的pv
---
apiVersion: v1
kind: Pod
metadata:
  name: pod-vol-pvc
  namespace: default
spec:
  containers:
  - name: myapp
    image: ikubernetes/myapp:v1
    volumeMounts:
    - name: html # 使用的存储卷的名字
      mountPath: /usr/share/nginx/html/ #挂载路径
  volumes:
  - name: html
    persistentVolumeClaim:
      claimName: mypvc # 表示要使用哪个pvc

所以pod的存储卷类型如果是pvc,则:pod指定的pvc需要先匹配一个pv,才能被pod所挂载,在k8s 1.10之后,不能手工从底层删除pv。


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!