• Post author:
  • Post category:Kubernetes
  • Post comments:0评论
基于 Kubernetes 1.22 版本

一、基础概念

  我们知道 Pod 是由容器组成的,当容器宕机或停止之后数据就会随之丢失。这可能会给在容器中运行的应用程序带来了一些问题,例如,当容器崩溃时由 kubelet 重新启动的容器是一个全新的,之前的文件数据都丢失了。对于这种情况我们可以使用 Volume(卷)来解决。
  Kubernetes 支持多种类型的卷,一个 Pod 可以同时使用任意数量的卷。
  官方文档:https://kubernetes.io/docs/concepts/storage/volumes/

二、卷类型

  卷的类型有很多,例如 emptyDir、hostPath、NFS、分布式存储(ceph、glasterfs)、云存储(AWS EBS)等,下面就简单介绍几种。

1、emptyDir

  emptyDir 类型卷是在 Pod 分配到 Node 时创建的。顾名思义,它的初始内容为空,并且无须指定宿主机上对应的目录文件,因为这是 Kubernetes 自动分配的一个目录,当 Pod 从 Node 上移除时,emptyDir 中的数据也会被永久删除。
  注意容器崩溃不会从节点上移除 Pod,所以 emptyDir 卷中的数据在容器崩溃时是安全的。
  emptyDir 一些用途:

• 临时空间,例如用于某些应用程序运行时所需的临时目录,且无须永久保留。
• 长时间任务的中间过程检查点的临时保存目录,以便能从从崩溃中快速恢复
• 一个容器需要从另一个容器中获取数据的目录(多容器共享目录〉 

  根据你的环境,emptyDir 卷可以存储在支持节点的任何介质上,例如hdd、sdd、网络存储。
  我们也可以将 emptyDir.medium 字段设置为 "Memory",这样 Kubernetes 会挂载一个 tmpfs(内存文件系统)。虽然 tmpfs 非常快,但是与磁盘不同,tmpfs 在节点重新启动时会被清除,并且写入的任何文件都计入容器的内存限制中。
  示例,如下创建一个 Pod 并创建一个emptyDir 卷挂载到容器的 /cache 目录上,并10秒模拟一次崩溃,看写入的数据是否还在。

[root@master volume]# vim pod-emptydir.yaml
apiVersion: v1
kind: Pod
metadata:
  name: pod-emptydir
spec:
  containers:
  - name: test-container
    image: busybox
    imagePullPolicy: IfNotPresent
    command: [ "/bin/sh", "-c", "echo 'test' >> /cache/1.txt;sleep 10" ]
    volumeMounts:
    - mountPath: /cache
      name: cache-volume
  volumes:
  - name: cache-volume
    emptyDir: {}
  restartPolicy: Always

[root@master volume]# kubectl apply -f pod-emptydir.yaml
pod/pod-emptydir created
[root@master volume]# kubectl get pods
NAME           READY   STATUS    RESTARTS   AGE
pod-emptydir   1/1     Running   0          2s
[root@master volume]# kubectl exec pod-emptydir -- cat /cache/1.txt
test
[root@master volume]# kubectl describe pod pod-emptydir
......
  Normal   Created    16s (x2 over 27s)  kubelet            Created container test-container
  Normal   Started    16s (x2 over 27s)  kubelet            Started container test-container
......
[root@master volume]# kubectl exec pod-emptydir -- cat /cache/1.txt
test
test

2、hostPath

  hostPath 类型用于挂载宿主机上的文件或目录到 Pod 上。
  官方建议是 HostPath 卷存在许多安全风险,最佳做法是尽可能避免使用 HostPath。当必须使用 HostPath 卷时,它的范围应仅限于所需的文件或目录,并以只读方式挂载。
  而且我们要知道的是在不同的 Node 上具有相同配置(例如从 PodTemplate 创建)的 Pod 可能会因为宿主机上的目录和文件不同而导致对 Volume 上目录和文件的访问结果不一致。
  如果要挂载的文件或目录只能由 root 用户写入,那需要在特权容器中以 root 身份运行进程,或者修改主机上的文件权限才能写入 hostPath 卷中。
  在使用 hostPath 卷时,可以设置 type 字段,支持的类型有以下几种:

类型 含义
空字符串(默认)是为了向后兼容,这意味着在挂载 hostPath 卷之前不会执行任何检查。
DirectoryOrCreate 如果给定路径中不存在任何内容,则会根据需要在那里创建一个空目录,其权限设置为 0755,与 Kubelet 具有相同的组和所有权。
Directory 给定路径中必须存在目录
FileOrCreate 如果给定路径中不存在任何内容,则会根据需要在那里创建一个空文件,其权限设置为 0644,与 Kubelet 具有相同的组和所有权。
File 文件必须存在于给定路径
Socket 给定路径中必须存在 UNIX 套接字
CharDevice 字符设备必须存在于给定的路径中
BlockDevice 块设备必须存在于给定的路径

示例:

[root@master volume]# vim pod-hostpath.yaml
apiVersion: v1
kind: Pod
metadata:
  name: pod-hostpath
spec:
  containers:
  - name: test-container
    image: nginx
    imagePullPolicy: IfNotPresent
    volumeMounts:
    - mountPath: /usr/share/nginx/html/
      name: html
  volumes:
  - name: html
    hostPath:
      path: /data
      type: DirectoryOrCreate

[root@master volume]# kubectl apply -f pod-hostpath.yaml 
pod/pod-hostpath created
[root@master volume]# kubectl get pod -o wide
NAME           READY   STATUS    RESTARTS   AGE   IP             NODE    NOMINATED NODE   READINESS GATES
pod-hostpath   1/1     Running   0          11s   10.244.2.188   node2   <none>           <none>
[root@master volume]# curl 10.244.2.188
<html>
<head><title>403 Forbidden</title></head>
<body>
<center><h1>403 Forbidden</h1></center>
<hr><center>nginx/1.21.4</center>
</body>
</html>
[root@master volume]# kubectl exec pod-hostpath -- /bin/bash -c "echo 'test' > /usr/share/nginx/html/index.html"
[root@master volume]# curl 10.244.2.188
test

[root@node2 data]# ll
total 4
-rw-r--r-- 1 root root 5 Dec  2 19:25 index.html
[root@node2 data]# cat index.html 
test

3、NFS

  NFS 类型卷用于将现有 NFS(网络文件系统)挂载到 Pod 中。当从节点移除 Pod 时,与会擦除的 emptyDir 卷不同,NFS 卷的内容会被保留仅仅只是卸载。这意味着 nfs 卷可以预先填充数据,并且数据可以在 Pod 之间共享,也可以同时被多个 Pod 挂载并进行读写。

示例:
部署 NFS 服务:

[root@master ~]# yum install -y nfs-utils
[root@master ~]# mkdir /data
[root@master ~]# echo "NFS" > /data/index.html
[root@master ~]# echo "/data *(rw,no_root_squash)" > /etc/exports
[root@master ~]# systemctl restart nfs rpcbind
[root@master ~]# showmount -e localhost
Export list for localhost:
/data *

使用 NFS 卷(注意 node 节点都要安装 nfs-utils ):

[root@master volume]# cat deployment-nfs.yaml 
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  labels:
    app: nginx
spec:
  replicas: 3       
  selector:  
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx
        ports:
        - containerPort: 80
        volumeMounts:
        - mountPath: /usr/share/nginx/html/
          name: nfs
      volumes:
        - name: nfs
          nfs:
            path: /data
            server: 10.0.0.100

[root@master volume]# kubectl apply -f deployment-nfs.yaml
[root@master volume]# kubectl get pod -o wide
NAME                                READY   STATUS    RESTARTS   AGE   IP             NODE    NOMINATED NODE   READINESS GATES
nginx-deployment-5dd4fcd6bf-6wb5k   1/1     Running   0          38s   10.244.2.195   node2   <none>           <none>
nginx-deployment-5dd4fcd6bf-n7psj   1/1     Running   0          38s   10.244.2.196   node2   <none>           <none>
nginx-deployment-5dd4fcd6bf-t42mz   1/1     Running   0          38s   10.244.1.107   node1   <none>           <none>
[root@master volume]# curl 10.244.2.195
NFS
[root@master volume]# curl 10.244.2.196
NFS
[root@master volume]# curl 10.244.1.107
NFS
[root@master volume]# echo NFS-test > /data/index.html 
[root@master volume]# curl 10.244.1.107 10.244.2.196 10.244.1.107
NFS-test
NFS-test
NFS-test

参考文章:

https://kubernetes.io/docs/
《Kubernetes 权威指南》

发表评论

验证码: 2 + 5 =