-
Volume 生命周期
-
Volume 的生命周期包括 5 个阶段
- Provisioning,即 PV 的创建,可以直接创建 PV(静态方式),也可以使用 StorageClass 动态创建
- Binding,将 PV 分配给 PVC
- Using,Pod 通过 PVC 使用该 Volume,并可以通过准入控制 StorageObjectInUseProtection(1.9 及以前版本为 PVCProtection)阻止删除正在 使用的 PVC
- Releasing,Pod 释放 Volume 并删除 PVC
- Reclaiming,回收 PV,可以保留 PV 以便下次使用,也可以直接从云存储中删除
- Deleting,删除 PV 并从云存储中删除后段存储
-
Volume 的状态有以下 4 种
- Available:可用
- Bound:已经分配给 PVC
- Released:PVC 解绑但还未执行回收策略
- Failed:发生错误
-
PV
PersistentVolume(PV)是集群之中的一块网络存储。跟 Node 一样,也是集群的资源。PV 跟 Volume (卷) 类似,不过会有独立于 Pod 的生命周期。比如一个 NFS 的 PV 可以定义为:
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv0003
spec:
capacity:
storage: 5Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Recycle
nfs:
path: /tmp
server: 172.17.0.2
-
PV 的访问模式(accessModes)有三种
- ReadWriteOnce (RWO):是最基本的方式,可读可写,但只支持被单个节点挂载。
- ReadOnlyMany (ROX):可以以只读的方式被多个节点挂载。
- ReadWriteMany (RWX):这种存储可以以读写的方式被多个节点共享。不是每一 种存储都支持这三种方式,像共享方式,目前支持的还比较少,比较常用的是 NFS。在 PVC 绑定 PV 时通常根据两个条件来绑定,一个是存储的大小,另一个就是访问模式。
-
PV 的回收策略(persistentVolumeReclaimPolicy,即 PVC 释放卷的时候 PV 该如何操作)也有三种:
- Retain:不清理, 保留 Volume(需要手动清理)
- Recycle:删除数据,即 rm -rf /thevolume/* (只有 NFS 和 HostPath 支持)
- Delete:删除存储资源,比如删除 AWS EBS 卷(只有 AWS EBS, GCE PD, Azure Disk 和 Cinder 支持)
StorageClass
上面通过手动的方式创建了一个 NFS Volume,这在管理很多 Volume 的时候不太方便。Kubernetes 还提供了 StorageClass 来动态创建 PV,不仅节省了管理员的时间,可以封装不同类型的存储供 PVC 选用。
-
StorageClass 包括四个部分
- provisioner:指定 Volume 插件的类型,包括内置插件(如 kubernetes.io/glusterfs)和外部插件(如 external-storage 提供的 ceph.com/cephfs)。
- mountOptions:指定挂载选项,当 PV 不支持指定的选项时会直接失败。比如 NFS 支持 hard 和 nfsvers=4.1 等选项。
- parameters:指定 provisioner 的选项,比如 kubernetes.io/aws-ebs 支持 type 、 zone 、 iopsPerGB 等参数。
- reclaimPolicy:指定回收策略,同 PV 的回收策略。
在使用 PVC 时,可以通过 DefaultStorageClass 准入控制设置默认 StorageClass, 即给未设置 storageClassName 的 PVC 自动添加默认的 StorageClass。而默认的 StorageClass 带有 annotation storageclass.kubernetes.io/is-default-class=true
创建一个NFS类型的storagecalss,并将它挂载到nginx的pod中
- 首先在系统中安装nfs服务
$ sudo apt-get install nfs-common
$ sudo apt install nfs-kernel-server
设置共享目录(在/etc/exports 最下面加这一行)
/k8s-data *(rw,no_root_squash,no_all_squash,sync)
- 启动nfs服务
$ sudo systemctl strart rpcbind
$ sudo service nfs-kernel-server start
查看共享目录设置情况
$ showmount -e
Export list for xxxxxxx:
/k8s-data *
这时候nfs的共享目录就设置好了,路径是server的/k8s-data 目录
- 创建pv
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv1
spec:
capacity:
storage: 1Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Retain
storageClassName: nfs
nfs:
path: /k8s-data
server: xxxxxxx
$ kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pv1 1Gi RWO Retain Bound default/pvc1 nfs 23m
设置pv的大小为1G,storageClass为nfs,指向nfs server的/k8s-data 路径
- 创建pvc
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pvc1
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
storageClassName: nfs
$ kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
pvc1 Bound pv1 1Gi RWO nfs 23m
- 创建一个nginx的deployment,并且将创建的pv挂载到pods上面
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
selector:
matchLabels:
app: nginx
replicas: 2
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:latest
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
volumeMounts:
- mountPath: /data
name: data
volumes:
- name: data
persistentVolumeClaim:
claimName: pvc1
这里面引用刚刚创建的pvc1,并且将它挂载到pods的/data 目录下,然后通过kubectl create -f nginx-dep.yaml创建deployment
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
nginx-deployment-68ffbd49cc-hf79w 1/1 Running 0 25m
nginx-deployment-68ffbd49cc-jffw7 1/1 Running 0 25m
$ kubectl get deployment
NAME READY UP-TO-DATE AVAILABLE AGE
nginx-deployment 2/2 2 2 25m
$ kubectl describe deployment nginx-deployment
Name: nginx-deployment
Namespace: default
CreationTimestamp: Mon, 05 Aug 2024 16:45:46 +0800
Labels: <none>
Annotations: deployment.kubernetes.io/revision: 1
Selector: app=nginx
Replicas: 2 desired | 2 updated | 2 total | 2 available | 0 unavailable
StrategyType: RollingUpdate
MinReadySeconds: 0
RollingUpdateStrategy: 25% max unavailable, 25% max surge
Pod Template:
Labels: app=nginx
Containers:
nginx:
Image: nginx:latest
Port: 80/TCP
Host Port: 0/TCP
Environment: <none>
Mounts:
/data from data (rw)
Volumes:
data:
Type: PersistentVolumeClaim (a reference to a PersistentVolumeClaim in the same namespace)
ClaimName: pvc1
ReadOnly: false
Conditions:
Type Status Reason
---- ------ ------
Available True MinimumReplicasAvailable
Progressing True NewReplicaSetAvailable
OldReplicaSets: <none>
NewReplicaSet: nginx-deployment-68ffbd49cc (2/2 replicas created)
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal ScalingReplicaSet 26m deployment-controller Scaled up replica set nginx-deployment-68ffbd49cc to 2
通过上面的查看,已经能看到pvc1被挂载到nginx-deployment上面了
- 测试
在主机的/k8s-data目录下创建几个文件
/k8s-data$ ls
1.txt 2.txt 3.txt
然后登录到pod里面查看/data 目录,发现也可以看到这几个文件
$ kubectl exec -it nginx-deployment-68ffbd49cc-hf79w -- /bin/sh
# ls /data
1.txt 2.txt 3.txt
再通过pod的/data 目录创建文件
# cd /data
# ls
1.txt 2.txt 3.txt
# touch 4.txt
# ls
1.txt 2.txt 3.txt 4.txt
在主机的/k8s-data目录下也可以看到新建的文件
/k8s-data$ ls
1.txt 2.txt 3.txt 4.txt
至此pv创建并挂载完成