介绍
kubernetes 集群不会为你处理数据的存储,我们可以为数据库挂载一个磁盘来确保数据的安全。
你可以选择云存储、本地磁盘、NFS。
- 本地磁盘:可以挂载某个节点上的目录,但是这需要限定 pod 在这个节点上运行
- 云存储:不限定节点,不受集群影响,安全稳定;需要云服务商提供,裸机集群是没有的。
- NFS:不限定节点,不受集群影响
- emptyDir:主要用于某些应用程序无需永久保存的临时目录,多个容器的共享目录等,生产一般不使用。
存储卷架构

为什么要这么多层抽象
- 更好的分工,运维人员负责提供好存储,开发人员不需要关注磁盘细节,只需要写一个申请单。
- 方便云服务商提供不同类型的,配置细节不需要开发者关注,只需要一个申请单。
- 动态创建,开发人员写好申请单后,供应商可以根据需求自动创建所需存储卷。
NFS存储卷示例
安装NFS
# 所有k8s节点安装nfs-utils$ yum install -y nfs-utils rpcbind# 在192.168.0.240上创建nfs目录$ mkdir -p /data/nfs# 更改归属组与用户$ chown -R nfsnobody:nfsnobody /data/nfs# 配置nfs$ cat /etc/exports/data/nfs 192.168.0.0/24(rw,async,no_root_squash)# 启动nfs服务并设置开机启动$ systemctl start nfs$ systemctl enable nfs# 验证$ showmount -eExport list for k8s.lechuang.com:/data/nfs 192.168.0.0/24
创建NFS Storage Class(SC)
为了简单,我们使用helm创建
# 添加helm charts
$ helm repo add nfs-subdir-external-provisioner https://kubernetes-sigs.github.io/nfs-subdir-external-provisioner/
$ helm repo update
$ helm install nfs-subdir-external-provisioner nfs-subdir-external-provisioner/nfs-subdir-external-provisioner \
--set storageClass.name=nfs-client \
--set storageClass.defaultClass=true \
--set nfs.server=192.168.0.240 \ # nfs server地址
--set nfs.path=/data/nfs # nfs server目录
# 查看是否创建成功
$ kubectl get sc
NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE
nfs-client (default) cluster.local/nfs-subdir-external-provisioner Delete Immediate true 3d20h
创建Persistent Volume (PV)
描述卷的具体信息,例如磁盘大小,访问模式,文档,类型
apiVersion: v1
kind: PersistentVolume
apiVersion: v1
metadata:
name: nfs-pv-volume
namespace: demo
spec:
capacity:
storage: 1Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Recycle
storageClassName: nfs
nfs:
server: 192.168.0.240
path: /data/nfs
使用NFS Storage Class创建PVC
对存储需求的一个申明,可以理解为一个申请单,系统根据这个申请单去找一个合适的 PV
还可以根据 PVC 自动创建 PV。
nfs-pv-claim.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: nfs-pv-claim
namespace: demo
spec:
storageClassName: nfs-client # 指定我们上一步创建的NFS Storage Class
accessModes:
- ReadWriteOnce # 卷可以被一个节点以读写方式挂载
resources:
requests:
storage: 1Gi
应用yaml
$ kubectl apply -f nfs-pv-claim.yaml
$ kubectl get pvc -n demo
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
nfs-pv-claim Bound pvc-dfc45458-489b-4055-82d3-9ef95ce2fb4f 1Gi RWO nfs-client 6s
更新redis配置,增加数据卷挂载
redis-statefulset.yaml
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: redis
namespace: redis
spec:
replicas: 2 # 默认是一主一从
selector:
matchLabels:
app: redis
serviceName: redis
template:
metadata:
labels:
app: redis
spec:
containers:
- name: redis
image: redis:5
imagePullPolicy: IfNotPresent
command:
- /bin/sh
- -c
- |
set -e
hostname=$(echo `hostname` | grep -oE '\-([0-9]+)$')
if [ "$hostname" != "-0" ]; then #如果不是第一个节点,则向第一个节点同步
redis-server /etc/redis.conf slaveof redis-0.redis.redis.svc.cluster.local 6379
else
redis-server /etc/redis.conf
fi
volumeMounts:
- name: redis-data
mountPath: /data
- name: redis-conf
mountPath: /etc/redis.conf
subPath: redis.conf
volumes:
- name: redis-conf
configMap:
name: redis
volumeClaimTemplates:
- metadata:
name: redis-data
namespace: redis
spec:
accessModes: ["ReadWriteMany"] # 卷可以被多个节点以读写方式挂载
storageClassName: nfs-client # 指定我们上一步创建的NFS Storage Class
resources:
requests:
storage: 500Mi # 卷的容量
应用yaml
$ kubectl apply -f redis-statefulset.yaml
$ kubectl get pod -n demo
NAME READY STATUS RESTARTS AGE
redis-0 1/1 Running 0 60s
redis-1 1/1 Running 0 57s
# 可以看到自动创建了两个就nfs-client的pvc,会自动挂载到对应的pod
$ kubectl get pvc -n demo
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
redis-data-redis-0 Bound pvc-796256a6-f82c-40b1-975a-ee82073695e4 500Mi RWX nfs-client 2m3s
redis-data-redis-1 Bound pvc-9dd325f6-2788-41b2-82e6-251e14596e41 500Mi RWX nfs-client 79s
