介绍

kubernetes 集群不会为你处理数据的存储,我们可以为数据库挂载一个磁盘来确保数据的安全。
你可以选择云存储、本地磁盘、NFS。

  • 本地磁盘:可以挂载某个节点上的目录,但是这需要限定 pod 在这个节点上运行
  • 云存储:不限定节点,不受集群影响,安全稳定;需要云服务商提供,裸机集群是没有的。
  • NFS:不限定节点,不受集群影响
  • emptyDir:主要用于某些应用程序无需永久保存的临时目录,多个容器的共享目录等,生产一般不使用

存储卷架构

image.png

为什么要这么多层抽象

  • 更好的分工,运维人员负责提供好存储,开发人员不需要关注磁盘细节,只需要写一个申请单。
  • 方便云服务商提供不同类型的,配置细节不需要开发者关注,只需要一个申请单。
  • 动态创建,开发人员写好申请单后,供应商可以根据需求自动创建所需存储卷。

NFS存储卷示例

安装NFS

  1. # 所有k8s节点安装nfs-utils
  2. $ yum install -y nfs-utils rpcbind
  3. # 在192.168.0.240上创建nfs目录
  4. $ mkdir -p /data/nfs
  5. # 更改归属组与用户
  6. $ chown -R nfsnobody:nfsnobody /data/nfs
  7. # 配置nfs
  8. $ cat /etc/exports
  9. /data/nfs 192.168.0.0/24(rw,async,no_root_squash)
  10. # 启动nfs服务并设置开机启动
  11. $ systemctl start nfs
  12. $ systemctl enable nfs
  13. # 验证
  14. $ showmount -e
  15. Export list for k8s.lechuang.com:
  16. /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