k8s的pv和pvc概念
存储卷
同一个pod内的所有容器共享存储 网络 用户等空间 pod内的容器都是以pause镜像为基础镜像来运行的
k8s.gcr.io/pause 3.1 da86e6ba6ca1 17 mon 742 kB
emptyDir
临时存储目录 pod删除 存储卷也随即会被删除
hostPath 主机目录
pod所在主机上的目录
搭建NFS网络存储
nfs搭建 yum install nfs-utils mkdir -pv /data/volumes vi /etc/exports /data/volumes 192.168.11.0/16(rw,no_root_squash) systemctl start nfs 1.确保k8s集群中的所有节点都能驱动nfs yum install nfs-utils 2.[root@node2 ~]# mount -t nfs 192.168.11.157:/data/volumnes/ /mnt mount.nfs: access denied by server while mounting 192.168.11.157:/data/volumnes/ 3.在nfs服务器查看/var/log/messages查看 volumnes单词拼写错误 [root@node2 ~]# mount -t nfs 192.168.11.157:/data/volumes /mnt [root@localhost ~]# vi /etc/exports /data/volumes/ 192.168.11.0/16(insecure,rw,async,no_root_squash) [root@localhost ~]# exportfs -r exportfs: Invalid prefix `24*' for 192.168.11.0/24* [root@localhost ~]# showmount -e Export list for localhost.localdomain: /data/volumes 192.168.11.0/16
apiVersion: v1 kind: Pod metadata: name: pod-vol-hostpath namespace: default spec: containers: - name: myapp image: ikubernetes/myapp:v1 volumeMounts: - name: html mountPath: /usr/share/nginx/html/ volumes: - name: html hostPath: path: /data/pod/volume1 type: DirectoryOrCreate
apiVersion: v1 kind: Pod metadata: name: pod-vol-nfs namespace: default spec: containers: - name: myapp image: ikubernetes/myapp:v1 volumeMounts: - name: html mountPath: /usr/share/nginx/html/ volumes: - name: html nfs: path: /data/volumes server: 192.168.11.157
nfs远程文件存储并没有一个“存储设备”需要挂载在宿主机上 所以不需要attach阶段
直接将远端 NFS 服务器的目录(比如:“/”目录)挂载到Volume的宿主机目录上即可
mount -t nfs <NFS服务器地址>:/ /var/lib/kubelet/pods/<Pod的ID>/volumes/kubernetes.io~<Volume类型>/<Volume名字>
通过挂载操作,Volume的宿主机目录就成为了一个远程NFS目录的挂载点,后面你在这个目录里写入的所有文件,都会被保存在远程NFS服务器
所以,我们也就完成了对这个Volume宿主机目录的“持久化”
pv和pvc的使用
存储工程师把分布式存储系统上的总空间划分成一个一个小的存储块
k8s管理员根据存储块创建与之一一对应的pv资源
pv属于集群级别资源 不属于任何名称空间 定义的时候不能指定名称空间
用户在创建pod的时候同时创建与pv一一对应的pvc资源
创建Pod的时候,系统里并没有合适的PV跟它定义的PVC绑定 也就是说此时容器想要使用的Volume不存在.这时候Pod的启动就会报错
[root@localhost volumes]# mkdir v{1,2,3,4,5} [root@localhost volumes]# ls index.html v1 v2 v3 v4 v5 [root@localhost volumes]# vi /etc/exports /data/volumes/v1 192.168.11.0/16(insecure,rw,async,no_root_squash) /data/volumes/v2 192.168.11.0/16(insecure,rw,async,no_root_squash) /data/volumes/v3 192.168.11.0/16(insecure,rw,async,no_root_squash) /data/volumes/v4 192.168.11.0/16(insecure,rw,async,no_root_squash) /data/volumes/v5 192.168.11.0/16(insecure,rw,async,no_root_squash) [root@localhost volumes]# exportfs -r [root@localhost volumes]# showmount -e Export list for localhost.localdomain: /data/volumes/v5 192.168.11.0/16 /data/volumes/v4 192.168.11.0/16 /data/volumes/v3 192.168.11.0/16 /data/volumes/v2 192.168.11.0/16 /data/volumes/v1 192.168.11.0/16
apiVersion: v1 kind: PersistentVolume metadata: name: pv001 labels: name: pv001 spec: nfs: path: /data/volumes/v1 server: 192.168.11.158 accessModes: ["ReadWriteMany","ReadWriteOnce"] capacity: storage: 2Gi --- apiVersion: v1 kind: PersistentVolume metadata: name: pv002 labels: name: pv002 spec: nfs: path: /data/volumes/v2 server: 192.168.11.158 accessModes: ["ReadWriteMany","ReadWriteOnce"] capacity: storage: 5Gi --- apiVersion: v1 kind: PersistentVolume metadata: name: pv003 labels: name: pv003 spec: nfs: path: /data/volumes/v3 server: 192.168.11.158 accessModes: ["ReadWriteMany","ReadWriteOnce"] capacity: storage: 2Gi --- apiVersion: v1 kind: PersistentVolume metadata: name: pv004 labels: name: pv004 spec: nfs: path: /data/volumes/v4 server: 192.168.11.158 accessModes: ["ReadWriteMany","ReadWriteOnce"] capacity: storage: 2Gi --- apiVersion: v1 kind: PersistentVolume metadata: name: pv005 labels: name: pv005 spec: nfs: path: /data/volumes/v5 server: 192.168.11.158 accessModes: ["ReadWriteMany","ReadWriteOnce"] capacity: storage: 2Gi
apiVersion: v1 kind: PersistentVolumeClaim metadata: name: mypvc namespace: default spec: accessModes: ["ReadWriteMany"] resources: requests: storage: 4Gi --- 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
[root@k8s-master ~]# kubectl get pv NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE pv001 2Gi RWO,RWX Retain Available 8m pv002 5Gi RWO,RWX Retain Bound default/mypvc 8m pv003 2Gi RWO,RWX Retain Available 8m pv004 2Gi RWO,RWX Retain Available 8m pv005 2Gi RWO,RWX Retain Available 8m [root@k8s-master ~]# kubectl get pvc NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE mypvc Bound pv002 5Gi RWO,RWX 8m [root@k8s-master ~]# kubectl get pods NAME READY STATUS RESTARTS AGE myapp-deploy-67f6f6b4dc-2986w 1/1 Running 0 4h myapp-deploy-67f6f6b4dc-czvq4 1/1 Running 0 4h myapp-deploy-67f6f6b4dc-tpggj 1/1 Running 0 10d pod-vol-pvc 1/1 Running 0 9m tomcat-deploy-588c79d48d-mdgml 1/1 Running 0 10d tomcat-deploy-588c79d48d-mvttj 1/1 Running 0 4h tomcat-deploy-588c79d48d-w2mxb 1/1 Running 0 10d 在创建pvc的时候如果后端没有合适的pv 那么挂载此pvc的pod将会一致处于等待状态直到pvc匹配到一个符合条件的pv
pv和pvc的机制
pv和pvc绑定要求
1.PV和PVC的spec字段.比如PV的存储(storage)大小
2.PV和PVC的storageClassName字段必须一样
3. PV描述的是持久化存储卷 这个API对象主要定义的是一个持久化存储在宿主机上的目录,如一个NFS的挂载目录
PVC可以理解为持久化存储的 它提供了对某种持久化存储的描述,但不提供具体的实现
4. 持久化存储的实现部分则由PV负责完成
5.PV与PVC进行绑定,其实就是将这个PV对象的名字,填在了PVC对象的spec.volumeName字段上
当PV和PVC成功绑定后 Pod就能像使用hostPath等常规类型的Volume一样 在YAML文件中使用PVC
pv对象转换成持久化volume的原理
所谓容器的Volume,其实就是将一个宿主机上的目录跟一个容器里的目录绑定挂载在了一起
持久化宿主机目录
远程存储服务,比如:远程文件存储(比如,NFS、GlusterFS),远程块存储(比如,公有云提供的远程磁盘)
“持久化”宿主机目录的过程,我们可以形象地称为“两阶段处理”
先把远程存储设备附加到指定节点上 然后在节点上格式化存储设备再挂载到节点上的具体目录下 这样才能通过节点目录访问远程存储设备
Attach阶段
为虚拟机挂载远程磁盘的操作
当一个Pod调度到一个节点上之后,kubelet就要负责为这个Pod创建它的 Volume 目录.默认情况下,kubelet为Volume创建的目录是一个宿主机上的路径如
/var/lib/kubelet/pods/volumes/kubernetes.io~/ 这个目录是宿主机后面用来和远程存储服务mount的关联目录
Kubernetes提供的可用参数是nodeName,即宿主机的名字
Mount阶段
将磁盘设备格式化并挂载到Volume宿主机目录的操作
把格式化的磁盘mount到/var/lib/kubelet/pods/volumes/kubernetes.io~/
Kubernetes提供的可用参数是dir 即Volume的宿主机目录
经过了“两阶段处理” 我们就得到了一个“持久化”的 Volume 宿主机目录 但是还没有关联到docker容器
接下来 kubelet 只要把这个 Volume目录通过 CRI 里的 Mounts 参数,传递给 Docker 然后就可以为 Pod 里的容器挂载这个“持久化”的 Volume
docker run -v /var/lib/kubelet/pods/<Pod的ID>/volumes/kubernetes.io~<Volume类型>/<Volume名字>:/<容器内的目标目录> 我的镜像
上面是Kubernetes 处理 PV 的具体原理
StorageClass自动创建pv
Kubernetes只会将StorageClass相同的PVC和PV绑定起来
自动创建PV的机制Dynamic Provisioning
人工管理PV的方式就叫作Static Provisioning
StorageClass对象就是创建PV的模板
定义StorageClass一般包含Name,后端使用存储插件类型,存储插件需要使用到的参数等信息 定义好之后相当于定义了一块巨大的存储磁盘
当pvc中定义的storageClassName和StorageClass的Name相同的时候那么StorageClass会自动从巨大的存储磁盘创建一个指定storage大小的pv,创建的pv和pvc进行绑定
StorageClass对象会定义如下两个部分内容
第一 PV的属性. 比如,存储类型
第二 创建这种PV需要用到的存储插件. 比如Ceph等等
k8s根据用户提交的PVC中指定的storageClassName的属性值找到对应的StorageClass.然后调用该StorageClass声明的存储插件创建出需要的PV
有了Dynamic Provisioning机制,运维人员只需要在Kubernetes集群里创建出数量有限的StorageClass对象就可以了
当开发人员提交了包含StorageClass字段的PVC之后,Kubernetes就会根据这个StorageClass创建出对应的PV
在没有StorageClass的情况下运维人员对开发人员定义的每一个pvc都要手动创建一个对应的pv与其进行绑定 这样就会大大的增加创建pv的工作量
本文来自博客园,作者:不懂123,转载请注明原文链接:https://www.cnblogs.com/yxh168/p/11031003.html