文章目录
- 一、Volume
- 1、什么是Volume
- 2、Host类型volume实战(不推荐)
- (1)小总结
- 二、PersistentVolume持久化volume(推荐)
- 1、什么是PersistentVolume
- 2、什么是PersistentVolumeClaim
- 3、Pod中如何使用PVC
- 三、Pod中使用PVC实战
- 1、搭建NFS
- 2、创建PV&PVC&Nginx
- (1)在nfs服务器创建所需要的目录
- (2)定义PV,PVC和Nginx的yaml文件
- (3)根据yaml文件创建资源并查看资源
- (4)测试持久化存储
- 四、StorageClass
- 1、什么是StorageClass
- 2、StorageClass实战
- (1)准备好NFS服务器[并且确保nfs可以正常工作],创建持久化需要的目录
- (2)根据rbac.yaml文件创建资源
- (3)根据deployment.yaml文件创建资源
- (4)根据class.yaml创建资源
- (5)根据pvc.yaml创建资源
- (6)根据nginx-pod.yaml创建资源
- 五、PV的状态和回收策略
一、Volume
1、什么是Volume
Volume官网:https://kubernetes.io/docs/concepts/storage/volumes/
On-disk files in a Container are ephemeral, which presents some problems for non-trivial applications when running in Containers. First, when a Container crashes, kubelet will restart it, but the files will be lost - the Container starts with a clean state. Second, when running Containers together in a Pod it is often necessary to share files between those Containers. The Kubernetes Volume abstraction solves both of these problems.
容器中的磁盘上文件是短暂的,这给在容器中运行的重要应用程序带来了一些问题。首先,当一个容器崩溃时,kubelet会重启它,但是文件会丢失——容器以干净的状态开始。其次,当在一个Pod中一起运行容器时,通常需要在这些容器之间共享文件。Kubernetes的Volume 抽象解决了这两个问题。
2、Host类型volume实战(不推荐)
定义一个Pod,其中包含两个Container,都使用Pod的Volume
创建volume-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: volume-pod
spec:
containers:
- name: nginx-container # nginx container
image: nginx
ports:
- containerPort: 80
volumeMounts: # 使用某个volume
- name: volume-pod # volume名称
mountPath: /nginx-volume # 对应container中的目录
- name: busybox-container # busybox的container
image: busybox
command: ['sh', '-c', 'echo The app is running! && sleep 3600']
volumeMounts:
- name: volume-pod
mountPath: /busybox-volume # 对应container目录
volumes: # 定义volume
- name: volume-pod # volume名称
hostPath: # volume类型
path: /tmp/volume-pod # 对应宿主机的位置
# 运行
kubectl apply -f volume-pod.yaml
# 查看pod,发现pod运行在了w1节点
kubectl get pods -o wide
# 进入w1的容器
docker exec -it a2e9dbc52a11 /bin/bash
docker exec -it 27c66caa2b85 sh
# 看容器的/nginx-volume目录中的内容与宿主机的/tmp/volume-pod内容是不是一样,再折腾一下看文件会不会同步,看两个pod中的内容是否会同步
(1)小总结
我们发现,使用volume形式,会与宿主机共享目录,里面数据内容是一致的。
如果pod挂掉了,宿主机的文件仍然不会丢失,可以完美解决数据保存的问题,保证数据不丢失。
但是host的方式,只能保证pod与当前宿主机目录的绑定关系,集群下无法保证(如果下次pod运行在另一台宿主机,文件仍然无法关联)。
或许我们可以使用打标签的方式,指定该pod永远部署在某一台机器,但是如果该机器挂了,就无法使用了。
二、PersistentVolume持久化volume(推荐)
1、什么是PersistentVolume
官网:https://kubernetes.io/docs/concepts/storage/persistent-volumes/
# 实例 ,定义一个PV
apiVersion: v1
kind: PersistentVolume
metadata:
name: my-pv
spec:
capacity:
storage: 5Gi # 存储空间大小
volumeMode: Filesystem
accessModes:
- ReadWriteOnce # 只允许一个Pod进行独占式读写操作
persistentVolumeReclaimPolicy: Recycle
storageClassName: slow
mountOptions:
- hard
- nfsvers=4.1
nfs:
path: /tmp # 远端服务器的目录
server: 172.17.0.2 # 远端的服务器
说白了,PV是K8s中的资源,volume的plugin实现,生命周期独立于Pod,封装了底层存储卷实现的细节。这种资源可以和第三方存储技术绑定,比如DFS。
注意:PV的维护通常是由运维人员、集群管理员进行维护的。
2、什么是PersistentVolumeClaim
官网:https://kubernetes.io/docs/concepts/storage/persistent-volumes/#persistentvolumeclaims
有了PV,那Pod如何使用呢?为了方便使用,我们可以设计出一个PVC(PersistentVolumeClaim)来绑定PV,然后把PVC交给Pod来使用即可。
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: myclaim
spec:
accessModes:
- ReadWriteOnce
volumeMode: Filesystem
resources:
requests:
storage: 8Gi
storageClassName: slow
selector:
matchLabels:
release: "stable"
matchExpressions:
- {key: environment, operator: In, values: [dev]}
说白了,PVC会匹配满足要求的PV[是根据size和访问模式进行匹配的
],进行一一绑定,然后它们的状态都会变成Bound。
也就是PVC负责请求PV的大小和访问方式,然后Pod中就可以直接使用PVC咯。
注意:PVC通常由开发小伙伴维护,开发小伙伴无需关注与存储细节,开发小伙伴只需要声明使用的资源大小,由PVC来声明,PVC会去找合适的PV。
3、Pod中如何使用PVC
官网:https://kubernetes.io/docs/concepts/storage/persistent-volumes/#claims-as-volumes
apiVersion: v1
kind: Pod
metadata:
name: mypod
spec:
containers:
- name: myfrontend
image: nginx
volumeMounts:
- mountPath: "/var/www/html"
name: mypd
volumes:
- name: mypd
persistentVolumeClaim:
claimName: myclaim # 指定pvc
三、Pod中使用PVC实战
(1)共享存储使用nfs,我们选择在m节点
(2)创建pv和pvc
(3)nginx pod中使用pvc
NFS(network file system)网络文件系统,是FreeBSD支持的文件系统中的一种,允许网络中的计算机之间通过TCP/IP网络共享资源。
1、搭建NFS
在master节点(192.168.56.100)上搭建一个NFS服务器,目录为/nfs/data
01 选择master节点作为nfs的server,所以在master节点上
# 安装nfs
yum install -y nfs-utils
# 创建nfs目录
mkdir -p /nfs/data/
mkdir -p /nfs/data/mysql
# 授予权限
chmod -R 777 /nfs/data
# 编辑export文件,输入下面一行
vi /etc/exports
/nfs/data *(rw,no_root_squash,sync)
# 使得配置生效
exportfs -r
# 查看生效 显示:/nfs/data <world>
exportfs
# 启动rpcbind、nfs服务
systemctl restart rpcbind && systemctl enable rpcbind
systemctl restart nfs && systemctl enable nfs
# 查看rpc服务的注册情况
rpcinfo -p localhost
# showmount测试 showmount -e 192.168.56.100
showmount -e master-ip
02 所有node上安装客户端
yum -y install nfs-utils
systemctl start nfs && systemctl enable nfs
2、创建PV&PVC&Nginx
(1)在nfs服务器创建所需要的目录
mkdir -p /nfs/data/nginx
(2)定义PV,PVC和Nginx的yaml文件
nginx-pv-demo.yaml
# 定义PV
apiVersion: v1
kind: PersistentVolume
metadata:
name: nginx-pv # pv名字
spec:
accessModes:
- ReadWriteMany # 多个pod多次访问模式
capacity:
storage: 2Gi # 大小
nfs:
path: /nfs/data/nginx # 服务器path
server: 192.168.56.100 # 服务器ip
---
# 定义PVC,用于消费PV
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: nginx-pvc # pvc名称
spec:
accessModes:
- ReadWriteMany # 访问模式,需要与pv对应,会进行匹配
resources:
requests:
storage: 2Gi # 需要的空间大小
---
# 定义Pod,指定需要使用的PVC
apiVersion: apps/v1beta1
kind: Deployment
metadata:
name: nginx
spec:
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- image: nginx
name: nginx
ports:
- containerPort: 80
volumeMounts:
- name: nginx-persistent-storage
mountPath: /usr/share/nginx/html # container共享目录
volumes:
- name: nginx-persistent-storage
persistentVolumeClaim:
claimName: nginx-pvc # 指定pvc
(3)根据yaml文件创建资源并查看资源
# 启动
[root@m ~]# kubectl apply -f nginx-pv-demo.yaml
persistentvolume/nginx-pv created
persistentvolumeclaim/nginx-pvc created
deployment.apps/nginx created
# 查看pv和pvc
[root@m ~]# kubectl get pv,pvc
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
persistentvolume/nginx-pv 2Gi RWX Retain Bound default/nginx-pvc 10s
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
persistentvolumeclaim/nginx-pvc Bound nginx-pv 2Gi RWX 9s
# 查看pod
[root@m ~]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-77945f44db-8rfhr 1/1 Running 0 53s 192.168.80.207 w2 <none> <none>
# 删除
kubectl delete -f nginx-pv-demo.yaml
(4)测试持久化存储
01 在nfs服务器的/nfs/data/nginx新建文件1.html,写上内容hello nginx
02 kubectl get pods -o wide 得到nginx-pod的ip地址 :192.168.80.207
03 curl nginx-pod-ip/1.html
curl 192.168.80.207/1.html :打印hello nginx
04 kubectl exec -it nginx-pod bash 进入/usr/share/nginx/html目录查看,发现有了1.html
05 kubectl delete pod nginx-pod
发现原来的pod被删了,又自动启动了一个新的pod,新的pod地址为:192.168.80.208
06 查看新nginx-pod的ip并且访问nginx-pod-ip/1.html
curl 192.168.80.208/1.html 确实仍然能够访问,打印出hello nginx
四、StorageClass
1、什么是StorageClass
上面手动管理PV的方式还是有点low,能不能更加灵活一点呢?
官网:https://kubernetes.io/docs/concepts/storage/storage-classes/
nfs github:github:https://github.com/kubernetes-incubator/external-storage/tree/master/nfs
A StorageClass provides a way for administrators to describe the “classes” of storage they offer. Different classes might map to quality-of-service levels, or to backup policies, or to arbitrary policies determined by the cluster administrators. Kubernetes itself is unopinionated about what classes represent. This concept is sometimes called “profiles” in other storage systems.
Each StorageClass contains the fields provisioner, parameters, and reclaimPolicy, which are used when a PersistentVolume belonging to the class needs to be dynamically provisioned.
The name of a StorageClass object is significant, and is how users can request a particular class. Administrators set the name and other parameters of a class when first creating StorageClass objects, and the objects cannot be updated once they are created.
StorageClass声明存储插件,用于自动创建PV。
说白了就是创建PV的模板,其中有两个重要部分:PV属性和创建此PV所需要的插件。
这样PVC就可以按“Class”来匹配PV。
可以为PV指定storageClassName属性,标识PV归属于哪一个Class。
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: standard
provisioner: kubernetes.io/aws-ebs
parameters:
type: gp2
reclaimPolicy: Retain
allowVolumeExpansion: true
mountOptions:
- debug
volumeBindingMode: Immediate
01 对于PV或者StorageClass只能对应一种后端存储
02 对于手动的情况,一般我们会创建很多的PV,等有PVC需要使用的时候就可以直接使用了
03 对于自动的情况,那么就由StorageClass来自动管理创建
04 如果Pod想要使用共享存储,一般会在创建PVC,PVC中描述了想要什么类型的后端存储、空间等,K8s从而会匹配对应的PV,如果没有匹配成功,Pod就会处于Pending状态。Pod中使用只需要像使用volumes一样,指定名字就可以使用了
05 一个Pod可以使用多个PVC,一个PVC也可以给多个Pod使用
06 一个PVC只能绑定一个PV,一个PV只能对应一种后端存储
有了StorageClass之后的PVC可以变成这样:
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: test-claim1
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 1Mi
storageClassName: nfs
StorageClass之所以能够动态供给PV,是因为Provisioner,也就是Dynamic Provisioning
但是NFS这种类型,K8s中默认是没有Provisioner插件的,需要自己创建。
2、StorageClass实战
github:https://github.com/kubernetes-incubator/external-storage/tree/master/nfs
(1)准备好NFS服务器[并且确保nfs可以正常工作],创建持久化需要的目录
mkdir -p /nfs/data/cxf
chmod 777 /nfs/data
# server: 192.168.56.100
(2)根据rbac.yaml文件创建资源
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: nfs-provisioner-runner
rules:
- apiGroups: [""]
resources: ["persistentvolumes"]
verbs: ["get", "list", "watch", "create", "delete"]
- apiGroups: [""]
resources: ["persistentvolumeclaims"]
verbs: ["get", "list", "watch", "update"]
- apiGroups: ["storage.k8s.io"]
resources: ["storageclasses"]
verbs: ["get", "list", "watch"]
- apiGroups: [""]
resources: ["events"]
verbs: ["create", "update", "patch"]
- apiGroups: [""]
resources: ["services", "endpoints"]
verbs: ["get"]
- apiGroups: ["extensions"]
resources: ["podsecuritypolicies"]
resourceNames: ["nfs-provisioner"]
verbs: ["use"]
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: run-nfs-provisioner
subjects:
- kind: ServiceAccount
name: nfs-provisioner
# replace with namespace where provisioner is deployed
namespace: default
roleRef:
kind: ClusterRole
name: nfs-provisioner-runner
apiGroup: rbac.authorization.k8s.io
---
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: leader-locking-nfs-provisioner
rules:
- apiGroups: [""]
resources: ["endpoints"]
verbs: ["get", "list", "watch", "create", "update", "patch"]
---
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: leader-locking-nfs-provisioner
subjects:
- kind: ServiceAccount
name: nfs-provisioner
# replace with namespace where provisioner is deployed
namespace: default
roleRef:
kind: Role
name: leader-locking-nfs-provisioner
apiGroup: rbac.authorization.k8s.io
kubectl apply -f rbac.yaml
(3)根据deployment.yaml文件创建资源
apiVersion: v1
kind: ServiceAccount
metadata:
name: nfs-provisioner
---
kind: Deployment
apiVersion: extensions/v1beta1
metadata:
name: nfs-provisioner
spec:
replicas: 1
strategy:
type: Recreate
template:
metadata:
labels:
app: nfs-provisioner
spec:
serviceAccount: nfs-provisioner
containers:
- name: nfs-provisioner
image: registry.cn-hangzhou.aliyuncs.com/open-ali/nfs-client-provisioner
volumeMounts:
- name: nfs-client-root
mountPath: /persistentvolumes
env:
- name: PROVISIONER_NAME
value: example.com/nfs
- name: NFS_SERVER
value: 192.168.56.100 # 指定nfs地址
- name: NFS_PATH
value: /nfs/data/cxf # 指定nfs目录
volumes:
- name: nfs-client-root
nfs:
server: 192.168.56.100 # 指定nfs地址
path: /nfs/data/cxf # 指定nfs目录
# 创建
kubectl apply -f deployment.yaml
(4)根据class.yaml创建资源
kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
name: example-nfs
provisioner: example.com/nfs
# 创建
kubectl apply -f class.yaml
(5)根据pvc.yaml创建资源
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: my-pvc
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 1Mi
# 这个名字要和上面创建的storageclass名称一致
storageClassName: example-nfs
# 创建
kubectl apply -f pvc.yaml
# 获取pvc,发现状态已经是Bound了
kubectl get pvc
# 获取pv,发现自动创建了pv
kubectl get pv
(6)根据nginx-pod.yaml创建资源
kind: Pod
apiVersion: v1
metadata:
name: nginx
spec:
containers:
- name: nginx
image: nginx
volumeMounts:
- name: my-pvc # 指定pvc
mountPath: "/usr/cxf" # 容器地址
restartPolicy: "Never"
volumes:
- name: my-pvc # 指定pvc
persistentVolumeClaim:
claimName: my-pvc
# 创建
kubectl apply -f nginx-pod.yaml
# 查看pod
kubectl get pods -o wide
# 进入nginx
kubectl exec -it nginx bash
cd /usr/cxf
# 进行同步数据测试
五、PV的状态和回收策略
- PV的状态
Available:表示当前的pv没有被绑定
Bound:表示已经被pvc挂载
Released:pvc没有在使用pv, 需要管理员手工释放pv
Failed:资源回收失败
- PV回收策略
Retain:表示删除PVC的时候,PV不会一起删除,而是变成Released状态等待管理员手动清理
Recycle:在Kubernetes新版本就不用了,采用动态PV供给来替代
Delete:表示删除PVC的时候,PV也会一起删除,同时也删除PV所指向的实际存储空间
注意
:目前只有NFS和HostPath支持Recycle策略。AWS EBS、GCE PD、Azure Disk和Cinder支持Delete策略