1 NFS Client Provisioner的介绍

NFS作为在Kubernetes当前版本的中,可以创建类型为nfs的持久化存储卷,用于为PersistentVolumClaim提供存储卷

NFS Client Provisioner是一个automatic provisioner,使用NFS作为存储,自动创建PV和对应的PVC,本身不提供NFS存储,需要外部先有一套NFS存储服务

  • PV以 ${namespace}-${pvcName}-${pvName}的命名格式提供(在NFS服务器上)
  • PV回收的时候以 archieved-${namespace}-${pvcName}-${pvName} 的命名格式(在NFS服务器上)

2 NFS动态分配PV的部署

配置授权 部署NFS Client Provisioner
(1)创建命名空间:kubectl create namespace nfs-client-provisioner

  • 查看命名空间:kubectl get ns

在这里插入图片描述
(2)应用文件:kubectl apply -f nfs-client-provisioner.yaml

2.1 配置授权

## 配置授权
---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: nfs-client-provisioner
  # replace with namespace where provisioner is deployed
  namespace: nfs-client-provisioner
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: nfs-client-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: ["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: nfs-client-provisioner
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: nfs-client-provisioner
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: nfs-client-provisioner
subjects:
 - kind: ServiceAccount
    name: nfs-client-provisioner
    # replace with namespace where provisioner is deployed
    namespace: nfs-client-provisioner
roleRef:
  kind: Role
  name: leader-locking-nfs-client-provisioner
  apiGroup: rbac.authorization.k8s.io
---

---

2.2 部署NFS Client Provisioner

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nfs-client-provisioner
  labels:
    app: nfs-client-provisioner
  # replace with namespace where provisioner is deployed
  namespace: nfs-client-provisioner
spec:
  replicas: 1
  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
          image: nfs-subdir-external-provisioner:v4.0.0
          volumeMounts:
            - name: nfs-client-root
              mountPath: /persistentvolumes
          env:
            - name: PROVISIONER_NAME
              value: k8s-sigs.io/nfs-subdir-external-provisioner
            - name: NFS_SERVER
              value: 172.25.12.1
            - name: NFS_PATH
              value: /nfsdata
      volumes:
        - name: nfs-client-root
          nfs:
            server: 172.25.12.1
            path: /nfsdata

2.3 创建 NFS SotageClass

官网:https://kubernetes.io/zh/docs/concepts/storage/storage-classes/

StorageClass提供了一种描述存储类(class)的方法,不同的class可能会映射到不同的服务质量等级和备份策略或其他策略等。

  • 每个 StorageClass 都包含 provisioner、parameters 和 reclaimPolicy 字段,这些字段会在StorageClass需要动态分配 PersistentVolume 时会使用到。

StorageClass的属性

  • Provisioner(存储分配器):用来决定使用哪个卷插件分配
    PV,该字段必须指定。可以指定内部分配器,也可以指定外部分配器,外部分配器的代码地址为:
    kubernetes-incubator/external-storage,其中包括NFS和Ceph等
  • Reclaim Policy(回收策略):通过reclaimPolicy字段指定创建的Persistent
    Volume的回收策略,回收策略包括:Delete 或者 Retain,没有指定默认为Delete
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: managed-nfs-storage
provisioner: k8s-sigs.io/nfs-subdir-external-provisioner
parameters:
  archiveOnDelete: "true"

将上述三个清单文件整合到一个文件并应用:

  • 应用文件:kubectl apply -f nfs-client-provisioner.yaml
  • 查看SotageClass:kubectl get sc

在这里插入图片描述

2.4 创建PVC和测试pod

(1)应用资源清单文件:kubectl apply -f pvc.yaml

## 创建PVC
---
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: test-claim
spec:
  storageClassName: managed-nfs-storage
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 2Gi

## 创建测试pod
---
kind: Pod
apiVersion: v1
metadata:
  name: test-pod
spec:
  containers:
 - name: test-pod
    image: myapp:v1
    volumeMounts:
      - name: nfs-pvc
        mountPath: "/usr/share/nginx/html"
  volumes:
    - name: nfs-pvc
      persistentVolumeClaim:
        claimName: test-claim
  • 查看NFS服务端的挂载目录下的挂载卷:
[root@server1 nfsdata]# ll
total 4
drwxrwxrwx 2 root root  6 Feb 25 16:54 default-test-claim-2-pvc-a15b9c41-94e9-4ed3-8ad2-b408d929752c
drwxrwxrwx 2 root root  6 Feb 25 16:53 default-test-claim-pvc-d855a068-ab3c-4744-b9f5-0ca828c3a8af

2.5 设定默认的StorageClass

  • 默认的 StorageClass 被用于动态的为没有特定 storage class 需求的 PersistentVolumeClaims配置存储:(只能有一个默认StorageClass) 如果没有默认StorageClass,PVC也没有指定storageClassName 的值,那么它只能够跟 storageClassName 也是的 PV 进行绑定。

(1)应用的资源清单文件没有指定StorageClass:kubectl apply -f pvc.yaml

kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: test-claim
spec:
 # storageClassName: managed-nfs-storage
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 2Gi
  • 查看pvc的信息:kubectl get pvctest-claim一直在Pending状态

在这里插入图片描述
(2)解决方案:

  • 设定默认的StorageClass
 kubectl patch storageclass managed-nfs-storage -p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"true"}}}'
  • 查看StorageClass的信息:kubectl get sc,此时设定默认的StorageClass设定成功

在这里插入图片描述
(3)测试

  • 删除相应的资源:kubectl delete -f pvc.yaml
  • 应用资源清单文件:kubectl apply -f pvc.yaml
  • 查看pvc:kubectl get pvc

在这里插入图片描述

2.6 维持Pod的拓扑状态

StatefulSet通过Headless Service维持Pod的拓扑状态

(1)创建Headless service

  • 应用文件:kubectl apply -f service.yml
## 创建Headless service
---
apiVersion: v1
kind: Service
metadata:
 name: nginx-svc
 labels:
  app: nginx
spec:
 ports:
 - port: 80
   name: web
 clusterIP: None
 selector:
  app: nginx
  • 查看svc的信息,
kubectl get svc
kubectl describe svc nginx-svc ##Endpoints没有相应的ip信息

在这里插入图片描述

2.7 StatefulSet控制器

StatefulSet将应用状态抽象成了两种情况:

  • 拓扑状态:应用实例必须按照某种顺序启动。新创建的Pod必须和原来Pod的网络标识一样
  • 存储状态:应用的多个实例分别绑定了不同存储数据

(1)应用文件:kubectl apply -f service.yml

## 创建Headless service
---
apiVersion: v1
kind: Service
metadata:
 name: nginx-svc
 labels:
  app: nginx
spec:
 ports:
 - port: 80
   name: web
 clusterIP: None
 selector:
  app: nginx

## StatefulSet控制器
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
 name: web
spec:
 serviceName: "nginx-svc"
 replicas: 2
 selector:
  matchLabels:
   app: nginx
 template:
  metadata:
   labels:
    app: nginx
  spec:
   containers:
 - name: nginx
     image: myapp:v1
     ports:
     - containerPort: 80
       name: web
  • StatefulSet给所有的Pod进行了编号,编号规则是:$(statefulset名称)-$(序号),从0开始。pod的创建也是严格按照编号顺序进行的。比如在web-0进入到running状态,并且Conditions为Ready之前,web-1一直会处于pending状态
[root@server2 mnt]# kubectl get pod
NAME    READY   STATUS    RESTARTS   AGE
web-0   0/1     Pending   0          2s
[root@server2 mnt]# kubectl get pod
NAME    READY   STATUS    RESTARTS   AGE
web-0   1/1     Running   0          5s
web-1   0/1     Pending   0          1s
[root@server2 mnt]# kubectl get pod
NAME    READY   STATUS    RESTARTS   AGE
web-0   1/1     Running   0          13s
web-1   1/1     Running   0          9s
  • 查看pod的信息:kubectl get pod -o wide
  • 查看nginx-svc 服务的详细信息:kubectl describe svc nginx-svc

在这里插入图片描述

(2)测试

  • 访问pod的服务会访问Pod的网络标识

在这里插入图片描述

[root@server2 mnt]# kubectl attach demo  -it
Defaulting container name to demo.
Use 'kubectl describe pod/demo -n default' to see all of the containers in this pod.
If you don't see a command prompt, try pressing enter.
/ # nslookup nginx-svc
Server:    10.96.0.10
Address 1: 10.96.0.10 kube-dns.kube-system.svc.cluster.local

Name:      nginx-svc
Address 1: 10.244.22.0 web-1.nginx-svc.default.svc.cluster.local
Address 2: 10.244.141.210 web-0.nginx-svc.default.svc.cluster.local
/ # curl  nginx-svc
Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>
/ # curl  nginx-svc/hostname.html
web-0
/ # curl  nginx-svc/hostname.html
web-0
/ # curl  nginx-svc/hostname.html
web-1
/ # curl  nginx-svc/hostname.html
web-1
/ # curl  web-1.nginx-svc.default.svc.cluster.local
Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>
/ # curl  web-1.nginx-svc.default.svc.cluster.local/hostname.html
web-1
/ # curl  web-0.nginx-svc.default.svc.cluster.local/hostname.html
web-0
  • Pod对应的DNS记录:dig -t A nginx-svc.default.svc.cluster.local. @10.96.0.10

在这里插入图片描述

Pod被删除后重建,重建Pod的网络标识也不会改变,Pod的拓扑状态按照Pod的“名字+编号”的方式固定下来,并且为每个Pod提供了一个固定且唯一的访问入口,即Pod对应的DNS记录。

  • 删除所有的pod:kubectl delete pod --all --force,会自动生成指定数量的pod
  • 查看pod的信息:kubectl get pod -o wide,此时各个pod的ip重新动态分配

在这里插入图片描述

  • Pod对应的DNS记录:
dig -t A nginx-svc.default.svc.cluster.local. @10.96.0.10

在这里插入图片描述

  • 重建后Pod的网络标识未改变

在这里插入图片描述

2.8 StatefulSet对存储状态的管理

PV和PVC的设计,使得StatefulSet对存储状态的管理成为了可能:

(1)应用文件:kubectl apply -f service.yml

## 创建Headless service
---
apiVersion: v1
kind: Service
metadata:
 name: nginx-svc
 labels:
  app: nginx
spec:
 ports:
 - port: 80
   name: web
 clusterIP: None
 selector:
  app: nginx
##  StatefulSet控制器
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
 name: web
spec:
 serviceName: "nginx-svc"
 replicas: 2
 selector:
  matchLabels:
   app: nginx
 template:
  metadata:
   labels:
    app: nginx
  spec:
   containers:
 - name: nginx
     image: myapp:v1
     ports:
     - containerPort: 80
       name: web
     volumeMounts:
       - name: www
         mountPath: /usr/share/nginx/html

 volumeClaimTemplates:
 - metadata:
     name: www
    spec:
     storageClassName: managed-nfs-storage
     accessModes:
     - ReadWriteOnce
     resources:
      requests:
       storage: 1Gi
  • Pod的创建也是严格按照编号顺序进行的。比如在web-0进入到running状态,并且Conditions为Ready之前,web-1一直会处于pending状态
[root@server2 mnt]# kubectl get pod
NAME    READY   STATUS    RESTARTS   AGE
web-0   1/1     Running   0          3s
web-1   0/1     Pending   0          1s
[root@server2 mnt]# kubectl get pod
NAME    READY   STATUS              RESTARTS   AGE
web-0   1/1     Running             0          5s
web-1   0/1     ContainerCreating   0          3s
[root@server2 mnt]# kubectl get pod
NAME    READY   STATUS    RESTARTS   AGE
web-0   1/1     Running   0          8s
web-1   1/1     Running   0          6s
  • 查看指定pod的详细信息:kubectl describe pod web-0,nginx的默认发布目录挂载成功

在这里插入图片描述

  • StatefulSet还会为每一个Pod分配并创建一个同样编号的PVC。这样,kubernetes就可以通过Persistent Volume机制为这个PVC绑定对应的PV,从而保证每一个Pod都拥有一个独立的Volume
[root@server2 mnt]# kubectl get pv
NAME                                       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM               STORAGECLASS          REASON   AGE
pvc-15e7aef5-8664-4767-a039-f9369ab7d1af   1Gi        RWO            Delete           Bound    default/www-web-1   managed-nfs-storage            11m
pvc-1e322dce-de7f-43e3-8a06-8e82a1c452f5   1Gi        RWO            Delete           Bound    default/www-web-0   managed-nfs-storage            11m
[root@server2 mnt]# kubectl get pvc
NAME        STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS          AGE
www-web-0   Bound    pvc-1e322dce-de7f-43e3-8a06-8e82a1c452f5   1Gi        RWO            managed-nfs-storage   11m
www-web-1   Bound    pvc-15e7aef5-8664-4767-a039-f9369ab7d1af   1Gi        RWO            managed-nfs-storage   11m
  • 查看nginx-svc服务的信息 :kubectl describe svc nginx-svc
  • 查看pod的详细信息:kubectl get pod -o wide

在这里插入图片描述

  • 查看NFS服务端的挂载目录,并向挂载目录中写入nginx默认的发布页面的信息

在这里插入图片描述

(2)测试:访问pod的服务时,显示的是默认的发布信息
在这里插入图片描述

[root@server2 mnt]# kubectl attach demo  -it
Defaulting container name to demo.
Use 'kubectl describe pod/demo -n default' to see all of the containers in this pod.
If you don't see a command prompt, try pressing enter.
/ # nslookup nginx-svc
Server:    10.96.0.10
Address 1: 10.96.0.10 kube-dns.kube-system.svc.cluster.local

Name:      nginx-svc
Address 1: 10.244.141.209 web-1.nginx-svc.default.svc.cluster.local
Address 2: 10.244.22.5 web-0.nginx-svc.default.svc.cluster.local
/ # curl web-0.nginx-svc.default.svc.cluster.local
www.web-0.org
/ # curl web-1.nginx-svc.default.svc.cluster.local
www.web-1.org
/ # curl nginx-svc
www.web-0.org
/ # curl nginx-svc
www.web-1.org
/ # curl nginx-svc
www.web-1.org
/ # curl nginx-svc
www.web-0.org
  • Pod对应的DNS记录:dig -t A nginx-svc.default.svc.cluster.local. @10.96.0.10

在这里插入图片描述

2.9 kubectl 弹缩

(1)想要弹缩的StatefulSet,需先验证是否能弹缩该应用

[root@server2 mnt]# kubectl get statefulsets  web
NAME   READY   AGE
web    2/2     21m

(2)改变StatefulSet副本数量并重新应用

  • pod的收缩:kubectl apply -f statefulset.yml

在这里插入图片描述

  • Pod的收缩也是严格按照编号倒序进行的,比如在web-0进入到Terminating状态,并且被彻底删除之前,web-0一直会处于running状态
root@server2 mnt]# kubectl get pod
NAME    READY   STATUS        RESTARTS   AGE
web-0   1/1     Running       0          95m
web-1   0/1     Terminating   0          95m
[root@server2 mnt]# kubectl get pod
NAME    READY   STATUS        RESTARTS   AGE
web-0   0/1     Terminating   0          95m
[root@server2 mnt]# kubectl get pod
No resources found in default namespace.
[root@server2 mnt]# kubectl get pv
NAME                                       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM               STORAGECLASS          REASON   AGE
pvc-15e7aef5-8664-4767-a039-f9369ab7d1af   1Gi        RWO            Delete           Bound    default/www-web-1   managed-nfs-storage            11m
pvc-1e322dce-de7f-43e3-8a06-8e82a1c452f5   1Gi        RWO            Delete           Bound    default/www-web-0   managed-nfs-storage            11m
[root@server2 mnt]# kubectl get pvc
NAME        STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS          AGE
www-web-0   Bound    pvc-1e322dce-de7f-43e3-8a06-8e82a1c452f5   1Gi        RWO            managed-nfs-storage   11m
www-web-1   Bound    pvc-15e7aef5-8664-4767-a039-f9369ab7d1af   1Gi        RWO            managed-nfs-storage   11m
  • pod的拉伸:kubectl apply -f service.yml

在这里插入图片描述

  • Pod对应的DNS记录:dig -t A nginx-svc.default.svc.cluster.local. @10.96.0.10

在这里插入图片描述

  • 虽然pod的ip地址被重新分配,但是挂载目录中的内容被没有改变

在这里插入图片描述

Logo

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

更多推荐