简介

持久化存储是安装 KubeSphere 的必备条件。使用 KubeKey 搭建 KubeSphere 集群时,可以安装不同的存储系统作为插件。如果 KubeKey 检测到未指定默认存储类型,则将默认安装 OpenEBS。

同样使用Kubernetes部署我们自己的服务时,也需要为对应的pod挂载pv持久卷,以实现服务数据本地持久化 。

本章演示如何使用nfs文件系统,配置持久化k8s集群本地文件存储并通过StatefulSet动态为pod生成pv挂载。

往期文章参考:
01.使用 KubeKey 在Linux上预配置生产就绪的 Kubernetes 和 KubeSphere 集群

版本如下

名称版本
CentOS7.6+
Kubernetes1.23.8
KubeSphere3.3.1

主机分配

主机名称IP角色容器运行时容器运行时版本
master01192.168.0.3control plane, etcd, workerdocker19.3.8+
node01192.168.0.5workerdocker19.3.8+
node02192.168.0.7workerdocker19.3.8+
node03192.168.0.8workerdocker19.3.8+

1. 安装配置前置环境

1.1 安装nfs文件系统

1.1.1 安装nfs-server

# 集群每台主机执行以下命令,启动 nfs 服务;创建共享目录
 yum install -y nfs-utils
 mkdir -p /nfs/data
 
# 在master01 执行以下命令 可以根据实际情况选择硬盘存储量比较大的作为nfs服务器
 echo "/nfs/data/ *(rw,insecure,sync,no_subtree_check,no_root_squash)" > /etc/exports

# 在master01执行
 systemctl enable rpcbind
 systemctl enable nfs # systemctl enable nfs-server
 systemctl start rpcbind
 systemctl start nfs
 exportfs -r # 使配置生效
 exportfs #检查配置是否生效

# 指定网段共享可参考如下
# mkdir -p /data/volumes/{v1,v2,v3}
# 编辑master节点/etc/exports文件,将目录共享到192.168.0.0/24这个网段中(网段可根据自己环境来填写,exports文件需要在每台master节点上进行配置)
# vim /etc/exports
# /data/volumes/v1 192.168.0.0/24(rw,no_root_squash,no_all_squash)
# 发布
# exportfs -arv
# exporting 192.168.0.0/24:/data/volumes/v1
# 查看
# showmounte -e 
# Export list for master01:
# /data/volumes/v1 192.168.0.0/24

常见的参数则有:
**rw** read-write 读写
**ro** read-only 只读
**sync** 请求或写入数据时,数据同步写入到NFS server的硬盘后才返回。数据安全,但性能降低了
**async** 优先将数据保存到内存,硬盘有空档时再写入硬盘,效率更高,但可能造成数据丢失。
**root_squash**NFS 客户端使用root用户访问时,映射为NFS 服务端的匿名用户
**no_root_squash**NFS 客户端使用root 用户访问时,映射为NFS服务端的root 用户
**all_squash** 不论NFS 客户端使用任何帐户,均映射为NFS 服务端的匿名用户

1.1.2 配置nfs-client

IP地址为master(nfs服务器)的IP地址

# 查看
 showmount -e 192.168.0.3
 
# 除了nfs服务器节点,其他节点都要执行
# 挂载到nfs服务器
 mount -t nfs 192.168.0.3:/nfs/data /nfs/data 
# 设置开机自动挂载 
 echo "192.168.0.3:/nfs/data      /nfs/data       nfs     defaults       0 0"  >> /etc/fstab

1.1.3 测试nfs

# 在master01的/home目录下新建test-nfs.yml
apiVersion: v1
kind: Pod
metadata:
  name: test-nfs-pod
spec:
  containers:
    - name: busybox
      image: busybox
      command:
        - sh
        - -c
        - 'echo hello world > /mnt/hello'
      imagePullPolicy: IfNotPresent
      volumeMounts:
        - mountPath: "/mnt"
          name: nfs
  volumes:
    - name: nfs
      nfs: # 使用NFS存储
        path: /nfs/data # NFS存储路径
        server: 192.168.0.3 # NFS服务器地址

# 上面busybox的逻辑就是将“hello world”写入/mnt/hello文件中,而/mnt目录和NFS挂载,所以理论上,nfs虚拟机的/nfs目录下也会有个hello文件。
# 创建后,运行kubectl apply -f test-nfs.yml
# 查看nfs虚拟机(master),查看/nfs/data目录下是否有hello文件
# 测试成功后,可以删除hello文件:rm -rf /nfs/hello
# 执行以下命令删除刚刚的测试Pod:kubectl delete -f test-nfs.yml

2. 配置默认存储(Storageclass)

Storageclass解决PV手动创建需求,当每次创建 PVC 声明使用存储时,都需要去手动的创建 PV,来满足 PVC 的使用。
可以用一种机制来根据用户声明的存储使用量(PVC)来动态的创建对应的持久化存储卷(PV),k8s 用 StorageClass 来实现动态创建 持久化存储。
目前支持的类参考:https://kubernetes.io/zh-cn/docs/concepts/storage/storage-classes/
在NFS StorageClass中最核心概念为Provisioner,那什么是Provisioner?
Provisioner是StorageClass中必须的一个资源,它是存储资源自动调配器,可以将其看作是后端存储驱动。对于NFS类型,K8S没有提供内部Provisioner,但可以使用外部的Provisioner。Provisioner必须符合存储卷的开发规范(CSI)。本文档中使用NFS提供的Provisioner。
流程分解:
①pod挂载pvc
②pvc配置存储类请求pv
③storageclass找到provisioner申请pv
④nfs provisioner生成pvc需要的pv,提供给pod做存储

2.1 创建默认公共存储类

以下操作在master01主节点执行即可
需注意,StorageClass为全局资源,所以命名空间为default,不影响其他命名空间调用 如果*K8s版本为1.20.x *
且nfs-subdir-external-provisioner(nfs-client)的版本低于4.0
在/etc/kubernetes/manifests/kube-apiserver.yaml的command中添加:
- –feature-gates=RemoveSelfLink=false 否则会报错: Kubernetes v1.20.13 报"unexpected error getting claim reference: selfLink was
empty, can’t make reference"

2.1.1 创建nfs-storage存储类

# 创建 sc.yaml 并执行 kubectl apply -f sc.yaml 创建名为nfs-storage的存储类
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: nfs-storage ## 可以改成自己的存储名称
  annotations:
    storageclass.beta.kubernetes.io/is-default-class: 'true'
    storageclass.kubernetes.io/is-default-class: "true"  ## true 默认空间,false 不是默认空间
provisioner: k8s-sigs.io/nfs-subdir-external-provisioner ## 这里指定存储供应者来源名称
reclaimPolicy: Delete  ## 指定回收策略,在这里选择的是Delete,与PV相连的后端存储完成Volume的删除操作
volumeBindingMode: Immediate ## 指定绑定模式,在这里选择的是即刻绑定,也就是存储卷声明创建之后,立刻动态创建存储卷饼将其绑定到存储卷声明,另外还有"WaitForFirstConsumer",直到存储卷声明第一次被容器组使用时,才创建存储卷,并将其绑定到存储卷声明
parameters:
  archiveOnDelete: "true"  ## 删除pv的时候,pv的内容是否要备份
  ##pathPattern: "${.PVC.namespace}/${.PVC.annotations.nfs.io/storage-path}"  ## 配置默认没有,支持NFS创建子目录,用于不同应用使用NFS的不同目录

# kubectl get sc 查看
# local为KubeKey默认安装的 OpenEBS 类型存储
# nfs-storage为我们刚才生成的
[root@master01 ~]# kubectl get sc
NAME                    PROVISIONER                                   RECLAIMPOLICY   VOLUMEBINDINGMODE      ALLOWVOLUMEEXPANSION   AGE
local (default)         openebs.io/local                              Delete          WaitForFirstConsumer   false                  3d22h
nfs-storage (default)   k8s-sigs.io/nfs-subdir-external-provisioner   Delete          Immediate              false                  17h

2.1.2 创建RBAC权限

创建Service Account,用来管控NFS provisioner在k8s集群中的运行权限 rbac (Role-Based Access Control 基于角色的访问控制,就是用户通过角色与权限进行关联),是一个从认证—>授权—>准入机制

# 创建 rbac.yaml 并执行 kubectl apply -f rbac.yaml 
apiVersion: v1
kind: ServiceAccount
metadata:
  name: nfs-client-provisioner
  # replace with namespace where provisioner is deployed
  namespace: default
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: nfs-client-provisioner-runner
rules:
  - apiGroups: [""]
    resources: ["nodes"]
    verbs: ["get", "list", "watch"]
  - apiGroups: [""]
    resources: ["persistentvolumes"]
    verbs: ["get", "list", "watch", "create", "delete"]
  - apiGroups: [""]
    resources: ["persistentvolumeclaims"]
    verbs: ["get", "list", "watch", "update"]
  - apiGroups: ["storage.k8s.io"]
    resources: ["storageclasses"]
    verbs: ["get", "list", "watch"]
  - apiGroups: [""]
    resources: ["events"]
    verbs: ["create", "update", "patch"]
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: run-nfs-client-provisioner
subjects:
  - kind: ServiceAccount
    name: nfs-client-provisioner
    # replace with namespace where provisioner is deployed
    namespace: default
roleRef:
  kind: ClusterRole
  name: nfs-client-provisioner-runner
  apiGroup: rbac.authorization.k8s.io
---
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: leader-locking-nfs-client-provisioner
  # replace with namespace where provisioner is deployed
  namespace: default
rules:
  - apiGroups: [""]
    resources: ["endpoints"]
    verbs: ["get", "list", "watch", "create", "update", "patch"]
---
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: leader-locking-nfs-client-provisioner
  # replace with namespace where provisioner is deployed
  namespace: default
subjects:
  - kind: ServiceAccount
    name: nfs-client-provisioner
    # replace with namespace where provisioner is deployed
    namespace: default
roleRef:
  kind: Role
  name: leader-locking-nfs-client-provisioner
  apiGroup: rbac.authorization.k8s.io
  

2.1.3 创建PV的Provisioner(存储插件)

创建PV存储插件,这样才能实现自动创建PV,一是在NFS共享目录下创建挂载点(volume),二是建立PV并将PC与NFS挂载建立关联。
本文采用高可用配置 如不需要可将replicas设置为1,env中ENABLE_LEADER_ELECTION高可用选举环境变量注释掉

# 创建 rbac.yaml 并执行 kubectl apply -f rbac.yaml 
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nfs-client-provisioner
  labels:
    app: nfs-client-provisioner
  # replace with namespace where provisioner is deployed
  namespace: default
spec:
  replicas: 3  # 想做高可用的话这里可以改成3,一般为大于等于3的奇数
  strategy:
    type: Recreate
  selector:
    matchLabels:
      app: nfs-client-provisioner
  template:
    metadata:
      labels:
        app: nfs-client-provisioner
    spec:
      serviceAccountName: nfs-client-provisioner
      containers:
        - name: nfs-client-provisioner
          # 注意该NFS-client镜像一定要与k8s版本相匹配,如果不兼容那么就无法绑定
          image: registry.cn-hangzhou.aliyuncs.com/lfy_k8s_images/nfs-subdir-external-provisioner:v4.0.2
          # resources:
          #    limits:
          #      cpu: 10m
          #    requests:
          #      cpu: 10m
          volumeMounts:
            - name: nfs-client-root
              mountPath: /persistentvolumes
          env:
            - name: PROVISIONER_NAME
              value: k8s-sigs.io/nfs-subdir-external-provisioner
            - name: ENABLE_LEADER_ELECTION
              value: "True"      ## 设置高可用允许选举
            - name: NFS_SERVER
              value: 192.168.0.5 ## 指定自己nfs服务器地址
            - name: NFS_PATH  
              value: /nfs/data  ## nfs服务器共享的目录
      volumes:
        - name: nfs-client-root
          nfs:
            server: 192.168.0.3
            path: /nfs/data

# 通过检查容器日志查看启动的NFS插件是否正常
# 如果出现error等相关信息一定仔细排查,否则会导致NFS-celient一直处于pending状态
# https://github.com/kubernetes-sigs/nfs-subdir-external-provisioner/issues/25 
[root@master01 ~]# kubectl get pod | grep nfs
nfs-client-provisioner-86b55c565d-fqmm5   1/1     Running   0          20h
nfs-client-provisioner-86b55c565d-p2sks   1/1     Running   0          20h
nfs-client-provisioner-86b55c565d-r5stq   1/1     Running   0          20h

2.1.4 创建PVC持久化卷

# # 创建 pvc.yaml 并执行 kubectl apply -f pvc.yaml 
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: test-pvc
  namespace: default
spec:
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 200Mi
  storageClassName:  nfs-storage   ## 这里不加就是默认存储
  
# kubectl get pvc 查看
[root@master01 nfs]# kubectl get pvc
NAME       STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   AGE
test-pvc   Bound    pvc-dd852bab-8b86-4d42-8666-9b2b550597aa   200Mi      RWX            nfs-storage    8s
[root@master01 nfs]# kubectl delete -f pvc.yaml 

2.2 使用statefulset动态为pod生成pv

RC、Deployment、DaemonSet都是面向无状态的服务,它们所管理的Pod的IP、名字,启停顺序等都是随机的,而StatefulSet是什么?顾名思义,有状态的集合,管理所有有状态的服务,比如MySQL、MongoDB集群等。
StatefulSet本质上是Deployment的一种变体,在v1.9版本中已成为GA版本,它为了解决有状态服务的问题,它所管理的Pod拥有固定的Pod名称,启停顺序,在StatefulSet中,Pod名字称为网络标识(hostname),还必须要用到共享存储。
在Deployment中,与之对应的服务是service,而在StatefulSet中与之对应的headless
service,headless service,即无头服务,与service的区别就是它没有Cluster
IP,解析它的名称时将返回该Headless Service对应的全部Pod的Endpoint列表。
除此之外,StatefulSet在Headless Service的基础上又为StatefulSet控制的每个Pod副本创建了一个DNS域名,这个域名的格式为:

$(podname).(headless server name)
FQDN:$(podname).(headless server name).namespace.svc.cluster.local

2.2.1 创建测试pod

# 创建 test.yaml 并执行 kubectl apply -f test.yaml 
apiVersion: v1
kind: Service
metadata:
  name: nginx
  labels:
    app: nginx
spec:
  ports:
  - port: 80
    name: web
  clusterIP: None
  selector:
    app: nginx
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: nfs-web
spec:
  serviceName: "nginx"
  replicas: 3
  selector:
    matchLabels:
      app: nfs-web # has to match .spec.template.metadata.labels
  template:
    metadata:
      labels:
        app: nfs-web
    spec:
      terminationGracePeriodSeconds: 10
      containers:
      - name: nginx
        image: nginx:1.7.9
        ports:
        - containerPort: 80
          name: web
        volumeMounts:
        - name: www
          mountPath: /usr/share/nginx/html
  volumeClaimTemplates:  # pvc模板
  - metadata:
      name: www
      namespace: default # 要和pod的namspace一致
      annotations:
        volume.beta.kubernetes.io/storage-class: nfs-storage
    spec:
      accessModes: [ "ReadWriteOnce" ]
      resources:
        requests:
          storage: 10Mi
# kubectl get pvc 查看 可以看到为pod动态生成了pvc,pv
# 在StatefulSet中动态生成的pv不会随着pod的删除而被删除
# 它是和pod一一对应,pod恢复后,数据依然存在
[root@master01 nfs]# kubectl get pvc            
NAME            STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   AGE
www-nfs-web-0   Bound    pvc-bdd6ff3e-9524-4e21-8cb6-29aebfd67e6f   10Mi       RWO            nfs-storage    4s
www-nfs-web-1   Bound    pvc-9eea90b4-3ac7-4a7d-a037-301c96eb707e   10Mi       RWO            nfs-storage    0s
[root@master01 nfs]# 
[root@master01 nfs]# kubectl delete -f test.yaml 

3. KubeSphere存储持久化和其他组件安装

3.1 存储持久化和其他组件安装

3.1.1 存储持久化和配置其他组件

1、以 admin 用户登录控制台,点击左上角的平台管理,选择集群管理。
2、点击定制资源定义,在搜索栏中输入 ClusterConfiguration,点击搜索结果查看其详细页面。

在这里插入图片描述

3、在自定义资源中,点击 ks-installer 右侧的操作,选择编辑 YAML。。

在这里插入图片描述

4、在该 YAML 文件中,修改配置内容完成后,点击右下角的确定,保存配置,组件就开始安装,安装需要一定的时间,需要耐心等待。

1、kubesphere平台上操作:metrics_server 改为 true

  metrics_server:
    enabled: true

2、kubesphere平台上操作:建议将存储配置进行修改: storageClass: “nfs-storage” ,不修改会默认创建一个存储空间 local (default)

  monitoring:
    gpu:
      nvidia_dcgm_exporter:
        enabled: false
    node_exporter:
      port: 9100
    storageClass: 'nfs-storage'
# 监控如果开启建议修改为nfs-storage
  monitoring:
    gpu:
      nvidia_dcgm_exporter:
        enabled: false
    node_exporter:
      port: 9100
    storageClass: 'nfs-storage'

3、kubesphere平台上操作: network配置改为如下:

  network:
    ippool:
      type: calico
    networkpolicy:
      enabled: true
    topology:
      type: weave-scope

4、kubesphere平台上操作: 应用商店开启:

  openpitrix:
    store:
      enabled: true

传送门KubeSphere启用可插拔组件官方文档

在这里插入图片描述

5、在 kubectl 中执行以下命令检查安装过程:
 kubectl logs -n kubesphere-system $(kubectl get pod -n kubesphere-system -l 'app in (ks-install, ks-installer)' -o jsonpath='{.items[0].metadata.name}') -f

往期文章参考:
01.使用 KubeKey 在Linux上预配置生产就绪的 Kubernetes 和 KubeSphere 集群

Logo

K8S/Kubernetes社区为您提供最前沿的新闻资讯和知识内容

更多推荐