持久化存储

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上,可以通过标签选择器来实现,这里就不多介绍了。

作者:Gacfox
版权声明:本网站为非盈利性质,文章如非特殊说明均为原创,版权遵循知识共享协议CC BY-NC-ND 4.0进行授权,转载必须署名,禁止用于商业目的或演绎修改后转载。