跳至主要內容

k8s资源存储

xw大约 10 分钟k8s

概述

Volume(卷)是k8s抽象出来的对象,它被定义在Pod上,然后被一个Pod里的多个容器挂载到具体的文件目录下,kubernetes通过Volume实现同一个Pod中不同容器之间的数据共享以及数据的持久化存储,Volume的生命周期不与Pod中单个容器的生命周期相关,当容器终止或者重启时,Volume中的数据也不会丢失。K8S可以支持许多类型的卷,Pod 也能同时使用任意数量的卷。

Volume常见的类型:

  • 常规存储:EmptyDir、HostPath
  • 高级存储:PV、PVC
  • 配置存储:ConfigMap、Secret
  • 其他:网络存储系统 NFS、CIFS,包括云服务商提供的、本地、分布式

常见卷类型

EmptyDir

当 Pod 分派到某个 Node 上时,emptyDir 卷会被创建,并且在 Pod 在该节点上运行期间,卷一直存在。 就像其名称表示的那样,卷最初是空的。 尽管 Pod 中的容器挂载 emptyDir 卷的路径可能相同也可能不同,这些容器都可以读写 emptyDir 卷中相同的文件。 当 Pod 因为某些原因被从节点上删除时,emptyDir 卷中的数据也会被永久删除。

emptyDir 的一些用途:

  • 缓存空间,例如基于磁盘的归并排序。
  • 为耗时较长的计算任务提供检查点,以便任务能方便地从崩溃前状态恢复执行。
  • 在 Web 服务器容器服务数据时,保存内容管理器容器获取的文件。

示例:

  • 编辑volume-emptydir.yaml,添加以下内容:

    apiVersion: v1
    kind: Pod
    metadata:
      name: volume-emptydir
      namespace: dev
    spec:
      containers:
      - name: nginx
        image: nginx:1.20
        ports:
        - containerPort: 80
        volumeMounts:  # 将nginx-log-volume挂在到nginx容器中,对应的目录为 /var/log/nginx
        - name: nginx-log-volume
          mountPath: /var/log/nginx
    
      - name: busybox
        image: busybox:1.35.0 
        command: ["/bin/sh","-c","tail -f /usr/local/test/access.log"] # 容器启动后初始命令,读取指定文件中内容
        volumeMounts:  # 将nginx-log-volume挂在到busybox容器中,对应的目录为 /logs
        - name: nginx-log-volume
          mountPath: /usr/local/test
    
      volumes: # 这里声明volume存储劵, name为nginx-log-volume,类型是emptyDir
      - name: nginx-log-volume
        emptyDir: {}
    
    
  • 执行以下命令

    kubectl apply -f volume-emptydir.yaml
    ## 查看
    kubectl get pods -n dev -o wide
    
    #访问nignx 产生访问日志
    curl ip
    
    ##查看busybox日志
    kubectl logs -f volume-emptydir -n dev -c busybox
    
    

  • 删除

    kubectl delete -f volume-emptydir.yaml
    

HostPath

emptyDir中数据没做持久化,随着Pod的结束而销毁,需要持久化到磁盘则选其他方式,hostPath类型的磁盘就是挂在了主机的一个文件或者目录。hostPath有以下几个类型:

描述
DirectoryOrCreate如果在给定路径上什么都不存在,那么将根据需要创建空目录,权限设置为 0755,具有与 kubelet 相同的组和属主信息。
Directory在给定路径上必须存在的目录。
FileOrCreate如果在给定路径上什么都不存在,那么将在那里根据需要创建空文件,权限设置为 0644,具有与 kubelet 相同的组和所有权。
File在给定路径上必须存在的文件。
Socket在给定路径上必须存在的 UNIX 套接字。
CharDevice在给定路径上必须存在的字符设备。
BlockDevice在给定路径上必须存在的块设备。
空值不执行任何检查

示例:

  • 编辑volume-hostpath.yaml,添加以下内容:
apiVersion: v1
kind: Pod
metadata:
  name: volume-hostpath
  namespace: dev
spec:
  containers:
  - name: nginx
    image: nginx:1.20
    ports:
    - containerPort: 80
    volumeMounts:  # 将nginx-log-volume挂在到nginx容器中,对应的目录为 /var/log/nginx
    - name: nginx-log-volume
      mountPath: /var/log/nginx

  - name: busybox
    image: busybox:1.35.0 
    command: ["/bin/sh","-c","tail -f /usr/local/test/access.log"] # 容器启动后初始命令,读取指定文件中内容
    volumeMounts:  # 将nginx-log-volume挂在到busybox容器中,对应的目录为 /logs
    - name: nginx-log-volume
      mountPath: /usr/local/test

  volumes: # 这里声明volume存储劵, name为nginx-log-volume,类型是emptyDir
  - name: nginx-log-volume
    hostPath:
      path: /data/test
      type: DirectoryOrCreate

  • 执行以下命令
kubectl apply -f volume-hostpath.yaml

## 查看
kubectl get pods -n dev -o wide

#访问nignx 产生访问日志
curl ip

##查看busybox日志
kubectl logs -f volume-hostpath -n dev -c busybox

  • 删除

    kubectl delete -f volume-hostpath.yaml
    

ConfigMap

ConfigMap 是 Kubernetes 用来向应用 Pod 中注入配置数据的方法,可以用作环境变量、命令行参数等,将环境变量、配置信息和容器镜像解耦,便于应用配置的修改。

  • 编辑configmap.yaml

    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: configmap
      namespace: dev
    data:
      info: 
        username:xdclass
        password:123456
    
  • 执行

    #创建
    kubectl create -f configmap.yaml
    
    
    # 查看configmap详情
    kubectl describe cm configmap -n dev
    
  • 创建pod-configmap.yaml

    apiVersion: v1
    kind: Pod
    metadata:
      name: pod-configmap
      namespace: dev
    spec:
      containers:
      - name: nginx
        image: nginx:1.20
        volumeMounts: # configmap挂载的目录
        - name: config
          mountPath: /config
    
      volumes: # 声明configmap
      - name: config
        configMap:
          name: configmap
    
  • 执行

    kubectl exec -it pod-configmap -n dev -- /bin/sh
    cd /config
    cat info
    

Secret

有些配置需要加密存储,ConfigMap只能使用明文保存,因此不适合,Secret用来保存敏感信息,例如密码、秘钥、证书、OAuth 令牌和 ssh key等。

  • 创建secret.yaml

    apiVersion: v1
    kind: Secret
    metadata:
      name: mysecret
    type: Opaque
    data:
      username: YWRtaW4=
      password: MTIzNDU2
    
  • 命令

    #创建
    kubectl apply -f secret.yaml 
    
    # 查看secret的信息
    kubectl get secret
    
    # 查看mysecret详细信息
    kubectl get secret mysecret -o yaml
    
  • 创建 pod-secret-volume.yaml

    apiVersion: v1
    kind: Pod
    metadata:
      name: pod-secret
    spec:
      containers:
      - name: nginx
        image: nginx:1.20
        volumeMounts: # secret挂载
        - name: config
          mountPath: /etc/secret
      volumes:
      - name: config
        secret:
          secretName: mysecret
          
    
  • 执行命令:

    kubectl exec -it pod-secret -- /bin/sh
    #ls /etc/secret
    #cat /etc/secret/username
    #cat /etc/secret/password
    

在pod容器中查看数据已经被解密。

NFS

部署NFS

  • 下载nfs-util (对应要用到的节点都需要安装,但是不需要启动)

    yum install nfs-utils -y
    
  • 创建目录(nfs服务器执行)

    #目录可以自定义
    mkdir /opt/nfsdata
    #给路径授权
    chmod 777 /opt/nfsdata
    
  • 编辑/etc/exports 配置文件(nfs服务器执行)

    vim /etc/exports
    # 目录的读写权限暴露给这个网段的全部主机
    /opt/nfsdata 192.168.0.0/24(rw,insecure,sync)
    
    解释
       172.31.101.0/24表示的IP范围, 换成32位二进制,四组,每组8位
       /24 表示前24位不变,后8位由全0变化到全1的过程,也就是由“00000000”变化到“11111111”
        又因为全0是子网网络地址,全1是子网广播地址,这两个地址是不分配给主机使用的。
        所以有效的可分配的范围是前24位不变,后8位由“00000001”变化为“11111110”的范围
        再转换回十进制就是172.31.101.1~172.31.101.254
    
    • 参数
      • rw 共享目录可读可写
      • secure 限制客户端只能从小于1024的tcp/ip端口连接服务器;
      • insecure允许客户端从大于1024的tcp/ip端口连接服务器;
      • sync 将数据同步写入内存缓冲区与磁盘中,效率低,但可以保证数据的一致性;
      • async 将数据先保存在内存缓冲区中,必要时才写入磁盘;
  • 启动rpcbind(安装nfs依赖包会自动下载)和nfs服务

    systemctl start rpcbind
    
    systemctl start nfs
    
  • 验证

    • showmount -e localhost

    使用

  • 创建pod挂载nfs,创建文件pod-nfs.yaml

    apiVersion: v1
    kind: Pod
    metadata:
      name: pod-nfs
      namespace: dev
      labels: 
        apps: nginx-nfs
    spec:
      containers:
      - name: nginx
        image: nginx:1.20
        ports:
        - containerPort: 80
        volumeMounts:
        - name: logs-volume
          mountPath: /var/log/nginx
      volumes:
      - name: logs-volume
        nfs:
          server: 192.168.0.112  #nfs服务器地址
          path: /opt/nfsdata #共享文件路径
    
  • 执行

    ## 执行命令
    kubectl apply -f pod-nfs.yaml 
    
    ## 暴露服务
    kubectl expose pod pod-nfs -n dev --port=80 --target-port=80 --type=NodePort
    

    访问nginx页面,可查到挂载目录产生了日志:

PV&PVC

PV 持久卷(Persistent Volume):是集群中由管理员配置的一段网络存储,它是集群的一部分资源和底层存储密切相关,对象包含存储实现的细节,即 对接NFS、CIFS等存储系统,不同的PV会对应到不用的存储资源,这样在部署pod的时候直接调用集群内部的pv即可,PV没有命名空间隔离概念.

PVC 持久卷声明 (Persistent Volume Claim): PVC是用户存储的一种声明, PVC 可以请求特定的存储空间和访问模式,PVC 消耗的是 PV 资源,PVC必须与对应的PV建立关系,PVC会根据定义的PV去申请,创建pod的时候会附带一个PVC的请求,PVC的请求相当于就是去寻找一个合适的pv。

PV 是集群中的【资源】,PVC 是对这些【资源的请求】

PV模板

apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv1
spec:
  capacity:
    storage: 5Gi #存储大小
  accessModes:#访问模式
    - ReadWriteOnce
  persistentVolumeReclaimPolicy: Recycle #回收策略
  storageClassName: slow #存储类别
  nfs:#卷插件
    path: /tmp
    server: 172.31.101.8
  • **存储大小:**存储大小是可以设置和请求的唯一资源。 未来可能会包含 IOPS、吞吐量等属性

  • 访问模式:用户对资源的访问权限

    • ReadWriteOnce(RWO):读写权限,只能被单个节点挂载
    • ReadOnlyMany(ROX): 只读权限,可以被多个节点挂载
    • ReadWriteMany(RWX):读写权限,可以被多个节点挂载
  • 存储类别:

    • 每个 PV 可以属于某个类,通过将其 storageClassName属性设置为某个 StorageClass 的名称来指定。
    • 特定类的 PV 卷只能绑定到请求该类存储卷的 PVC 申领。
    • 未设置 storageClassName 的 PV 卷没有类设定,只能给到那些没有指定特定 存储类的 PVC 申领。
  • 回收策略(当PV不再被使用了之后的处理策略)

    • 保留 Retain -- 当PV对象被删除之后,与之相关的位于外部的基础设施中的数据仍然存在(如nfs),需要根据实际情况手动回收

    • 回收 Recycle -- 相当于在卷上执行rm -rf /volume/* 操作,之后该卷可以用于新的pvc申领

    • 删除 Delete -- 当PV对象被删除之后,与之相关的位于外部的基础设施中的数据也被一并删除(如nfs),需要根据实际情况手动回收,更多是云厂商设备

  • 状态( PV 的生命周期有4种不同状态)

    • Available(可用)——一块空闲资源还没有被任何声明绑定
    • Bound(已绑定)——卷已经被声明绑定
    • Released(已释放)——声明被删除,但是资源还未被集群重新声明
    • Failed(失败)——该卷的自动回收失败

PVC模板

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: pvc1
  namespace: dev
spec:
  accessModes: # 访问模式
  - ReadWriteMany
  selector: # 采用label标签对PV选择过滤
  storageClassName: # 存储类别,设置对应的class的PV才能被系统选出
  resources: # 需要存储资源的请求
    requests:
      storage: 3Gi
使用
  • 创建目录

    mkdir /opt/nfsdata/pv1
    mkdir /opt/nfsdata/pv2
    chmod 777 /opt/nfsdata/pv1
    chmod 777 /opt/nfsdata/pv2
    
  • 修改配置文件

    vim /etc/exports
    #暴露nfs服务
    /opt/nfsdata/pv1 192.168.0.0/24(rw,insecure,sync)
    /opt/nfsdata/pv2 192.168.0.0/24(rw,insecure,sync)
    
  • 重启nfs

    systemctl restart nfs
    
  • 创建两个PV,编辑pv-1.yaml

    apiVersion: v1
    kind: PersistentVolume
    metadata:
      name: xw-pv1
    spec:
      capacity: 
        storage: 1Gi
      accessModes:
      - ReadWriteMany
      persistentVolumeReclaimPolicy: Retain
      nfs:
        server: 192.168.0.112
        path: /opt/nfsdata/pv1
        
    
    ---
    
    apiVersion: v1
    kind: PersistentVolume
    metadata:
      name: xw-pv2
    spec:
      capacity: 
        storage: 2Gi
      accessModes:
      - ReadWriteMany
      persistentVolumeReclaimPolicy: Retain
      nfs:
        server: 192.168.0.112
        path: /opt/nfsdata/pv2
    
  • 执行

    ## 启动
    kubectl apply -f pv-1.yaml
    
    ## 查看
    kubectl get pv -o wide
    
  • 创建PVC,使用pvc.yaml (与PV不同,PVC不属于集群资源,拥有自己的名称空间)

    apiVersion: v1
    kind: PersistentVolumeClaim
    metadata:
      name: xw-pvc1
      namespace: dev
    spec:
      accessModes: 
      - ReadWriteMany
      resources:
        requests:
          storage: 1Gi
    ---
    apiVersion: v1
    kind: PersistentVolumeClaim
    metadata:
      name: xw-pvc2
      namespace: dev
    spec:
      accessModes: 
      - ReadWriteMany
      resources:
        requests:
          storage: 3Gi
    
  • 执行

    kubectl apply -f pvc.yaml
    
    ## 查看PVC
    kubectl get pvc -o wide -n dev
    
    

​ 可以看到xw-pvc1已经与pv1绑定,xw-pvc2没有绑定,因为没有符合要求的PV,当手动起了一个容量大小为3g的PV时,绑定成功。

  • 创建POD挂载pvcpod-pvc.yaml

    apiVersion: v1
    kind: Pod
    metadata:
      name: pod1
      namespace: dev
    spec:
      containers:
      - name: busybox
        image: busybox
        command: ["/bin/sh","-c","while true;do echo hello xdclass pod1 >> /opt/print.txt; sleep 5; done;"]
        volumeMounts:
        - name: volume
          mountPath: /opt/
      volumes:
        - name: volume
          persistentVolumeClaim:
            claimName: xw-pvc2
            readOnly: false
    

    查看日志,发现挂载成功