持久化存储
k8s自动调度的Pod是一种短生命周期的组件,在进行滚动升级、扩缩容等操作时都会造成Pod的销毁和重新创建。那么如果我们需要持久化保存数据,比如用户上传的文件、应用程序日志等,此时就不能直接将数据放在Pod容器内了。
针对此问题,可以通过挂载外部的存储目录解决,k8s支持非常多种存储目录挂载方式,比较简单的方式就是直接挂载主机目录或NFS目录,更进一步,也可以通过k8s提供的PersistentVolume(PV)、PersistentVolumeClaim(PVC)组件来实现更为复杂的自动挂载。
直接挂载主机目录
挂载存储目录最简单的方式就是直接挂载当前节点主机的目录,下面是一个例子。
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deploy
labels:
k8s-app: nginx-demo
spec:
selector:
matchLabels:
app: nginx
replicas: 3
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.20
ports:
- containerPort: 80
volumeMounts:
- name: wwwroot
mountPath: /usr/share/nginx/html
volumes:
- name: wwwroot
hostPath:
path: /home/ubuntu
上面例子中,我们将Pod内/usr/share/nginx/html挂载到节点主机的/home/ubuntu目录。
当然,这种方式实际上不太常用,毕竟Pod部署的节点是随机选择的,hostPath这个路径却和节点相关。实际上,挂载NFS目录更常用。
直接挂载NFS目录
基于NFS实现持久化存储也比较简单,我们直接将NFS目录挂载到Pod内就行了。有关NFS服务的详细内容可以参考NFS相关章节。
注意:在具体挂载NFS目录之前,相关节点上必须安装NFS客户端,否则挂载时将报错。
下面是一个挂载NFS目录的例子。
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deploy
labels:
k8s-app: nginx-demo
spec:
selector:
matchLabels:
app: nginx
replicas: 3
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.20
ports:
- containerPort: 80
volumeMounts:
- name: wwwroot
mountPath: /usr/share/nginx/html
volumes:
- name: wwwroot
nfs:
server: 192.168.1.107
path: /home/ubuntu/nfs
上面例子中,我们将容器中的/usr/share/nginx/html挂载为NFS服务器192.168.1.107的/home/ubuntu/nfs目录。
基于NFS创建PV和PVC
直接挂载NFS目录,实际上我们需要手动指定IP、挂载路径,同样不方便维护。通过定义PV和PVC,我们可以实现存储资源的自动选择和挂载。
- PV(Persistent Volume):对存储资源的抽象
- PVC(Persistent Volumes Claim):申请存储资源的声明
下面是一个例子。
apiVersion: v1
kind: PersistentVolume
metadata:
name: my-pv
spec:
capacity:
storage: 5Gi
accessModes:
- ReadWriteMany
nfs:
server: 192.168.1.107
path: /home/ubuntu/nfs
上面配置定义了PV,其中依然是使用NFS作为底层存储。除此之外,还指定了其大小限制为5Gi。
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deploy
labels:
k8s-app: nginx-demo
spec:
selector:
matchLabels:
app: nginx
replicas: 3
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.20
ports:
- containerPort: 80
volumeMounts:
- name: wwwroot
mountPath: /usr/share/nginx/html
volumes:
- name: wwwroot
persistentVolumeClaim:
claimName: my-pvc
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: my-pvc
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 5Gi
这里定义了两个组件,一个是我们的应用程序,它需要挂载一个持久化的路径,但和之前不同,我们这里指定的是通过PVC方式,由k8s自动选择存储资源来挂载。之后配置定义了PVC,并指定需要5Gi大小的存储空间。
指定如上配置文件后,我们可以通过kubectl get pvc命令来查看相关情况。

可以看到,my-pvc自动绑定了my-pv这个存储资源,此时Pod也能够正常使用相关的存储资源了。
其实即使使用PV、PVC的方式我们也是需要手动指定NFS的IP和存储路径,但这样我们可以将维护PV的工作交给平台维护的运维人员,而负责应用部署的运维人员只需要维护PVC,这样划分比直接给容器挂载NFS目录要合理的多。
此外,前面的例子中,我们的PVC实际上是根据存储容量和权限自动匹配PV并绑定的。如果我们希望PVC绑定到指定PV上,可以通过标签选择器来实现,这里就不多介绍了。