【Kubernetes】Volume
Storage Requirements
Storage Use Case
Local vs Remote Volume Types
Local Volume
- 定义使用Host类型Volume的Pod
vim volume-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: volume-pod
spec:
# 一个pod中的多个容器可以都绑定宿主机中的路径,达到共享宿主机的存储目录
containers:
- name: nginx-container
image: nginx
ports:
- containerPort: 80
# 定义容器中绑定的存储,即将容器中的某个路径和宿主机中的某个路径互相绑定
volumeMounts:
- name: volume-pod
mountPath: /nginx-volume
- name: busybox-container
image: busybox
command: [ 'sh', '-c', 'echo The app is running! && sleep 3600' ]
# 定义容器中绑定的存储,即将容器中的某个路径和宿主机中的某个路径互相绑定
volumeMounts:
- name: volume-pod
mountPath: /busybox-volume
# 定义host类型的存储
volumes:
- name: volume-pod
hostPath:
path: /tmp/volume-pod
- 创建Host类型Volume的Pod
kubectl apply -f volume-pod.yaml
- 分别进入这个pod中的两个容器中mountPath
docker ps | grep volume
5c3ebca91431 busybox "sh -c 'echo The app…" 45 seconds ago Up 44 seconds k8s_busybox-container_volume-pod_default_e17f43ed-ac43-11ec-8b81-00163e18d0d0_0
a7e00097e55a nginx "/docker-entrypoint.…" About a minute ago Up About a minute k8s_nginx-container_volume-pod_default_e17f43ed-ac43-11ec-8b81-00163e18d0d0_0
a86724b8049d k8s.gcr.io/pause:3.1 "/pause" About a minute ago Up About a minute k8s_POD_volume-pod_default_e17f43ed-ac43-11ec-8b81-00163e18d0d0_0
docker exec -it 5c3ebca91431 sh
cd /busybox-volume
在宿主机中/tmp/volume-pod路径上创建文件,会同样的在两个容器中的mountPath路径下创建相同的文件,说明他们之间是互相绑定了
- 查看两个容器的hosts文件
docker exec -it 5c3ebca91431 cat /etc/hosts
发现两个容器中的hosts文件都相同,并且都是由pod来统一管理;所以一般容器中的存储或者网络的内容,不要在容器层面修改,而是在pod中修改。
- 修改pod中的所有容器的网络
...
spec:
# 是否使用主机的网络
hostNetwork: true
# 是否使用主机的PID命令空间
hostPID: true
# 自定义容器的IP地址
hostAliases:
- ip: "192.168.8.61"
# 自定义容器的主机名
hostname: test.jack.com
# 一个pod中的多个容器可以都绑定宿主机中的路径,达到共享宿主机的存储目录
containers:
...
ConfigMap and Secret
Remote Volume
NFS
nfs(network file system)网络文件系统,是FreeBSD支持的文件系统中的一种,允许网络中的计算机之间通过TCP/IP网络共享资源
- 安装nfs
yum install -y nfs-utils
- 创建nfs目录
mkdir -p /nfs/data/
- 目录授予权限
chmod -R 777 /nfs/data
- 编辑export文件
vim /etc/exports
/nfs/data *(rw,no_root_squash,sync)
- 使得配置生效
exportfs -r
- 查看配置是否生效
exportfs
- 启动rpcbind、nfs服务
systemctl restart rpcbind && systemctl enable rpcbind
systemctl restart nfs && systemctl enable nfs
- 查看rpc服务的注册情况
rpcinfo -p localhost
- showmount测试
showmount -e master节点ip
- 集群其他节点安装客户端
yum -y install nfs-utils
systemctl start nfs && systemctl enable nfs
Different Volume Types in a Pod
Persistent Volume
官方文档:https://kubernetes.io/docs/concepts/storage/persistent-volumes/
- PV是K8s中的资源,volume的plugin实现,生命周期独立于Pod,封装了底层存储卷实现的细节。
Persistent Volumes are NOT namespaced
Yaml Example
- 创建一个PV
apiVersion: v1
kind: PersistentVolume
metadata:
name: nginx-pv
spec:
# 定义PV的访问模式
accessModes:
- ReadWriteMany
# 定义PV的存储容量
capacity:
storage: 2Gi
# 远端服务器配置
nfs:
path: /nfs/data/nginx
server: 172.24.253.248
- 查看所有的namespace下的PV资源
kubectl get pv --all-namespaces
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
nginx-pv 2Gi RWX Retain Bound default/nginx-pvc 2d23h
状态为Bound表示这个PV已经和namespace为default下面的nginx-pvc这个PVC进行绑定
- PV的状态:
Available
:表示当前的pv没有被绑定Bound
:表示已经被pvc挂载Released
:pvc没有在使用pv, 需要管理员手工释放pvFailed
:资源回收失败
- PV回收策略:
Retain
:表示删除PVC的时候,PV不会一起删除,而是变成Released状态等待管理员手动清理Recycle
:在Kubernetes新版本就不用了,采用动态PV供给来替代Delete
:表示删除PVC的时候,PV也会一起删除,同时也删除PV所指向的实际存储空间
目前只有NFS和HostPath支持Recycle策略。AWS EBS、GCE PD、Azure Disk和Cinder支持Delete策略
Persistent Volume Claim
官方文档:https://kubernetes.io/docs/concepts/storage/persistent-volumes/#persistentvolumeclaims
PVC是Pod使用PV资源的纽带
PVC会根据accessModes和storage来匹配对应的PV,然后进行一一绑定,绑定之后他们的状态就变成Bound
- 创建一个PVC
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: nginx-pvc
spec:
# 定义PVC的访问模式
accessModes:
- ReadWriteMany
resources:
# 定义PVC请求的PV的存储容量
requests:
storage: 2Gi
- 查看所有的namespace下的PVC资源
kubectl get pvc --all-namespaces
NAMESPACE NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
default nginx-pvc Bound nginx-pv 2Gi RWX 3d
状态为Bound表示这个PVC已经和nginx-pv这个PV进行绑定
Persistent Volume Claim Use Case
Claims must be in the same namespace!
- 创建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: mysql
ports:
- containerPort: 80
# 定义容器中使用pvc的方式将容器中的某一个路径和pv对应的nfs上的指定路径互相绑定,从而将容器的存储不依赖于宿主机
volumeMounts:
- name: nginx-persistent-storage
mountPath: /usr/share/nginx/html
# 定义pvc类型的存储
volumes:
- name: nginx-persistent-storage
persistentVolumeClaim:
claimName: nginx-pvc
- 到此为止,这个Pod中的
/usr/share/nginx/html
目录已经和nfs服务器上/nfs/data/nginx
目录互相绑定了,下面进行简单测试:
- 在/nfs/data/nginx新建文件1.html,写上内容
- 获取Pod的详情信息:
kubectl get pods -o wide
- 进入Pod:
kubectl exec -it nginx-pod bash
- 进入/usr/share/nginx/html目录查看,发现存在1.html文件
- 手动删除这个Pod:
kubectl delete pod nginx-pod
- 再次进入新的Pod中查看/usr/share/nginx/html目录是否存在1.html文件
Storage Class
官方文档:https://kubernetes.io/docs/concepts/storage/storage-classes/
StorageClass声明存储插件,用于自动创建PV,也就是创建PV的模板。
StorageClass和PV的关系相关于Java中的类和实例的关系
StorageClass的两个重要部分:PV属性,创建此PV所需要的插件(Provisioner)
- 创建一个StorageClass
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: standard
# 使用内部集成的AWSElasticBlockStore这个Volume Plugin来创建AWSElasticBlockStore类型的PV
provisioner: kubernetes.io/aws-ebs
parameters:
type: gp2
reclaimPolicy: Retain
allowVolumeExpansion: true
mountOptions:
- debug
volumeBindingMode: Immediate
Storage Class Use Cases
NFS Type Provisioner
如图所示,因为NFS类型的存储没有Internal Provisioner,所有需要手动创建,才能供StorageClass使用
- 根据rbac.yaml文件创建资源
vim 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
- 根据deployment.yaml文件创建资源
vim 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
# 指定手动创建的NFS类型的provisioner的名称,提供给StorageClass使用
value: example.com/nfs
- name: NFS_SERVER
# 指定NFS服务器的IP地址
value: 172.24.253.248
- name: NFS_PATH
# 指定NFS服务器的路径
value: /nfs/data/storageclass
volumes:
- name: nfs-client-root
nfs:
# 指定NFS服务器的IP地址
server: 172.24.253.248
# 指定NFS服务器的路径
path: /nfs/data/storageclass
kubectl apply -f deployment.yaml
- 根据class.yaml创建StorageClass
vim class.yaml
kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
name: example-nfs
# 使用上面手动创建好的provisioner来创建NFS类型的PV
provisioner: example.com/nfs
kubectl apply -f class.yaml
- 根据pvc.yaml创建PVC
vim my-pvc.yaml
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: my-pvc
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 1Mi
# 这个名字要和上面创建的StorageClass名称一致
storageClassName: example-nfs
kubectl apply -f my-pvc.yaml
- 查看创建的PVC资源
kubectl get pvc -o wide
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
my-pvc Bound pvc-2fca01a6-b042-11ec-8b81-00163e18d0d0 1Mi RWX example-nfs 6s
可以看到此时PVC的状态为Bound,说明已经和PV绑定了
- 创建Pod,并使用上面创建的PVC
vim nginx-pod.yaml
kind: Pod
apiVersion: v1
metadata:
name: nginx
spec:
containers:
- name: nginx
image: nginx
volumeMounts:
- name: my-pvc
mountPath: /usr/storageclass
restartPolicy: "Never"
volumes:
- name: my-pvc
persistentVolumeClaim:
claimName: my-pvc
kubectl apply -f nginx-pod.yaml
- 查看创建的Pod
kubectl get pods -o wide
- 这样Pod中的容器的
/usr/storageclass
路径就和NFS上的/nfs/data/storageclass
路径进行绑定,接下来可以测试一下 - 进入Pod的容器
kubectl exec -it nginx bash
- 进入
/usr/storageclass
目录,新增1.html文件,看下NFS服务器上/nfs/data/storageclass
路径下是否也新增同样的文件。
Pod PV PVC and StorageClass
- 一个Pod可以使用多个PVC,一个PVC也可以给多个Pod使用
- 一个PVC只能绑定一个使用StorageClass创建的PV或者直接绑定一个提前创建好的PV,一个PV只能对应一种后端存储
- 对于手动的情况,一般我们会创建很多的PV,等有PVC需要使用的时候就可以直接使用了
- 对于自动的情况,那么就由StorageClass来自动管理创建PV
- 如果Pod想要使用共享存储,比如NFS,一般会创建PVC,PVC中描述了想要什么类型的后端存储、空间等,K8s从而会匹配对应的PV,如果没有匹配成功,Pod就会处于Pending状态。Pod中使用只需要像使用volumes一样,指定名字就可以使用了
- K8S集群管理员负责创建PV并进行管理,K8S用户负责创建PVC,并按照需求使用PV
评论区