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挂载pvc
pod-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
查看日志,发现挂载成功