Volumes

Containers中的磁盘文件是短暂的,当容器崩溃时,kubelet会已最干净的状态去重启容器。另外当一个Pod运行多个container时,各个容器需要共享这些文件,Kubernetes的Volume可以解决两个问题
一些需要持久化的数据才会用到volume,或者一些需要共享数据的容器需要volumes
详情可参考: volumes 官网文档地址

EmptyDir

emptyDir官方文档
生命周期和Pod一致、如果Pod删除了,emptyDir的数据也会被删除
emptyDir 卷最初是空的,主要共享数据
在创建pod时、卷会自动创建在pod对应的node上,默认路径一般都在/var/lib/kubelet/pods/podid下 ,则容器内emptydir的大小应该也是受到/var大小的限制
EmptyDir能实现共享数据的前提:
必须在同一个node上、不管你是同Pod还是不同Pod

# 尝试找到empdir对应的宿主机目录
[root@k8s-master01 pods]# kubectl exec -it dp-cm-66c5664bbc-k7pmm -- sh
/ # cd /cache/
/cache # ls
whtest

[root@k8s-master01 pods]# find / -name whtest -type f
/var/lib/kubelet/pods/731600ab-a710-4dcb-9fdc-d90c287b03c5/volumes/kubernetes.io~empty-dir/cache-volume/whtest

# 这里是pod的id 不是容器的id
容器ID查询方法
kubectl describe pods/AA | grep "Container ID"
ctr -n k8s.io containers ls | grep "Container ID"
PodID查询方法
kubectl get pods/dp-cm-66c5664bbc-k7pmm -o jsonpath='{.metadata.uid}'
EmtyDir使用
为容器提供空目录
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: dp-cm
  name: dp-cm
spec:
  replicas: 1
  selector:
    matchLabels:
      app: dp-cm
  template:
    metadata:
      labels:
        app: dp-cm
    spec:
      containers:
      - image: registry.cn-beijing.aliyuncs.com/dotbalo/nginx:1.15.12-alpine
        name: nginx
        volumeMounts:
        - mountPath: /cache
          name: cache-volume
      volumes:
      - name: cache-volume
        emptyDir: {}


[root@k8s-master01 ~]# kubectl exec -it dp-cm-67c6d7fffc-fcj5m  -- sh
/ # cd /cache/
/cache # ls

多容器共享数据
# 一个Pod创建两个容器 测试数据共享
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: dp-cm
  name: dp-cm
spec:
  replicas: 1
  selector:
    matchLabels:
      app: dp-cm
  template:
    metadata:
      labels:
        app: dp-cm
    spec:
      containers:
      - image: registry.cn-beijing.aliyuncs.com/dotbalo/nginx:1.15.12-alpine
        name: nginx
        volumeMounts:
        - mountPath: /cache
          name: cache-volume
      - image: registry.cn-beijing.aliyuncs.com/dotbalo/nginx:1.15.12-alpine
        name: nginx2
        command: ['sleep','3600'] # 因为同pod共享网络名称空间,镜像都是nginx、都拉起会端口占用
        volumeMounts:
        - mountPath: /cache
          name: cache-volume
      volumes:
      - name: cache-volume
        emptyDir: {}



# 测试数据共享
[root@k8s-master01 pod]# kubectl exec -it dp-cm-84b8877cd7-7phtp -c nginx -- sh
/ # touch /cache/sharedir
/ # [root@k8s-master01 pod]# kubectl exec -it dp-cm-84b8877cd7-7phtp -c nginx2 -- ls /cache/
sharedir

生命周期验证
  • 如果容器被销毁、数据就没了
  • 使用emptydir共享的目录,生命周期和容器一致
  • 容器重启没事 ,只要容器id不变 基本上数据就不会丢
# 创建test文件
[root@k8s-master01 pod]# kubectl get pods -o wide
NAME                     READY   STATUS    RESTARTS   AGE   IP             NODE           NOMINATED NODE   READINE
dp-cm-6c669f8688-l4vb2   1/1     Running   0          7s    172.25.92.90   k8s-master02   <none>           <none>
[root@k8s-master01 pod]# kubectl exec -it dp-cm-6c669f8688-l4vb2 -- sh
/ # cd /mnt
/mnt # ls
/mnt # touch test

# 删除pod
[root@k8s-master01 pod]# kubectl delete deploy/dp-cm

# 重新创建查看是否还有test
[root@k8s-master01 pod]# kubectl create -f dp-cm.yaml
[root@k8s-master01 pod]# kubectl get pods
NAME                     READY   STATUS    RESTARTS   AGE
dp-cm-6c669f8688-s9ztg   1/1     Running   0          23s
[root@k8s-master01 pod]# kubectl exec -it dp-cm-6c669f8688-s9ztg -- sh
/ # cd /mnt
/mnt # ls
/mnt # 

Hostpath

hostpath使用
  • hostpath卷则是将主机节点的文件系统中的文件或目录挂载到集群中。当Pod删除时,hostpath卷不会被删除。因此,从这个特点来看,hostpath卷并不算是严格意义上的临时卷。
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: dp-cm
  name: dp-cm
spec:
  replicas: 1
  selector:
    matchLabels:
      app: dp-cm
  template:
    metadata:
      labels:
        app: dp-cm
    spec:
      containers:
      - image: registry.cn-beijing.aliyuncs.com/dotbalo/nginx:1.15.12-alpine
        name: nginx
        volumeMounts:
        - mountPath: /cache
          name: cache-volume
        - mountPath: /etc/timezone
          name: time-zone
      - image: registry.cn-beijing.aliyuncs.com/dotbalo/nginx:1.15.12-alpine
        name: nginx2
        command: ['sleep','3600']
        volumeMounts:
        - mountPath: /cache
          name: cache-volume
      volumes:
      - name: cache-volume
        emptyDir: {}
      - name: time-zone
        hostPath:
          path: /etc/timezone # # 宿主机上目录位置
          type: File # 此字段为可选



除了必需的 path 属性之外,
你可以选择性地为 hostPath 卷指定 type。
支持的 type 值如下:
空字符串(默认)用于向后兼容,这意味着在安装 hostPath 卷之前不会执行任何检查。
DirectoryOrCreate	如果在给定路径上什么都不存在,那么将根据需要创建空目录,权限设置为 0755,具有与 kubelet 相同的组和属主信息。
Directory	在给定路径上必须存在的目录。
FileOrCreate	如果在给定路径上什么都不存在,那么将在那里根据需要创建空文件,权限设置为 0644,具有与 kubelet 相同的组和所有权。
File	在给定路径上必须存在的文件。
Socket	在给定路径上必须存在的 UNIX 套接字。
CharDevice	在给定路径上必须存在的字符设备。
BlockDevice	在给定路径上必须存在的块设备。

验证:

[root@k8s-master01 pod]# kubectl exec -it dp-cm-7b4555ddf9-z7wd6 -c nginx -- cat /etc/timezone 
Asia/Shanghai

验证2:
如果这个pod挂了,跑到别的节点了 是否还能正常挂载呢?
# 假设pod目前再master03节点
1. 先创建一个其他节点没有的文件
[root@k8s-master01 pod]# cp /etc/timezone{,.bak}
[root@k8s-master01 pod]# vim /etc/timezone.bak 
[root@k8s-master01 pod]# cat /etc/timezone.bak
Asia/Shanghai
Asia/Anhui

spec:
      containers:
      - image: registry.cn-beijing.aliyuncs.com/dotbalo/nginx:1.15.12-alpine
        name: nginx
        volumeMounts:
        - mountPath: /etc/timezone
          name: time-zone
		...

        hostPath:
          path: /etc/timezone.bak
          type: FileOrCreate

# 现在pod在master03上
[root@k8s-master01 pod]# kubectl get pods -o wide
NAME                    READY   STATUS    RESTARTS   AGE   IP              NODE           NOMINATED NODE   READINESS GATES
dp-cm-7c99665f9-r8n8v   1/1     Running   0          33s   172.18.195.36   k8s-master03   <none>           <none>
[root@k8s-master01 pod]# kubectl exec -it dp-cm-7c99665f9-r8n8v -- cat /etc/timezone 
Asia/Shanghai
Asia/Anhui

# 指定node 将pod创建到master01上,但是master01节点没有zonetime.bak这个文件
[root@k8s-master01 pod]# kubectl get pods -o wide
NAME                    READY   STATUS    RESTARTS   AGE   IP               NODE           NOMINATED NODE   READINESS GATES
dp-cm-ccbcfd49c-zvn8k   1/1     Running   0          7s    172.25.244.211   k8s-master01   <none>           <none>
[root@k8s-master01 pod]# kubectl exec -it dp-cm-ccbcfd49c-zvn8k  -- cat /etc/timezone 
[root@k8s-master01 pod]# 

# 查看容器内没有信息,这就是hostpath的弊端,如果pod被重建到其他节点,对应的宿主机映射路径 node上又不存在,那容器中就无数据

NFS

  • 生产环境不推荐使用、nfs高可用没有保障
node01安装nfs
yum -y install nfs-utils
mkdir /data/nfs # 创建共享目录
[root@k8s-node01 nfs]# cat /etc/exports # 写入exports配置
/data/nfs 192.168.255.0/24(rw,sync,no_subtree_check,no_root_squash) 
exportfs -r
systemctl restart nfs

# master01 节点操作
mount -t nfs 192.168.255.141:/data/nfs  /mnt
cd /mnt
touch 123# 测试创建文件
# 其他节点安装nfs客户端
yum -y install nfs-utils
# 容器挂载nfs
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: dp-cm
  name: dp-cm
spec:
  replicas: 3
  selector:
    matchLabels:
      app: dp-cm
  template:
    metadata:
      labels:
        app: dp-cm
    spec:
      containers:
      - image: registry.cn-beijing.aliyuncs.com/dotbalo/nginx:1.15.12-alpine
        name: nginx
        volumeMounts:
        - mountPath: /opt
          name: nfs-volume
      nodeName: k8s-master01
      volumes:
      - name: nfs-volume
        nfs:
          server: 192.168.255.141
          path: /data/nfs/

验证

# 可以看到使用nfs也可以实现数据共享、虽然容器都不再同一个节点
# 跨node实现数据共享,这是emptydir不具备的
[root@k8s-master01 pod]# kubectl get pods -o wide
NAME                     READY   STATUS        RESTARTS   AGE   IP               NODE           NOMINATED NODE   READINESS GATES
dp-cm-7689bc6dd7-964xb   1/1     Running       0          16s   172.18.195.38    k8s-master03   <none>           <none>
dp-cm-7689bc6dd7-kqp77   1/1     Running       0          14s   172.25.244.215   k8s-master01   <none>           <none>
dp-cm-7689bc6dd7-s6s5c   1/1     Running       0          11s   172.17.125.27    k8s-node01     <none>           <none>
[root@k8s-master01 pod]# kubectl exec -it dp-cm-7689bc6dd7-964xb -- ls /opt
123
[root@k8s-master01 pod]# kubectl exec -it dp-cm-7689bc6dd7-kqp77 -- ls /opt
123
[root@k8s-master01 pod]# kubectl exec -it dp-cm-7689bc6dd7-s6s5c -- ls /opt
123
生命周期验证
  • 使用nfs挂载的卷,卷的生命周期不受容器所控制
#  
[root@k8s-master01 pod]# kubectl get pods -o wide
NAME                     READY   STATUS        RESTARTS   AGE   IP               NODE           NOMINATED NODE   READINESS GATES
dp-cm-7689bc6dd7-964xb   1/1     Running       0          16s   172.18.195.38    k8s-master03   <none>           <none>
dp-cm-7689bc6dd7-kqp77   1/1     Running       0          14s   172.25.244.215   k8s-master01   <none>           <none>
dp-cm-7689bc6dd7-s6s5c   1/1     Running       0          11s   172.17.125.27    k8s-node01     <none>           <none>
[root@k8s-master01 pod]# kubectl exec -it dp-cm-7689bc6dd7-964xb -- ls /opt
123
[root@k8s-master01 pod]# kubectl exec -it dp-cm-7689bc6dd7-kqp77 -- ls /opt
123
[root@k8s-master01 pod]# kubectl exec -it dp-cm-7689bc6dd7-s6s5c -- ls /opt
123

# 删除重新创建
kubectl delete deploy/dp-cm
kubectl create -f dp-cm.yaml

# 其挂载卷的生命周期也是不随pod所控制
[root@k8s-master01 pod]# kubectl get pods -o wide
NAME                     READY   STATUS    RESTARTS   AGE     IP               NODE           NOMINATED NODE   READINESS GATES
dp-cm-7689bc6dd7-98fkg   1/1     Running   0          6m14s   172.25.244.216   k8s-master01   <none>           <none>
dp-cm-7689bc6dd7-nh7nz   1/1     Running   0          6m14s   172.17.125.28    k8s-node01     <none>           <none>
dp-cm-7689bc6dd7-qk6q4   1/1     Running   0          6m14s   172.18.195.39    k8s-master03   <none>           <none>
[root@k8s-master01 pod]# kubectl exec -it dp-cm-7689bc6dd7-98fkg -- cat /opt/123
456
[root@k8s-master01 pod]# kubectl exec -it dp-cm-7689bc6dd7-nh7nz -- cat /opt/123
456
[root@k8s-master01 pod]# kubectl exec -it dp-cm-7689bc6dd7-qk6q4  -- cat /opt/123
456

持久化存储

PV/PVC

什么是pv和pvc?
PV(Persistent Volume)是持久化存储卷,是对底层的共享存储的一种抽象。它由kubernetes管理员进行创建和配置,与底层具体的共享存储技术有关,并通过插件完成与共享存储的对接。

PVC(Persistent Volume Claim)是持久卷声明的意思,是用户对于存储需求的一种声明。换句话说,PVC其实是用户向kubernetes系统发出的一种资源需求申请。

为什么要引入pv和pvc?
在Kubernetes中,存储系统有很多种,每种都有其特定的配置和操作方式。如果让每个用户都去直接操作底层存储,会大大增加用户的负担,并且容易造成错误。因此,Kubernetes引入了PV和PVC这两种资源对象,将底层的存储实现细节进行屏蔽,使得用户只需要关心存储需求即可。
引入PV和PVC是为了简化用户对Kubernetes存储资源的管理和使用,提高系统的可用性和可维护性

PV的回收策略

数据卷可以被 Retained(保留)、Recycled(回收)或 Deleted(删除)

  • Retained:保留,当删除pvc时,pv仍然存在,PV被视为已释放,管理员需要手动回收卷
  • Recycled: 如果下层的卷插件支持,回收策略 Recycle 会在卷上执行一些基本的擦除 (rm -rf /thevolume/*)操作,之后允许该卷用于新的 PVC 申领,目前只有nfs和HostPath支持该策略。
  • Delete: 如果Volume插件支持,删除pvc的同时也会删除pv,动态卷默认为delete,目前支持delete的插件有AWS、EBS、GCEPD、Azure Disk、Openstack Cinder等。
PV的访问策略

访问模式官网地址

  • ReadWriteOnce: 可以被单节点以读写模式挂载,缩写RWO
  • ReadOnlyMant: 可以被多个节点以只读模式挂载,缩写ROX
  • ReadWriteMany: 可以被多个节点以读写模式挂载,缩写RWX
PV配置例子-NFS/NAS
  1. 首先节点需要安装nfs,本案例是测试使用、生产环境别用nfs
  2. 具体nfs搭建可参考上方NFS的配置,这里不再演示
[root@k8s-master01 pod]# df -h /mnt
Filesystem                 Size  Used Avail Use% Mounted on
192.168.255.141:/data/nfs   17G  5.1G   12G  30% /mnt

apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv-nfs # pv名称
spec:
  capacity:
    storage: 5Gi # 容量配置
  volumeMode: Filesystem # 卷的模式、目前支持Filesystem文件系统和Block块,其中Block类型需要后端存储支持,默认为文件系统
  accessModes:
    - ReadWriteOnce # 访问模式 单用户读写
  persistentVolumeReclaimPolicy: Recycle # 回收策略
  storageClassName: nfs-slow # PV的类,名称任意
  nfs:
    path: /data/nfs # nfs上的共享目录
    server: 192.168.255.141 # nfs的ip地址
    
[root@k8s-master01 pod]# kubectl create -f nfs-pv.yaml 
persistentvolume/pv-nfs created
You have new mail in /var/spool/mail/root
[root@k8s-master01 pod]# kubectl get pv
NAME     CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM   STORAGECLASS   REASON   AGE
pv-nfs   5Gi        RWO            Recycle          Available           nfs-slow                4s

PV的状态
  • Available:可用,没有被PVC绑定的空闲资源
  • Bound:已绑定,已经被PVC绑定
  • Released: 已释放、PVC被删除,但是资源还未被重新使用
  • Failed: 失败,自动回收失败
PV配置例子-HostPath
  • 就后端实际配置不一致 前面都是一样的
[root@k8s-master01 pod]# cat hostpath-pv.yaml 
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv-hostpath
spec:
  capacity:
    storage: 5Gi
  volumeMode: Filesystem
  accessModes:
    - ReadWriteOnce
  persistentVolumeReclaimPolicy: Recycle
  storageClassName: hostpath-slow
  hostPath:
    path: /data

创建NFS类型的PVC
  • pvc要和pod在同一个命名空间
[root@k8s-master01 pod]# cat nfs-pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: nfs-pvc # pvc的名称 等待pod 挂载时调用
spec:
  accessModes:
    - ReadWriteOnce
  volumeMode: Filesystem
  resources:
    requests:
      storage: 1Gi
  storageClassName: nfs-slow # 这里类名要和刚才创建的pv类名一样

[root@k8s-master01 pod]# kubectl get pv
NAME          CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM             STORAGECLASS    REASON   AGE
pv-hostpath   5Gi        RWO            Recycle          Available                     hostpath-slow            8m57s
pv-nfs        5Gi        RWO            Recycle          Bound       default/nfs-pvc   nfs-slow                 18m

[root@k8s-master01 pod]# kubectl get pvc
NAME      STATUS   VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS   AGE
nfs-pvc   Bound    pv-nfs   5Gi        RWO            nfs-slow       12s
Pod引用PVC
[root@k8s-master01 pod]# cat dp-cm.yaml 
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: dp-cm
  name: dp-cm
spec:
  replicas: 1
  selector:
    matchLabels:
      app: dp-cm
  template:
    metadata:
      labels:
        app: dp-cm
    spec:
      containers:
      - image: registry.cn-beijing.aliyuncs.com/dotbalo/nginx:1.15.12-alpine
        name: nginx
        volumeMounts:
        - mountPath: /data # 挂载到容器的路径
          name: nfs-volume # 引用的卷名称
      volumes:
      - name: nfs-volume # volume名称
        persistentVolumeClaim:
          claimName: nfs-pvc  # 指定pvc的名称

# 容器内查看信息和nfs服务器上数据一致
[root@k8s-master01 pod]# kubectl exec -it dp-cm-6f86bf6959-fnqzf -- sh
/ # cat /data/pvc 
pvcfiletest

更加详细的文档可以参考:

Logo

K8S/Kubernetes社区为您提供最前沿的新闻资讯和知识内容

更多推荐