emptyDir

当pod分配到某个Node上时,emptyDir卷会被创建,并且在Pod运行期间,卷是一直存在的,当pod因为某些原因被删除,卷也会自动删除。

emptyDir 的一些用途:

  • 缓存空间,例如基于磁盘的归并排序。
  • 为耗时较长的计算任务提供检查点,以便任务能方便地从崩溃前状态恢复执行。
  • 在 Web 服务器容器服务数据时,保存内容管理器容器获取的文件。

emptyDir :以内存为介质

当pod删除后,物理机对应的挂载卷也会消失

kubectl run pod1 --image=nginx  --image-pull-policy=IfNotPresent=IfNotPresent --dry-run=client -o yaml > pod1.yaml  #生成pod1 yaml文件

####################################################
#empty配置示例
[root@cka-master volume]# vim pod1.yaml
apiVersion: v1
kind: Pod
metadata:
  creationTimestamp: null
  labels:
    run: pod1
  name: pod1
spec:
  volumes:   #定义卷
  - name: vname  #卷的名字
    emptyDir: {}  #卷的类型,不指定默认为emptyDir
  containers:
  - image: nginx
    imagePullPolicy: IfNotPresent
    name: pod1
    resources: {}
    volumeMounts:  #挂载卷
    - mountPath: /em-volume #挂载在容器中的路径
      name: vname  #挂载卷的名字
  dnsPolicy: ClusterFirst
  restartPolicy: Always
status: {}
####################################################
[root@cka-master volume]# kubectl apply  -f pod1.yaml 
pod/pod1 created  #创建pod

[root@cka-master volume]# kubectl exec pod1  -- ls /em-volume #查看挂载目录
[root@cka-master volume]# 


[root@cka-master volume]# kubectl  get pods -o wide #查看pod分配到了哪个节点
NAME   READY   STATUS    RESTARTS   AGE     IP              NODE        NOMINATED NODE   READINESS GATES
pod1   1/1     Running   0          9m59s   10.244.115.87   cka-node1   <none>           <none>


[root@cka-node1 ~]# docker inspect  6f  | grep -A 10 Mounts  #查看挂载信息
        "Mounts": [
            {
                "Type": "bind",
                "Source": "/var/lib/kubelet/pods/8309886f-2ac5-4aad-a411-9d21fc8a2441/volumes/kubernetes.io~empty-dir/vname",
                "Destination": "/em-volume",
                "Mode": "Z",
                "RW": true,
                "Propagation": "rprivate"
            },
            {
                "Type": "bind",


[root@cka-node1 ~]# ls /var/lib/kubelet/pods/8309886f-2ac5-4aad-a411-9d21fc8a2441/volumes/kubernetes.io~empty-dir/vname #查看卷,刚创建是卷是空的
[root@cka-node1 ~]# 


[root@cka-master volume]# kubectl exec pod1  -- touch /em-volume/test.txt  #创建text.txt
[root@cka-master volume]# kubectl exec pod1  -- ls /em-volume  #查看挂载目录,此时看到了上面创建的test.txt
test.txt

[root@cka-node1 ~]# ls /var/lib/kubelet/pods/8309886f-2ac5-4aad-a411-9d21fc8a2441/volumes/kubernetes.io~empty-dir/vname
test.txt #再次去对应的几点查看卷

[root@cka-master volume]# kubectl  delete  pod pod1  --force  #删除pod
#此时在去对应的节点查看卷,发现卷就自动删除了
[root@cka-node1 ~]# ls /var/lib/kubelet/pods/8309886f-2ac5-4aad-a411-9d21fc8a2441/volumes/kubernetes.io~empty-dir/vname
ls: cannot access /var/lib/kubelet/pods/8309886f-2ac5-4aad-a411-9d21fc8a2441/volumes/kubernetes.io~empty-dir/vname: No such file or directory


hostPath

hostPath 卷能将主机节点文件系统上的文件或目录挂载到你的 Pod 中。 虽然这不是大多数 Pod 需要的,但是它为一些应用程序提供了强大的逃生舱。

hostPath:以磁盘为介质,挂载到物理机上自己指定的磁盘上,如果指定挂载目录没有,自动创建

[root@cka-master volume]# kubectl  run pod2 --image=nginx --image-pull-policy=IfNotPresent --dry-run=client -o yaml  > pod2.yaml

[root@cka-master volume]# vim pod2.yaml 
####################################################
apiVersion: v1
kind: Pod
metadata:
  creationTimestamp: null
  labels:
    run: pod2
  name: pod2
spec:
  volumes:
  - name: hp-volume
    hostPath:
      path: /host-data
  containers:
  - image: nginx
    imagePullPolicy: IfNotPresent
    name: pod2
    resources: {}
    volumeMounts:
      - name: hp-volume
        mountPath: /hp
  dnsPolicy: ClusterFirst
  restartPolicy: Always
status: {}
####################################################
[root@cka-node1 ~]# docker inspect d7 | grep -A 10 Mounts 
        "Mounts": [
            {
                "Type": "bind",
                "Source": "/host-data", #物理机
                "Destination": "/hp", #容器内
                "Mode": "",
                "RW": true,
                "Propagation": "rprivate"
            },
            {
                "Type": "bind",
[root@cka-node1 ~]# ls /host-data/ 
[root@cka-node1 ~]# 

[root@cka-master volume]# kubectl  exec  pod2  -- ls /hp 
[root@cka-master volume]# kubectl  exec  pod2  -- touch /hp/test.txt
[root@cka-master volume]# kubectl  exec  pod2  -- ls /hp 
test.txt

[root@cka-node1 ~]# ls /host-data/ 
test.txt #此时可以看到前面创建的test.txt

[root@cka-master volume]# kubectl  delete  pod pod2 --force  #删除pod2

[root@cka-node1 ~]# ls /host-data/ 
test.txt #当pod2被删除是,卷不会删除

NFS

使用nfs卷可以将nfs(网络文件系统)挂载到Pod中,不同之前的emptyDir,pod删除后卷里的数据不会删除,nfs 卷的内容在删除 Pod 时会被保存,卷只是被卸载。 这意味着 nfs 卷可以被预先填充数据,并且这些数据可以在 Pod 之间共享。

配置一台nfs服务器

#所有节点安装 nfs-utils 

mkdir /nfstest ; echo nfs.txt > nfs.txt
[root@cka-nfs ~]# cat /etc/exports 
/nfstest *(rw,async,no_root_squash) 
#注: 这里一定要有no_root_squash,不压缩root的权限,具体含义看下面参数说明

参数说明

rw ro该目录分享的权限是可擦写 (read-write) 或只读 (read-only),但最终能不能读写,还是与文件系统的 rwx 及身份有关。
sync asyncsync 代表数据会同步写入到内存与硬盘中,async 则代表数据会先暂存于内存当中,而非直接写入硬盘!
no_root_squash root_squash客户端使用 NFS 文件系统的账号若为 root 时,系统该如何判断这个账号的身份?预设的情况下,客户端 root 的身份会由 root_squash 的设定压缩成 nfsnobody, 如此对服务器的系统会较有保障。但如果你想要开放客户端使用 root 身份来操作服务器的文件系统,那么这里就得要开 no_root_squash 才行!
all_squash不论登入 NFS 的使用者身份为何, 他的身份都会被压缩成为匿名用户,通常也就是 nobody(nfsnobody) 啦!
anonuid anongidanon 意指 anonymous (匿名者) 前面关于 *_squash 提到的匿名用户的 UID 设定值,通常为 nobody(nfsnobody),但是你可以自行设定这个 UID 的值!当然,这个 UID 必需要存在于你的 /etc/passwd 当中! anonuid 指的是 UID 而 anongid 则是群组的 GID 啰。
[root@cka-master volume]# kubectl  run pod3 --image=nginx --image-pull-policy=IfNotPresent --dry-run=client -o yaml > pod3.yaml 
[root@cka-master volume]# vim pod3.yaml 
####################################################
apiVersion: v1
kind: Pod
metadata:
  creationTimestamp: null
  labels:
    run: pod3
  name: pod3
spec:
  volumes:
  - name: nfs
    nfs:
      server: 192.168.4.100 
      path: /nfstest
  containers:
  - image: nginx
    imagePullPolicy: IfNotPresent
    name: pod3
    resources: {}
    volumeMounts:
    - name: nfs
      mountPath: /nfs
      #readOnly: true #只读方式挂载
  dnsPolicy: ClusterFirst
  restartPolicy: Always
status: {}
####################################################
[root@cka-master volume]# kubectl  apply  -f pod3.yaml  

pod/pod3 created
[root@cka-master volume]# kubectl  exec  -it pod3 -- sh -c ">nfs2.txt"  #创建nfs2.txt
[root@cka-master volume]# kubectl  exec  -it pod3 -- ls /nfs
nfs.txt  nfs2.txt

[root@cka-nfs ~]# 
[root@cka-nfs ~]# ls /nfstest 
nfs2.txt  nfs.txt  #查看nftest

持久卷(Persistent Volume)

一pv只能和一个pvc进行关联

volume.png

Persistent Volume

apiVersion: v1
kind: PersistentVolume
metadata:
  name: 1pv  #pv名字
spec:
  capacity:
    storage: 5Gi  #指定pv的容量,后端需要块储存才有效
  volumeMode: Filesystem
  accessModes:  #访问模式
    - ReadWriteOnce  #卷可以被一个节点以读写方式挂载
  persistentVolumeReclaimPolicy: Recycle  #回收策略
  storageClassName: slow
  nfs:  #后端储存类型
    path: /nfstest  #共享的目录
    server: 192.168.4.100  #后端服务器地址

访问模式

PersistentVolume 卷可以用资源提供者所支持的任何方式挂载到宿主系统上。 如下表所示,提供者(驱动)的能力不同,每个 PV 卷的访问模式都会设置为 对应卷所支持的模式值。 例如,NFS 可以支持多个读写客户,但是某个特定的 NFS PV 卷可能在服务器 上以只读的方式导出。每个 PV 卷都会获得自身的访问模式集合,描述的是 特定 PV 卷的能力。

访问模式有:

  • ReadWriteOnce -- 卷可以被一个节点以读写方式挂载;
  • ReadOnlyMany -- 卷可以被多个节点以只读方式挂载;
  • ReadWriteMany -- 卷可以被多个节点以读写方式挂载。

在命令行接口(CLI)中,访问模式也使用以下缩写形式:

  • RWO - ReadWriteOnce
  • ROX - ReadOnlyMany
  • RWX - ReadWriteMany

重要提醒! 每个卷只能同一时刻只能以一种访问模式挂载,即使该卷能够支持 多种访问模式。例如,一个 GCEPersistentDisk 卷可以被某节点以 ReadWriteOnce 模式挂载,或者被多个节点以 ReadOnlyMany 模式挂载,但不可以同时以两种模式 挂载。

回收策略

目前的回收策略有:

  • Retain -- 手动回收
  • Recycle -- 基本擦除 (rm -rf /thevolume/*)
  • Delete -- 诸如 AWS EBS、GCE PD、Azure Disk 或 OpenStack Cinder 卷这类关联存储资产也被删除

目前,仅 NFS 和 HostPath 支持回收(Recycle)。 AWS EBS、GCE PD、Azure Disk 和 Cinder 卷都支持删除(Delete)。

[root@cka-master volume]# kubectl  apply  -f 1pv.yaml  
persistentvolume/1pv created
[root@cka-master volume]# 
[root@cka-master volume]# kubectl  get pv 
NAME   CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM   STORAGECLASS   REASON   AGE
1pv    5Gi        RWO            Recycle          Available    

###PV STATUS 
阶段 
每个卷会处于以下阶段(Phase)之一:

Available(可用)-- 卷是一个空闲资源,尚未绑定到任何申领;
Bound(已绑定)-- 该卷已经绑定到某申领;
Released(已释放)-- 所绑定的申领已被删除,但是资源尚未被集群回收;
Failed(失败)-- 卷的自动回收操作失败。

PersistentVolumeClaims

每个PVC对象都有spec和status部分,分别对应申领的规约和状态。PersistentVolumeClaim对象的名称必须是合法的DNS子域名。

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mypvc  #pvc名字
spec:
  accessModes: #访问规则
    - ReadWriteOnce 
  volumeMode: Filesystem
  resources:
    requests:
      storage: 8Gi
  #storageClassName: slow
[root@cka-master volume]# kubectl  apply  -f pvc1.yaml  
persistentvolumeclaim/mypvc created
[root@cka-master volume]# kubectl  get pvc
NAME    STATUS    VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS   AGE
mypvc   Pending                                       #此时查看pvc是Pending状态,还没有关联。

pv和pvc关联取决于两个参数
1.capcity 
  pvc里的要求容量 <= pv --capcity
2.accessmode
  必须要相同

#修改storate 8G改成5G,再重新创建pvc,此时pvc就是Bound状态了
[root@cka-master volume]# kubectl  get pvc 
NAME    STATUS   VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS   AGE
mypvc   Bound    1pv      5Gi        RWO                           10s

创建pod

####################################################
apiVersion: v1
kind: Pod
metadata:
  creationTimestamp: null
  labels:
    run: pod4
  name: pod4
spec:
  volumes:
  - name: pvc
    persistentVolumeClaim:
      claimName: mypvc
  containers:
  - image: nginx
    imagePullPolicy: IfNotPresent
    name: pod4
    resources: {}
    volumeMounts:
    - name: pvc
      mountPath: /pvctest
  dnsPolicy: ClusterFirst
  restartPolicy: Always
status: {}
####################################################
[root@cka-master volume]# kubectl  apply  -f pod4.yaml 
pod/pod4 created
[root@cka-master volume]# kubectl  get pods 
NAME   READY   STATUS    RESTARTS   AGE
pod4   1/1     Running   0          4s
[root@cka-master volume]# kubectl  exec  pod4 -- ls /pvctest
nfs.txt
nfs2.txt 

[root@cka-master volume]# kubectl  get pv 
NAME   CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM   STORAGECLASS   REASON   AGE
1pv    5Gi        RWO            Recycle          Available                          169m

[root@cka-nfs ~]# ls /nfstest/ 
[root@cka-nfs ~]# 
#当pvc删除后会发现/nfstest下的数据都没了,这是因为PV的回收策略是Recycle,如果想pvc删除后数据保存可以修改回收策略为Retain

测试如下
[root@cka-master volume]# vim 1pv.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
  name: 1pv
spec:
  capacity:
    storage: 5Gi
  volumeMode: Filesystem
  accessModes:
    - ReadWriteOnce
  persistentVolumeReclaimPolicy: Retain
  #storageClassName: slow
  nfs:
    path: /nfstest
    server: 192.168.4.100
    
[root@cka-master volume]# kubectl  apply  -f 1pv.yaml 
persistentvolume/1pv created 
[root@cka-master volume]# kubectl  get pv 
NAME   CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM   STORAGECLASS   REASON   AGE
1pv    5Gi        RWO            Retain           Available                                   2s
[root@cka-master volume]# kubectl  apply  -f pvc1.yaml  
persistentvolumeclaim/mypvc created
[root@cka-master volume]# kubectl  get pvc mypvc  
NAME    STATUS   VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS   AGE
mypvc   Bound    1pv      5Gi        RWO                           5s
[root@cka-master volume]# kubectl  apply  -f pod4.yaml  
pod/pod4 created
[root@cka-master volume]# kubectl  exec pod4 --  touch /pvctest/{1..6}.txt
[root@cka-master volume]# kubectl exec  pod4  -- ls /pvctest/
1.txt
2.txt
3.txt
4.txt
5.txt
6.txt
#创建完成后此时删除pvc
[root@cka-master volume]# kubectl  delete  pod pod4  --force
[root@cka-master volume]# kubectl  delete  pvc mypvc
[root@cka-master volume]# kubectl  get pv 
NAME   CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS     CLAIM          STORAGECLASS   REASON   AGE
1pv    5Gi        RWO            Retain           Released   volume/mypvc                           6m27s
#此时的PV是Released状态,此时去创建pvc,pvc是关联不了的。
[root@cka-nfs nfstest]# ls  #此时数据保留了下来
1.txt  2.txt  3.txt  4.txt  5.txt  6.txt

动态卷供应

配置动态卷供应

上面配置持久性存储的时候,是要先创建pv然后才能创建pvc。如果不同的命名空间里同时要创建不同的pvc,那么就需要提前把pv创建好,这样才能为pvc提供存储。这种操作方式太过于麻烦,所有通过 storageClass(简称sc)来解决这个问题。

最终的效果是,管理员不需要提前创建pv,只要创建好 storageClass之后就不用管pv了,用户创建pvc的时候,storageClass 会自动创建出来一个pv 和这个 pvc 进行关联。

kubernetes 自带的分配器包 括:

kubernetes.io/aws-ebs

kubernetes.io/gce-pd

kubernetes.io/glusterfs

kubernetes.io/cinder

kubernetes.io/vsphere-volume

kubernetes.io/rbd

kubernetes.io/quobyte

kubernetes.io/azure-disk

kubernetes.io/azure-file

kubernetes.io/portworx-volume

kubernetes.io/scaleio

kubernetes.io/storageos

kubernetes.io/no-provisioner

注:在1.20里修改kube-apiserver.yaml

  • --feature-gates=RemoveSelfLink=false

利用nfs创建动态卷供应

前面已经用 nfs 配置过共享文件夹了,因为配置起来相对简单,所以这里以 nfs 作为后端存 储来配置动态卷供应。

步骤1.:自行在储存服务器上创建一个目录/vdisk,并共享这个目录。

[root@cka-nfs nfstest]# vim /etc/exports 
[root@cka-nfs nfstest]# cat /etc/exports 
/nfstest *(rw,async,no_root_squash)
/vdisk *(rw,async,no_root_squash)
[root@cka-nfs nfstest]# exportfs -arv
exporting *:/vdisk
exportfs: Failed to stat /vdisk: No such file or directory
exporting *:/nfstest

因为kubernetes里,nfs没有内置分配器,所以需要下载相关插件来创建nfs 外部分配器。

步骤2:安装git 客户端工具,并克隆项目进入到目录

[root@cka-master volume]# yum -y install git
[root@cka-master volume]# git clone https://github.com/kubernetes-incubator/external-storage.git

cd external-storage-master/nfs-client/deploy/ 
... ...
##我把需要的包都放在了服务器上,这里可以直接下载
wget http://1.116.86.11/k8s/nfs-client/external-storage-master.zip
wget http://1.116.86.11/k8s/nfs-client/nfs-client-provisioner.tar

docker load -i nfs-client-provisioner.tar  #所有节点导入

unzip external-storage-master.zip

cd /root/volume/external-storage-master/nfs-client/deploy

步骤3部署rpac

#因为我是在命名空间 volume 里的,所以需要把 rbac.yaml 里指定的命名空间更换为 volume,然后部署 rbac

sed -i 's/namespace: default/namespace: volume/g' rbac.yaml 
 
[root@cka-master deploy]# kubectl  apply -f rbac.yaml 
serviceaccount/nfs-client-provisioner created
clusterrole.rbac.authorization.k8s.io/nfs-client-provisioner-runner created
clusterrolebinding.rbac.authorization.k8s.io/run-nfs-client-provisioner created
role.rbac.authorization.k8s.io/leader-locking-nfs-client-provisioner created
rolebinding.rbac.authorization.k8s.io/leader-locking-nfs-client-provisioner created

部署nfs分配器

[root@cka-master deploy]# ls 
class.yaml  deployment-arm.yaml  deployment.yaml  objects  rbac.yaml  test-claim.yaml  test-pod.yaml
[root@cka-master deploy]# vim deployment.yaml 
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nfs-client-provisioner
  labels:
    app: nfs-client-provisioner
  # replace with namespace where provisioner is deployed
  namespace: volume  #命名空间之前给权限的
spec:
  replicas: 1
  strategy:
    type: Recreate
  selector:
    matchLabels:
      app: nfs-client-provisioner
  template:
    metadata:
      labels:
        app: nfs-client-provisioner
    spec:
      serviceAccountName: nfs-client-provisioner
      containers:
        - name: nfs-client-provisioner
          image: quay.io/external_storage/nfs-client-provisioner:latest
          volumeMounts:
            - name: nfs-client-root
              mountPath: /persistentvolumes
          env:
            - name: PROVISIONER_NAME
              value: fuseim.pri/ifs  #默认就行,改的话,class.yaml 也需要修改对应的
            - name: NFS_SERVER
              value: 192.168.4.100 #nfs服务地址
            - name: NFS_PATH
              value: /vdisk  #共享目录
      volumes:
        - name: nfs-client-root
          nfs:
            server: 192.168.4.100   #你nfs服务器地址
            path: /vdisk   #共享的目录
            
[root@cka-master deploy]# vim class.yaml           
kind: StorageClass
metadata:
  name: mysc
provisioner: fuseim.pri/ifs # or choose another name, must match deployment's env PROVISIONER_NAME'
parameters:
  archiveOnDelete: "false"


#验证此时直接创建pvc,可以直接创建了
[root@cka-master volume]# vim pvc2.yaml
##########################################
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mypvc
spec:
  accessModes:
    - ReadWriteOnce
  volumeMode: Filesystem
  resources:
    requests:
      storage: 100M
  storageClassName: mysc   #指定之前创建的sc             
##############################################

[root@cka-master volume]# kubectl  apply  -f  pvc2.yaml  
persistentvolumeclaim/mypvc created
[root@cka-master volume]# 
[root@cka-master volume]# kubectl  get pvc mypvc  
NAME    STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   AGE
mypvc   Bound    pvc-3705dde2-58ea-4180-b7ef-699911660adc   100M       RWO            mysc           5s

Q.E.D.