赞
踩
一般来说,容器一旦被删除后,容器运行时内部产生的所有文件数据也会被清理掉,因此,Docker提供了 Volume 这种方式来将数据持久化存储。
可以说,Volume 是Pod与外部存储设备进行数据传递的通道,也是Pod内部容器间、Pod与Pod间、Pod与外部环境进行数据共享的方式。
实际上,这个 Volume 也只是宿主机上本地磁盘中的一个目录,也就是说,volume方式是将容器里面的数据都保存到宿主机上。除此之外,还能保存到外部存储上。
在k8s中,支持多种类型的Volume:本地存储(emptyDir / hostPath)、外部存储(如NFS)。
若pod使用了emptyDir类型的volume,则在创建pod时,emptyDir volume随着pod也会一同被创建出来。emptyDir volume 会在pod所在的node节点上生成一个空目录,而这个空目录的默认路径是在/var/lib/kubelet/pods/下。
emptyDir 类型相当于执行【docker run -v /CONTAINER/DIR】。
emptyDir Volume与Pod生命周期一致,只要Pod一直运行,该Volume就一直存在,而当Pod被删除时,该Volume也同时会删除,即Node上对应目录也会被删掉。
一个Volume可被Pod中的所有容器共享,且可被挂载到容器的指定路径下。
示例:
- 说明:创建一个Pod,Pod有两个容器,它们共享一个Volume,busybox容器负责往 Volume 中写数据,myapp容器则是从 Volume 读取数据
-
- apiVersion: v1
- kind: Pod
- metadata:
- name: pod-demo
- spec:
- volumes: # 定义emptyDir类型的Volume
- - name: myweb
- emptyDir: {}
- containers:
- - name: myapp
- image: ikubernetes/myapp:v1
- volumeMounts:
- - name: myweb
- mountPath: /usr/share/nginx/html/
- - name: busybox
- image: busybox:latest
- volumeMounts: # 将名为myweb的volume挂载到容器里的/web目录下
- - name: myweb
- mountPath: /web
- command: [ "/bin/sh", "-c", "while true; do echo $(date) >> /web/index.html; done" ]
查看volume信息:
- $ docker inspect 020799d427ae -f "{{.Mounts}}"
- "Mounts": [
- {
- "Type": "bind",
- "Source": "/var/lib/kubelet/pods/bb66b0cd-979d-4356-92a9-492d420fc613/volumes/kubernetes.io~empty-dir/html",
- "Destination": "/usr/share/nginx/html",
- "Mode": "",
- "RW": true,
- "Propagation": "rprivate"
- },
尝试将pod删除,node上的volume目录也会被删除:
- $ kubectl delete pod pod-demo
- $ ls /var/lib/kubelet/pods/bb66b0cd-979d-4356-92a9-492d420fc613
该类型是将Node上指定的文件或目录挂载到Pod中。当Pod被删除时,Node上对应的该Volume的文件或目录不会被删除,会保留下来,从这点来看,hostPath的持久性比emptyDir强。不过一旦node节点崩溃了,hostPath也就没法访问了。
hostPath 类型相当于执行【docker run -v /HOST/DIR:/CONTAINER/DIR】。
- apiVersion: v1
- kind: Pod
- metadata:
- name: pod-demo2
- spec:
- volumes:
- - name: myweb
- hostPath:
- path: /data/www/ # 指定node上的目录
- type: Directory
- containers:
- - name: myapp
- image: ikubernetes/myapp:v1
- volumeMounts:
- - name: myweb
- mountPath: /usr/share/nginx/html/ #要挂载到容器的哪个目录下
除了将数据存放在本地node节点上,为了更安全,我们也可以将数据存储到外部的远程磁盘上,比如放到NFS服务器上,IP为192.168.100.172。
1)搭建NFS服务器
- yum -y install nfs-utils
- mkdir -p /data/testvol
- echo "NFS Test Data" > /data/testvol/index.html
- echo "/data/testvol 192.168.100.0/24(rw,no_root_squash)" >> /etc/exports
- systemctl start nfs
2)创建NFS存储卷
- # 在k8s集群的节点上,安装nfs-utils工具
- $ yum -y install nfs-utils
-
- # 验证是否能成功挂载
- $ mount -t nfs 192.168.100.172:/data/testvol /mnt
-
- # yaml文件如下:
- $ cat vol-nfs-demo.yaml
- apiVersion: v1
- kind: Pod
- metadata:
- name: vol-nfs
- spec:
- volumes:
- - name: myweb
- nfs:
- path: /data/testvol # NFS共享目录
- server: 192.168.100.172 # NFS服务器IP
- containers:
- - name: myapp
- image: ikubernetes/myapp:v1
- volumeMounts:
- - name: myweb
- mountPath: /usr/share/nginx/html/
除了Volume之外,kubernetes 还提供了 Persistent Volume 的方法持久化数据。
它与普通Volume的区别是, 普通Volume和Pod之间是一种静态绑定关系,也就是,在定义pod时,同时要将pod所使用的Volume一并定义好,Volume是Pod的附属品。volume会随着pod创建而被创建,我们无法单独创建一个Volume,因为它不是一个独立的K8S资源对象。
而Persistent Volume则是一个K8S资源对象,它是独立于Pod的,能单独创建。Persistent Volume 不与Pod发生直接关系,而是通过 Persistent Volume Claim(PVC) 来与Pod绑定关系。在定义Pod时,为Pod指定一个PVC,Pod在创建时会根据PVC要求,从现有集群的PV中,选择一个合适的PV绑定,或动态建立一个新的PV,再与其进行绑定。
Persistent Volume(PV):用于定义各种存储资源的配置信息,一个PV对应一个volume,定义一个PV内容包括了 存储类型、存储大小和访问模式等。
Persistent Volume Claim(PVC):描述对PV的一个请求。请求信息包含存储大小、访问模式等。PVC只会选择符合自己要求的PV进行绑定,然后在定义pod时指定使用哪个PVC就可以了。
原理:
PVC和PV的设计,其实跟面向对象的思想完全一致,PVC是面向对象编程中的接口,PV是接口具体的实现。
用户只需通过PVC来声明自己的存储需求,比如存储大小、可读写权限等,类似于调用接口函数并传入属性参数,而不用关心后端存储实现细节,这些都交由运维人员统一管理即可。
Pod是直接与PVC绑定关系,再根据PVC存储需求,去找到对应PV。PVC只有绑定了PV之后才能被Pod使用。
PersistentVolume Controller 会不断地查看当前每一个PVC,是不是已经处于Bound(已绑定)状态。如果不是,那它就会遍历所有的、可用的PV,并尝试将其与这个PVC进行绑定。这样,Kubernetes就可以保证用户提交的每一个PVC,只要有合适的PV出现,它就能够很快进入绑定状态。
在提交PVC后,是如何找到对应的PV:先根据PVC的accessModes匹配出PV列表,再根据PVC的Capacity、StorageClassName、Label Selector进一步筛选PV。如果满足条件的PV有多个,选择PV的size最小的,accessmodes列表最短的PV,也即最小适合原则。
也就是说,PVC绑定PV的过程是有一定规则的,以下规则都满足的PV才能被PVC绑定:
VolumeMode:被消费PV的VolumeMode需要和PVC一致。
AccessMode:被消费PV的AccessMode需要和PVC一致。
StorageClassName:如果PVC定义了此字段,则PV也必须有对应字段才能进行绑定。
LabelSelector:通过标签(labels)匹配的方式从PV列表中选择合适的PV绑定。
Size:被消费PV的capacity必须大于或等于PVC的存储容量需求才能被绑定。
PV类型:
一般来说,PV又有多种类型:Static PV (静态)、Dynamic PV (动态)、Local PV (本地)。
Static/Dynamic PV:静态和动态PV
PV创建虽是由运维人员完成的,但在一个大规模的Kubernetes集群里,很可能有成千上万个PVC,这就意味着运维人员必须得事先创建出成千上万个PV,如果单纯靠人工来管理,会存在一定的困难。
Kubernetes提供了一套可以自动创建PV的机制,即Dynamic Volume Provisioning(动态PV)。而手动创建并管理的PV叫做Static Volume Provisioning(静态PV)。
Dynamic PV创建机制的核心,在于一个名为StorageClass的API对象,它是一个用于创建PV的模板。
在YAML文件中定义PVC时,需要指定一个StorageClass名称,然后等到用户要创建这个PVC时,系统会根据PVC定义的需求,并参考StorageClass的存储细节,最后通过调用StorageClass声明的存储插件(Provisioner),动态创建出需要的PV。
所以,在声明一个PVC时,如果在PVC中添加了StorageClassName字段,那就意味着,当PVC在集群中找不到匹配的PV时,它会根据StorageClassName的定义,触发相应的Provisioner插件创建出合适的PV进行绑定。
也就是说,现在无需事先创建好将来要用到的PV,只要通过StorageClass准备好一些PV模板,等到将来要使用时,PVC再直接使用StorageClass定义好的PV模板,调用存储插件将PV一并创建出来就可以了。
Local-PV:本地PV
一是,不应该随便把node上的任何一个目录当作PV使用,因为不安全,应该额外挂载一个外部磁盘到node上,也就是,一个PV对应一块外部数据盘。
二是,调度器要保证Pod始终能被正确地调度到它所请求的Local PV所在的节点上,那调度器就要知道所有node与local pv的关联关系,即PV的位置分布信息(也叫存储拓扑信息),然后根据这个位置信息来调度Pod。
流程图:
1:先准备好外部存储资源;
2:然后通过static或dynamic方式,将存储资源定义成PV;
3:定义PVC资源请求,PVC会根据配置描述选择合适的PV;
4:最后Pod指定使用哪个PVC,最终是由PVC将Pod与匹配的PV绑定在一起;
- ————————————————————————————————
- |namespace |
- | |
- | [pod1] [pod2] |
- | ↓ ↓ |
- | [volume1] [volume2] |
- | ↑ ↑ |
- | | / |
- | ↓ ↓ |
- | [pvc] [pvc] [pvc] |
- ——————↑—————————↑————————↑——————
- / \ |_ _ _ _ _ __
- / \ ↓
- ↓ ↓ ↓
- [pv] [pv] | | [pv] [pv] [pv] | [pv] [pv] [pv]
- | | |
- static | | storageClass | storageClass
- ——————————— —————————————— ————————————————
- ↑↑ ↑↑
- ↑↑ ↑↑
- ———————————————— ——————————————————————
- [NFS] [ISCSI] [Ceph RDB] [Glusterfs]
PV状态:
Create PV ---> pending ---> available ---> bound ---> released ---> deleted或failed
Available:创建PV后,会短暂处于pending状态,等真正创建好后,就会进入available状态,只有处于该状态下的PV才能够被PVC绑定。
Bound:用户在提交PVC后,并找到相应PV,此时PV与PVC已绑在一起,两者都处于BOUND状态。
Released:如果PV设置了ReclaimPolicy策略为retain,也就是当用户在使用完PVC,将其删除后,对应的这个PV就会处于released状态。
当PV已经处在released状态时,它是无法直接回到available状态,也就是说,接下来这个PV无法被一个新的PVC去做绑定。
有两种方式复用处于released状态的PV:
一种是对之前released的PV做好数据备份,然后重新创建一个PV,并将之前released的PV相关字段的信息填到这个PV中。另一种是在删除Pod后,不要删除PVC,将PVC保留下来供其他Pod直接复用。
这里还是以NFS服务器作为PV存储为例。
1)先搭建好NFS服务器(192.168.100.172)
创建4个NFS共享目录:
- yum -y install nfs-utils
- mkdir -p /data/volumes/v{1..5}
-
- echo "<h1>NFS stor 01</h1>" > /data/volumes/v1/index.html
- echo "<h1>NFS stor 02</h1>" > /data/volumes/v2/index.html
- echo "<h1>NFS stor 03</h1>" > /data/volumes/v3/index.html
- echo "<h1>NFS stor 04</h1>" > /data/volumes/v4/index.html
-
- cat > /etc/exports << EOF
- /data/volumes/v1 192.168.100.0/24(rw,no_root_squash)
- /data/volumes/v2 192.168.100.0/24(rw,no_root_squash)
- /data/volumes/v3 192.168.100.0/24(rw,no_root_squash)
- /data/volumes/v4 192.168.100.0/24(rw,no_root_squash)
- EOF
-
- systemctl start nfs
- exportfs -rv # 重新加载配置
- showmount -e # 查看本地有哪些共享目录
2)创建PV
创建4个pv,都使用nfs共享的目录,存储大小各不相同,是否可读也不相同。
- apiVersion: v1
- kind: PersistentVolume
- metadata:
- name: pv0001
- labels:
- name: pv0001
- spec:
- nfs:
- path: /data/volumes/v1
- server: 192.168.100.172
- accessModes: ["ReadWriteMany","ReadWriteOnce"]
- capacity:
- storage: 2Gi
- ---
- apiVersion: v1
- kind: PersistentVolume
- metadata:
- name: pv0002
- labels:
- name: pv0002
- spec:
- nfs:
- path: /data/volumes/v2
- server: 192.168.100.172
- accessModes: ["ReadWriteOnce"]
- capacity:
- storage: 7Gi
- ---
- apiVersion: v1
- kind: PersistentVolume
- metadata:
- name: pv0003
- labels:
- name: pv0003
- spec:
- nfs:
- path: /data/volumes/v3
- server: 192.168.100.172
- accessModes: ["ReadWriteMany","ReadWriteOnce"]
- capacity:
- storage: 10Gi
- ---
- apiVersion: v1
- kind: PersistentVolume
- metadata:
- name: pv0004
- labels:
- name: pv0004
- spec:
- nfs:
- path: /data/volumes/v4
- server: 192.168.100.172
- accessModes: ["ReadWriteMany","ReadWriteOnce"]
- capacity:
- storage: 15Gi
字段说明:
capacity:设置PV的存储属性,比如存储大小。
accessModes:设置对Volume的访问模式
ReadWriteOnce – the volume can be mounted as read-write by a single node
ReadOnlyMany – the volume can be mounted read-only by many nodes
ReadWriteMany – the volume can be mounted as read-write by many nodespersistentVolumeReclaimPolicy:当PVC被删除时,对应PV的回收策略
Retain - 当PVC被删除时,PV会保留,但被标识为released状态
Delete - 当PVC被删除时,PV也同时被删除
Recycle - 已废弃
查看PV信息:
- $ kubectl get pv
- NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
- pv0001 2Gi RWO,RWX Retain Available 6s
- pv0002 7Gi RWO Retain Available 6s
- pv0003 10Gi RWO,RWX Retain Available 6s
- pv0004 15Gi RWO,RWX Retain Available 6s
3)创建PVC
创建一个PVC,创建好后,该PVC会根据要求请求合适的PV资源。
- 如:下面的PVC会绑定到名为pv0003的PV上
-
- apiVersion: v1
- kind: PersistentVolumeClaim
- metadata:
- name: mypvc
- spec:
- accessModes: ["ReadWriteMany"] #匹配PV的accessModes要包含ReadWriteMany
- resources:
- requests:
- storage: 6Gi #且匹配PV要大于6G
4)创建Pod
创建一个Pod,并指定使用哪个PVC,PVC会决定将哪个PV绑定到此Pod上。
- apiVersion: v1
- kind: Pod
- metadata:
- name: pod-demo
- namespace: default
- spec:
- volumes:
- - name: myvol
- persistentVolumeClaim:
- claimName: mypvc #为此Pod指定使用哪个PVC
- containers:
- - name: myapp
- image: ikubernetes/myapp:v1
- volumeMounts:
- - name: myvol
- mountPath: /usr/share/nginx/html/
创建Pod后,查看PV和PVC状态:
- $ kubectl get pv
- NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
- pv0001 2Gi RWO,RWX Retain Available 18m
- pv0002 7Gi RWO Retain Available 18m
- pv0003 10Gi RWO,RWX Retain Bound default/mypvc 18m
- pv0004 15Gi RWO,RWX Retain Available 18m
-
- $ kubectl get pvc
- NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
- mypvc Bound pv0003 10Gi RWO,RWX 17s
测试访问:
- $ kubectl get pods pod-demo -o wide
- NAME READY STATUS RESTARTS AGE IP NODE
- pod-demo 1/1 Running 0 3m21s 10.244.1.73 node1
-
- $ curl 10.244.1.73
- <h1>NFS stor 03</h1>
步骤1:定义2个StorageClass(创建生成PV的模板文件),一个为普通磁盘,一个为SSD磁盘。
- apiVersion: storage.k8s.io/v1
- kind: StorageClass
- metadata:
- name: slow
- provisioner: kubernetes.io/aws-ebs # 指定一个volume plugin,即应该用哪个存储插件来去创建PV
- parameters:
- type: pd-standard
- reclaimPolicy: Delete # PV的回收策略,默认为delete
- ---
- apiVersion: storage.k8s.io/v1
- kind: StorageClass
- metadata:
- name: fast
- provisioner: kubernetes.io/gce-pd
- parameters:
- type: pd-ssd
- ---
- apiVersion: storage.k8s.io/v1
- kind: StorageClass
- metadata:
- name: csi-disk
- parameters:
- regionId: cn-hangzhou
- zoneId: cn-hangzhou-b
- fsType: ext4
- type: cloud_ssd
- provisioner: diskplugin.csi.alibabacloud.com
- reclaimPolicy: Delete
步骤2:创建PVC,并指定storageClassName名,即到底用哪一个模板文件来生成PV,Kubernetes只会将StorageClass相同的PVC和PV绑定起来。
- apiVersion: v1
- kind: PersistentVolumeClaim
- metadata:
- name: disk-pvc
- spec:
- accessModes:
- - ReadWriteOnce
- storageClassName: csi-disk # 为PVC指定使用哪个StorageClass
- resources:
- requests:
- storage: 30Gi
步骤3:创建Pod,并指定要调用的PVC
- kind: Pod
- apiVersion: v1
- metadata:
- name: mypod
- spec:
- containers:
- - name: myfrontend
- image: dockerfile/nginx
- volumeMounts:
- - mountPath: "/var/www/html"
- name: mypd
- volumes:
- - name: mypd
- persistentVolumeClaim:
- claimName: disk-pvc
yum -y install nfs-utils rpcbind
systemctl start nfs && systemctl enable nfs
systemctl start rpcbind && systemctl enable rpcbind
# master上创建并配置好共享挂载目录(node节点不需要,只需安装好nfs服务就行)
mkdir -pv /data/volumes/{v1,v2,v3}
cat > /etc/exports <<EOF
/data/volumes/v1 *(rw,no_root_squash,no_all_squash)
/data/volumes/v2 *(rw,no_root_squash,no_all_squash)
/data/volumes/v3 *(rw,no_root_squash,no_all_squash)
EOF
# 发布并查看
exportfs -arv
showmount -e
git clone https://github.com/kubernetes-incubator/external-storage.git
cd external-storage/nfs-client/deploy/
cp class.yaml deployment.yaml rbac.yaml test-claim.yaml /var/lib/k8s/storage
cd /var/lib/k8s/storage
a. 配置rbac授权(默认是存放在default空间,可修改为kube-system)
kubectl apply -f rbac.yaml
b. 部署 NFS Provisioner插件
# 修改deployment.yaml文件(设置nfs服务器相关信息)
- apiVersion: apps/v1
- kind: Deployment
- metadata:
- name: nfs-client-provisioner
- labels:
- app: nfs-client-provisioner
- namespace: kube-system #默认是default,修改为kube-sytem
- 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
- image: registry.cn-hangzhou.aliyuncs.com/open-ali/nfs-client-provisioner:latest
- volumeMounts:
- - name: nfs-client-root
- mountPath: /persistentvolumes
- env:
- - name: PROVISIONER_NAME
- value: nfs-client #可自定义,要与class.yaml中的provisioner的名称一致,否则部署不成功
- - name: NFS_SERVER
- value: x.x.x.x #修改为nfs服务器地址
- - name: NFS_PATH
- value: /data/volumes/v1 #NFS服务器中的共享挂载目录
- volumes:
- - name: nfs-client-root
- nfs:
- server: x.x.x.x #修改为nfs服务器地址
- path: /data/volumes/v1 #NFS服务器中的共享挂载目录
# 部署NFS Provisioner插件
kubectl apply -f deployment.yaml
# 查看安装情况
kubectl get pod -o wide -n kube-system -l app=nfs-client-provisioner
- [root@jdmaster ~]# kubectl get pod -o wide -n kube-system -l app=nfs-client-provisioner
- NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
- nfs-client-provisioner-7f75997fb6-tchxb 1/1 Running 0 21h 10.244.1.8 jdnode <none> <none>
kubectl get deployment -n kube-system
- [root@jdmaster ~]# kubectl get deployment -n kube-system
- NAME READY UP-TO-DATE AVAILABLE AGE
- coredns 2/2 2 2 3d
- nfs-client-provisioner 1/1 1 1 21h
# 修改class.yaml
- apiVersion: storage.k8s.io/v1
- kind: StorageClass
- metadata:
- name: managed-nfs-storage
- annotations:
- storageclass.kubernetes.io/is-default-class: "true" #设置为默认的storageclass(如果不设置默认,在创建pvc时,需要手动指定storageclass的名称,否则会处于pending)
- provisioner: nfs-client #可自定义,要与 deployment 中 env PROVISIONER_NAME 一致
- parameters:
- archiveOnDelete: "false"
-
-
- # 也命令方式设置默认的StorageClass(NAME后面会多出一个default字样)
- # kubectl patch storageclass managed-nfs-storage -p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"true"}}}'
# 创建storageclass
kubectl apply -f class.yaml
# 查看(storageclass所有命名空间都可以看到,不需要指定某个namespace)
kubectl get sc
- [root@jdmaster ~]# kubectl get sc
- NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE
- managed-nfs-storage (default) nfs-client Delete Immediate false 21h
# 修改test-claim.yaml
- kind: PersistentVolumeClaim
- apiVersion: v1
- metadata:
- name: test-claim
- #annotations:
- # volume.beta.kubernetes.io/storage-class: "managed-nfs-storage" #若这里指定storageclass了,可以不用手动指定storageClassName字段
- spec:
- storageClassName: managed-nfs-storage #若没有设置默认的storageclass,必须手动指定使用哪个storageclass
- accessModes:
- - ReadWriteMany
- resources:
- requests:
- storage: 1Gi
# 查看pvc状态(会处于Bound状态,若处于pending是不正常的)
kubectl get pvc
- [root@jdmaster ~]# kubectl get pvc
- NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
- test-claim Bound pvc-bcbea3c8-4a37-47c1-8aa6-2c2da6964108 1Gi RWX managed-nfs-storage 20h
# 只要创建好NFS Provisioner deployment 和 storageclass后,再创建PVC时,就会自动创建出PV
kubectl get pv
- [root@jdmaster ~]# kubectl get pv
- NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
- pvc-bcbea3c8-4a37-47c1-8aa6-2c2da6964108 1Gi RWX Delete Bound default/test-claim managed-nfs-storage 20h
kubectl apply -f test-pod.yaml
- cat > test-pod.yaml <<EOF
- kind: Pod
- apiVersion: v1
- metadata:
- name: test-pod
- spec:
- containers:
- - name: test-pod
- image: busybox:latest
- command:
- - "/bin/sh"
- args:
- - "-c"
- - "touch /mnt/SUCCESS && exit 0 || exit 1"
- volumeMounts:
- - name: nfs-pvc
- mountPath: "/mnt"
- restartPolicy: "Never"
- volumes:
- - name: nfs-pvc
- persistentVolumeClaim:
- claimName: test-claim
- EOF
# POD会成功创建好SUCCESS文件,就退出了,状态为Completed
# 进入到NFS共享目录(/data/volumes/v1/<namespace名称>-<pvc名称>-<pv名称>/),查看SUCCESS文件是否存在
PV和PVC的处理流程:
【配图-待补充】
csi全称是container storage interface,它是K8s社区后面对存储插件实现(out of tree)的官方推荐方式。
csi的实现大体可分为两部分:
第一部分:是由k8s社区驱动实现的通用的部分,如图中的csi-provisioner和csi-attacher controller;
第二部分:由云存储厂商实践的,对接云存储厂商的OpenApi,主要是实现真正的create/delete/mount/unmount 存储的相关操作,对应到图中的csi-controller-server和csi-node-server。
用户在提交PVC yaml时,首先会在集群中生成一个PVC对象,然后PVC对象会被csi-provisioner controller watch到,csi-provisioner会结合PVC对象及PVC对象中声明的 storageClass,通过GRPC调用csi-controller-server。然后,到云存储服务这边去创建真正的存储,并最终创建出来PV对象。最后,由集群中的PV controller将PVC和PV对象做bound 之后,这个PV就可以被使用了。
用户在提交pod之后,首先会被scheduler调度选中某一个合适的node,然后node上的kubelet在创建pod时,会先通过csi-node-server将之前创建的PV挂载到pod指定路径。
然后kubelet开始 create && start pod 中的所有container。
PV、PVC及通过csi使用存储流程:
【配图-待补充】
第一个阶段:create阶段,主要是创建存储。
用户提交完PVC,由csi-provisioner创建存储,并生成PV对象,之后PV controller将PVC及生成的PV对象做bound,bound之后,create阶段就完成了。
第二个阶段:attach阶段,将对应的存储挂载到node上。
用户在提交pod之后,首先会被scheduler调度选中某一个合适的node,node被选出来后,AD Controller会watch到该node,它会根据Pod使用了哪些PV,生产一个内部的VolumeAttachment对象,从而去触发csi-attacher去调用csi-controller-server去做真正的attach操作,attach操作调到云存储厂商OpenAPI,并将存储attach到pod将会运行的node上面。
第三个阶段:mount阶段,将对应的存储进一步挂载到pod里。
在kubelet创建pod的过程中,会先做一个mount操作,这是为了将已经attach到这个node上的那块盘,进一步mount到pod可使用的一个具体路径,之后kubelet才开始创建并启动容器。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。