kubernetes(k8s) 配置nfs动态卷实现StatefulSet的持久化存储

概述

    我们知道,平时kubernetes在部署无状态服务的时候,并不需要太多考虑持久化存储的事情,直接通过volume挂载网络存储,比如常见的nfs就能实现文件共享存储。

    但是如果在有状态服务中,你就会需要很多的问题,比如:当你部署一些集群服务的时候:

1. 不可以用共享存储,因为每个服务的数据都不能相同。

2. 不可以直接用node的本地路径进行挂载,因为pod的随机性,一个node可能会跑多个pod副本,则会造成冲突。

3. 数据量可能会很大,可能需要使用外部存储,或者独立的磁盘,云盘等

4. 就算用pv,pvc也很不方便,需要你提前手动创建,不方便扩展。

 

   然后我们细数一下k8s里的持久化存储,总的分为两种,静态卷和动态卷。静态卷就是刚才我们说的,volume挂载,或者通过手动创建pv,pvc进行挂载。都属于静态卷。而动态卷,则是将一个网络存储作为一个StorageClass类,通过自己的配置,来动态的创建pv,pvc并进行绑定,这样就可以实现动态的存储生成与持久化保存。

    具体详细的k8s的存储系统知识我这里就不想洗说明,有兴趣的自行百度,谷歌就可以了,先了解一下k8s的存储,再来看如何实现

   下面我们就说一下,怎么通过nfs动态卷来实现有状态服务的储存。

 

正文

环境:

kubernetes  v1.12.2 

centos7

这里以搭建neo4j 因果集群为例,展示nfs动态卷的使用,namespace为neo4j。

nfs动态卷的整体结构大致如下图,用户通过yaml创建StatefulSet,StatefulSet找到StorageClass,StorageClass指定到nfs-provisioner为nfs的pv提供者,这是一个pod的服务,用来自动生成pv的,此pod来绑定到对应的nfs服务。以此来通过nfs服务进行动态的pv生成,然后通过StatefulSet的pvc,与pod进行绑定,实现数据的持久化存储。

kubernetes(k8s) 配置nfs动态卷实现StatefulSet的持久化存储_第1张图片

 

 

1.  搭建好nfs服务

nfs服务的搭建,请看:《centos7.2 配置NFS文件服务器,远程共享文件》

我这里搭建好nfs后,创建文件夹 /opt/nfs 作为主目录进行,配置如下: 

# 172.18.0.0/16是我的内网网段,自己根据情况自定义
/opt/nfs 172.18.0.0/16(rw,sync,no_root_squash)

nfs服务的ip为:172.18.196.238

 

2. 配置rbac权限

由于我这里以neo4j为namespace,所以先创建namespace.yaml 文件,内容如下:

---
apiVersion: v1
kind: Namespace
metadata:
   name: neo4j
   labels:
     name: neo4j

执行此yaml文件,创建neo4j的命名空间,以保证下面的使用

kubectl create -f namespace.yaml

 

然后开始创建rbac.yaml,进行账号的授权,内容如下:

---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: nfs-provisioner
  namespace: neo4j
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
   name: nfs-provisioner-runner
rules:
   -  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: ["list", "watch", "create", "update", "patch"]
   -  apiGroups: [""]
      resources: ["services", "endpoints"]
      verbs: ["get","create","list", "watch","update"]
   -  apiGroups: ["extensions"]
      resources: ["podsecuritypolicies"]
      resourceNames: ["nfs-provisioner"]
      verbs: ["use"]
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: run-nfs-provisioner
subjects:
  - kind: ServiceAccount
    name: nfs-provisioner
    namespace: neo4j
roleRef:
  kind: ClusterRole
  name: nfs-provisioner-runner
  apiGroup: rbac.authorization.k8s.io

执行此yaml文件,执行账号创建与授权,必须进行账号的授权,否则无法自动创建pv和pvc

kubectl create -f rbac.yaml

 

3. 创建nfs-provisioner

创建deployment.yaml 文件,内容如下:

---
kind: Deployment
apiVersion: apps/v1
metadata:
  name: nfs-client-provisioner
  namespace: neo4j
  labels:
    app: nfs-client-provisioner
spec:
  replicas: 1
  strategy:
    type: Recreate
  selector:
    matchLabels:
      app: nfs-client-provisioner
  template:
    metadata:
      labels:
        app: nfs-client-provisioner
    spec:
      serviceAccount: nfs-provisioner
      containers:
        - name: nfs-client-provisioner
          image: quay.io/external_storage/nfs-client-provisioner:latest
          volumeMounts:
            - name: nfs-client-root
              mountPath: /persistentvolumes
          env:
            - name: PROVISIONER_NAME
              value: nfs-provisioner
            - name: NFS_SERVER
              value: 172.18.196.238
            - name: NFS_PATH
              value: /opt/nfs
      volumes:
        - name: nfs-client-root
          nfs:
            server: 172.18.196.238
            path: /opt/nfs

执行此yaml文件,创建nfs-provisioner,此nfs-provisioner通过授权的账号实现自动创建pv,pvc

kubectl create -f deployment.yaml

 

3. 创建storageclass

创建storageclass.yaml ,内容如下:

---
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: managed-nfs-storage
provisioner: nfs-provisioner
parameters:
  archiveOnDelete: "true"    # 这里为true,表示pv删除后,会自动归档,不会删除文件

执行此yaml文件,创建storageclass,指定使用的provisioner为nfs-provisioner

kubectl create -f storageclass.yaml

 

4. 测试使用

在StatefulSet中,通过配置volumeClaimTemplates来配置使用动态卷,这里以搭建neo4j的因果集群为例子,进行测试,创建demo.yaml 文件,内容如下:

---
apiVersion: apps/v1beta1
kind: StatefulSet
metadata:
  name: neo4j-core
  namespace: neo4j
  labels:
    app: neo4j-core
spec:
  replicas: 2
  selector:
    matchLabels:
      app: neo4j-core
  serviceName: neo4j-core
  template:
    metadata:
      labels:
        app: neo4j-core
    spec:
      nodeSelector:
        neo4j-core: "yes"
      containers:
      - name: neo4j-core
        image: neo4j:3.5.5-enterprise
        imagePullPolicy: IfNotPresent
        env:
          - name: NEO4J_ACCEPT_LICENSE_AGREEMENT
            value: "yes"
          - name: NEO4J_dbms_connectors_default__advertised__address
            valueFrom:
              fieldRef:
                fieldPath: status.podIP
          - name: NEO4J_dbms_mode
            value: "CORE"
          - name: NEO4J_causal__clustering_minimum__core__cluster__size__at__formation
            value: "2"
          - name: NEO4J_causal__clustering_minimum__core__cluster__size__at__runtime
            value: "2"
          - name: NEO4J_causal__clustering_discovery__type
            value: "LIST"
          - name: NEO4J_causal__clustering_initial__discovery__members
            value: "neo4j-core-0.neo4j-core.neo4j.svc.cluster.local:5000,neo4j-core-1.neo4j-core.neo4j.svc.cluster.local:5000"
          - name: NEO4J_causal__clustering_discovery__advertised__address
            value: $(NEO4J_dbms_connectors_default__advertised__address):5000
          - name: NEO4J_causalClustering_transactionAdvertisedAddress
            value: $(NEO4J_dbms_connectors_default__advertised__address):6000
          - name: NEO4J_causalClustering_raftAdvertisedAddress
            value: $(NEO4J_dbms_connectors_default__advertised__address):7000
        volumeMounts:
        - name: neo4j-core    # 这里的name要和 下面volumeClaimTemplates的metdata中name一致
          mountPath: /data
  volumeClaimTemplates:
  - metadata:
      name: neo4j-core
      annotations:
        volume.beta.kubernetes.io/storage-class: "managed-nfs-storage"    # 这里managed-nfs-storage就是我们创建的storageclass的name
    spec:
      accessModes: [ "ReadWriteOnce" ]
      resources:
        requests:
          storage: 2Gi
---
apiVersion: v1
kind: Service
metadata:
  name: neo4j-core
  namespace: neo4j
spec:
  selector:
    app: neo4j-core
  type: NodePort
  ports:
    - protocol: TCP
      name: http
      port: 7474
      nodePort: 27474
      targetPort: 7474
    - protocol: TCP
      name: blot
      port: 7687
      nodePort: 27687
      targetPort: 7687

执行此demo.yaml

kubectl create -f demo.yaml
执行过后,等待片刻,查看pvc已经生成,并与pv进行了绑定。

查看pv

这里pv的回收策略是delete,就是说pod删除后,pv,pvc与自动删除,但是数据文件并不会删除,会进行归档,因为在storageclass中设置了对删除PV的文件的归档。

 

我们查看一下nfs服务的目录,会发现生成了两个文件夹,名字为 pvc的name加上pv的name:

kubernetes(k8s) 配置nfs动态卷实现StatefulSet的持久化存储_第2张图片

进入文件夹,查看数据存在。 

 

然后现在我们删掉此neo4j的集群,查看数据是否会被删除

kubectl delete -f demo.yaml

删除后,查看pv,pvc,会发现,pv,pvc都被删除掉了,然后到nfs目录中查看:

会发现,文件夹还在,且其名称前面多一个archived,这是归档的意思,表示此文件夹的pv已经被删除了,进去查看文件是否存在

 

ok,到此测试通过,就可以使用volumeClaimTemplates来配置动态卷的使用,非常方便简单。当然动态卷不止支持nfs,还支持很多的储存插件来提供PV,详细可查看Storage Classes 官方文档 provisioner部分。

 

 

结束

    我这里并没有讲很多的k8s的存储系统相关的东西,只是主要实现了nfs动态卷的配置和使用。使用则主要是demo.yaml文件文件中的volumeClaimTemplates来进行配置。有任何不明白的,欢迎留言

你可能感兴趣的:(Centos7系列)