# K8s 持久化存储
# 1. Volume
Container(容器)中的磁盘文件是短暂的,当容器崩溃时,kubelet 会重新启动容器,Container 会以最干净的状态启动,最初的文件将丢失。另外,当一个 Pod 运行多个 Container 时,各个容器可能需要共享一些文件。Kubernetes Volume 可以解决这两个问题。
- 一些需要持久化数据的程序才会用到 Volumes,或者一些需要共享数据的容器需要 volumes。
- 日志收集的需求需要在应用程序的容器里面加一个 sidecar,这个容器是一个收集日志的容器,比如 filebeat,它通过 volumes 共享应用程序的日志文件目录。
# 1.1 EmptyDir 实现数据共享
和上述 volume 不同的是,如果删除 Pod,emptyDir 卷中的数据也将被删除,一般 emptyDir 卷用于 Pod 中的不同 Container 共享数据。
# cat nginx-deploy.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deploy
labels:
app: nginx-deploy
namespace: default
spec:
selector:
matchLabels:
app: nginx-deploy
replicas: 1
template:
metadata:
labels:
app: nginx-deploy
spec:
restartPolicy: Always
volumes:
- name: share-volume
emptyDir: {}
containers:
- name: nginx
image: nginx:latest
imagePullPolicy: IfNotPresent
resources:
limits:
memory: 1024Mi
cpu: 1
requests:
memory: 128Mi
cpu: 100m
volumeMounts:
- name: share-volume
mountPath: /opt
- name: nginx2
image: nginx:latest
imagePullPolicy: IfNotPresent
resources:
limits:
memory: 1024Mi
cpu: 1
requests:
memory: 128Mi
cpu: 100m
command:
- sh
- '-c'
- sleep 3600
volumeMounts:
- name: share-volume
mountPath: /mnt
# 1.2 Volumes HostPath 挂载宿主机路径
hostPath 卷可将节点上的文件或目录挂载到 Pod 上,用于 Pod 自定义日志输出或访问 Docker 内部的容器等。
[root@k8s-master01 ~]# cat nginx-deploy.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deploy
labels:
app: nginx-deploy
namespace: default
spec:
selector:
matchLabels:
app: nginx-deploy
replicas: 1
template:
metadata:
labels:
app: nginx-deploy
spec:
restartPolicy: Always
volumes:
- name: share-volume
emptyDir: {}
- name: tz-config
hostPath:
path: /usr/share/zoneinfo/Asia/Shanghai
type: ""
- name: timezone
hostPath:
path: /etc/timezone
type: ""
containers:
- name: nginx
image: nginx:latest
imagePullPolicy: IfNotPresent
resources:
limits:
memory: 1024Mi
cpu: 1
requests:
memory: 128Mi
cpu: 100m
volumeMounts:
- name: share-volume
mountPath: /opt
- name: tz-config
mountPath: /usr/share/zoneinfo/Asia/Shanghai
- name: tz-config
mountPath: /etc/localtime
- name: timezone
mountPath: /etc/timezone
- name: nginx2
image: nginx:latest
imagePullPolicy: IfNotPresent
resources:
limits:
memory: 1024Mi
cpu: 1
requests:
memory: 128Mi
cpu: 100m
command:
- sh
- '-c'
- sleep 3600
volumeMounts:
- name: share-volume
mountPath: /mnt
hostPath 卷常用的 type(类型)如下:
- type 为空字符串:默认选项,意味着挂载 hostPath 卷之前不会执行任何检查。
- DirectoryOrCreate:如果给定的 path 不存在任何东西,那么将根据需要创建一个权限为 0755 的空目录,和 Kubelet 具有相同的组和权限。
- Directory:目录必须存在于给定的路径下。
- FileOrCreate:如果给定的路径不存储任何内容,则会根据需要创建一个空文件,权限设置为 0644,和 Kubelet 具有相同的组和所有权。
- File:文件,必须存在于给定路径中。
- Socket:UNIX 套接字,必须存在于给定路径中。
- CharDevice:字符设备,必须存在于给定路径中。
- BlockDevice:块设备,必须存在于给定路径中。
# 1.3 挂载 NFS 至容器
#1.安装nfs
# yum install nfs-utils -y
# mkdir /data/nfs -p
# vim /etc/exports
/data 192.168.1.0/24(rw,no_root_squash)
# exportfs -arv
# systemctl start nfs-server && systemctl enable nfs-server && systemctl status nfs-server
#2.测试客户端挂载
# showmount -e 192.168.1.75
# mount -t nfs 192.168.1.75:/data/nfs /mnt
#3.Deploy挂载NFS
[root@k8s-master01 ~]# cat nginx-deploy-nfs.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deploy
labels:
app: nginx-deploy
annotations:
app: nginx-deploy
namespace: default
spec:
selector:
matchLabels:
app: nginx-deploy
replicas: 1
template:
metadata:
labels:
app: nginx-deploy
annotations:
app: nginx-deploy
spec:
restartPolicy: Always
volumes:
- name: nfs-volume
nfs:
server: 192.168.1.75
path: /data/nfs
- name: tz-config
hostPath:
path: /usr/share/zoneinfo/Asia/Shanghai
type: ""
- name: timezone
hostPath:
path: /etc/timezone
type: ""
containers:
- name: nginx-deploy
image: nginx:latest
imagePullPolicy: IfNotPresent
resources:
limits:
memory: 1024Mi
cpu: 1
requests:
memory: 128Mi
cpu: 100m
volumeMounts:
- name: nfs-volume
mountPath: /usr/share/nginx/html
- name: tz-config
mountPath: /usr/share/zoneinfo/Asia/Shanghai
- name: tz-config
mountPath: /etc/localtime
- name: timezone
mountPath: /etc/timezone
# 2. PV、PVC
PersistentVolume:简称 PV,是由 Kubernetes 管理员设置的存储,可以配置 Ceph、NFS、GlusterFS 等常用存储配置,相对于 Volume 配置,提供了更多的功能,比如生命周期的管理、大小的限制。PV 分为静态和动态。
PersistentVolumeClaim:简称 PVC,是对存储 PV 的请求,表示需要什么类型的 PV,需要存储的技术人员只需要配置 PVC 即可使用存储,或者 Volume 配置 PVC 的名称即可。
# 2.1 PV 回收策略
- Retain:保留,该策略允许手动回收资源,当删除 PVC 时,PV 仍然存在,PV 被视为已释放,管理员可以手动回收卷。
- Recycle:回收,如果 Volume 插件支持,Recycle 策略会对卷执行 rm -rf 清理该 PV,并使其可用于下一个新的 PVC,但是本策略将来会被弃用,目前只有 NFS 和 HostPath 支持该策略。
- Delete:删除,如果 Volume 插件支持,删除 PVC 时会同时删除 PV,动态卷默认为 Delete,目前支持 Delete 的存储后端包括 AWS EBS, GCE PD, Azure Disk, or OpenStack Cinder 等。
- 可以通过 persistentVolumeReclaimPolicy: Recycle 字段配置
# 2.2 PV 访问策略
- ReadWriteOnce:可以被单节点以读写模式挂载,命令行中可以被缩写为 RWO。
- ReadOnlyMany:可以被多个节点以只读模式挂载,命令行中可以被缩写为 ROX。
- ReadWriteMany:可以被多个节点以读写模式挂载,命令行中可以被缩写为 RWX。
- ReadWriteOncePod :只允许被单个 Pod 访问,需要 K8s 1.22 + 以上版本,并且是 CSI 创建的 PV 才可使用,缩写为 RWOP
Volume Plugin | ReadWriteOnce | ReadOnlyMany | ReadWriteMany | ReadWriteOncePod |
---|---|---|---|---|
AzureFile | ✓ | ✓ | ✓ | - |
CephFS | ✓ | ✓ | ✓ | - |
CSI | depends on the driver | depends on the driver | depends on the driver | depends on the driver |
FC | ✓ | ✓ | - | - |
FlexVolume | ✓ | ✓ | depends on the driver | - |
HostPath | ✓ | - | - | - |
iSCSI | ✓ | ✓ | - | - |
NFS | ✓ | ✓ | ✓ | - |
RBD | ✓ | ✓ | - | - |
VsphereVolume | ✓ | - | - (works when Pods are collocated) | - |
PortworxVolume | ✓ | - | ✓ | - |
# 2.3 存储分类
- 文件存储:一些数据可能需要被多个节点使用,比如用户的头像、用户上传的文件等,实现方式:NFS、NAS、FTP、CephFS 等。
- 块存储:一些数据只能被一个节点使用,或者是需要将一块裸盘整个挂载使用,比如数据库、Redis 等,实现方式:Ceph、GlusterFS、公有云。
- 对象存储:由程序代码直接实现的一种存储方式,云原生应用无状态化常用的实现方式,实现方式:一般是符合 S3 协议的云存储,比如 AWS 的 S3 存储、Minio、七牛云等。
# 2.4 PV 配置示例 NFS
apiVersion: v1
kind: PersistentVolume
metadata:
name: nfs-pv1
spec:
capacity:
storage: 5Gi
volumeMode: Filesystem
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Retain
storageClassName: nfs-slow
nfs:
path: /data/pv1
server: 192.168.1.75
capacity:容量配置
volumeMode:卷的模式,目前支持 Filesystem(文件系统) 和 Block(块),其中 Block 类型需要后端存储支持,默认为文件系统
accessModes:该 PV 的访问模式
storageClassName:PV 的类,一个特定类型的 PV 只能绑定到特定类别的 PVC;
persistentVolumeReclaimPolicy:回收策略
mountOptions:非必须,新版本中已弃用
nfs:NFS 服务配置,包括以下两个选项
- path:NFS 上的共享目录
- server:NFS 的 IP 地址
# 2.5 PV 配置示例 HostPath
apiVersion: v1
kind: PersistentVolume
metadata:
name: hostpath
spec:
capacity:
storage: 5Gi
volumeMode: Filesystem
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Retain
storageClassName: hostpath
hostPath:
path: "/mnt/data"
hostPath:hostPath 服务配置
- path:宿主机路径
# 2.6 PV 的状态
- Available:可用,没有被 PVC 绑定的空闲资源。
- Bound:已绑定,已经被 PVC 绑定。
- Released:已释放,PVC 被删除,但是资源还未被重新使用。
- Failed:失败,自动回收失败。
# 2.7 PVC 绑定 PV
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: nfs-pvc
spec:
storageClassName: nfs-slow
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 5Gi
- PVC 的空间申请大小≤PV 的大小
- PVC 的 StorageClassName 和 PV 的一致
- PVC 的 accessModes 和 PV 的一致
# 2.8 Depoyment 挂载 PVC
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: nginx-deploy
name: nginx-deploy
spec:
replicas: 3
selector:
matchLabels:
app: nginx-deploy
template:
metadata:
labels:
app: nginx-deploy
spec:
volumes:
- name: nfs-pvc-storage #volume名称
persistentVolumeClaim:
claimName: nfs-pvc #PVC名称
containers:
- image: nginx
name: nginx
volumeMounts:
- name: nfs-pvc-storage
mountPath: /usr/share/nginx/html
挂载 PVC 的 Pod 一直处于 Pending:
- PVC 没有创建成功或 PVC 不存在
- PVC 和 Pod 不在同一个 Namespace