• 045.Kubernetes集群存储-CSI存储机制


    一 CSI存储机制

    1.1 CSI简介

    Kubernetes从1.9版本开始引入容器存储接口Container Storage Interface(CSI)机制,用于在Kubernetes和外部存储系统之间建立一套标准的存储管理接口,通过该接口为容器提供存储服务。

    1.2 CSI的设计背景

    Kubernetes通过PV、PVC、Storageclass已经提供了一种强大的基于插件的存储管理机制,但是各种存储插件提供的存储服务都是基于一种被称为“in-true”(树内)的方式提供的,这要求存储插件的代码必须被放进Kubernetes的主干代码库中才能被Kubernetes调用,属于紧耦合的开发模式。这种“in-tree”方式会带来一些问题:
    • 存储插件的代码需要与Kubernetes的代码放在同一代码库中,并与Kubernetes的二进制文件共同发布;
    • 存储插件代码的开发者必须遵循Kubernetes的代码开发规范;
    • 存储插件代码的开发者必须遵循Kubernetes的发布流程,包括添加对Kubernetes存储系统的支持和错误修复;
    • Kubernetes社区需要对存储插件的代码进行维护,包括审核、测试等工作;
    • 存储插件代码中的问题可能会影响Kubernetes组件的运行,并且很难排查问题;
    • 存储插件代码与Kubernetes的核心组件(kubelet和kubecontroller-manager)享有相同的系统特权权限,可能存在可靠性和安全性问题。

    Kubernetes已有的FlexVolume插件机制试图通过为外部存储暴露一个基于可执行程序(exec)的API来解决这些问题。尽管它允许第三方存储提供商在Kubernetes核心代码之外开发存储驱动,但仍然有两个问题没有得到很好的解决:
    • 部署第三方驱动的可执行文件仍然需要宿主机的root权限,存在安全隐患;
    • 存储插件在执行mount、attach这些操作时,通常需要在宿主机上安装一些第三方工具包和依赖库,使得部署过程更加复杂,例如部署Ceph时需要安装rbd库,部署GlusterFS时需要安装mount.glusterfs库,等等。

    基于以上这些问题和考虑,Kubernetes逐步推出与容器对接的存储接口标准,存储提供方只需要基于标准接口进行存储插件的实现,就能使用Kubernetes的原生存储机制为容器提供存储服务。这套标准被称为CSI(容器存储接口)。
    在CSI成为Kubernetes的存储供应标准之后,存储提供方的代码就能和Kubernetes代码彻底解耦,部署也与Kubernetes核心组件分离,显然,存储插件的开发由提供方自行维护,就能为Kubernetes用户提供更多的存储功能,也更加安全可靠。
    基于CSI的存储插件机制也被称为“out-of-tree”(树外)的服务提供方式,是未来Kubernetes第三方存储插件的标准方案。

    二 CSI架构

    2.1 CSI存储组件/部署架构

    KubernetesCSI存储插件的关键组件和推荐的容器化部署架构:
    clipboard
    其中主要包括两种组件:CSI Controller和CSI Node。

    2.2 CSI Controller

    CSI Controller的主要功能是提供存储服务视角对存储资源和存储卷进行管理和操作。在Kubernetes中建议将其部署为单实例Pod,可以使用StatefulSet或Deployment控制器进行部署,设置副本数量为1,保证为一种存储插件只运行一个控制器实例。
    在这个Pod内部署两个容器:
    • 与Master(kube-controller-manager)通信的辅助sidecar容器。在sidecar容器内又可以包含external-attacher和external-provisioner两个容器,它们的功能分别如下。
      • external-attacher:监控VolumeAttachment资源对象的变更,触发针对CSI端点的ControllerPublish和ControllerUnpublish操作。
      • external-provisioner:监控PersistentVolumeClaim资源对象的变更,触发针对CSI端点的CreateVolume和DeleteVolume操作。
    • CSI Driver存储驱动容器,由第三方存储提供商提供,需要实现上述接口。
    这两个容器通过本地Socket(Unix DomainSocket,UDS),并使用gPRC协议进行通信。
    sidecar容器通过Socket调用CSI Driver容器的CSI接口,CSI Driver容器负责具体的存储卷操作。

    2.3 CSI Node

    CSI Node的主要功能是对主机(Node)上的Volume进行管理和操作。在Kubernetes中建议将其部署为DaemonSet,在每个Node上都运行一个Pod。
    在这个Pod中部署以下两个容器:
    • 与kubelet通信的辅助sidecar容器node-driver-registrar,主要功能是将存储驱动注册到kubelet中;
    • CSI Driver存储驱动容器,由第三方存储提供商提供,主要功能是接收kubelet的调用,需要实现一系列与Node相关的CSI接口,例如NodePublishVolume接口(用于将Volume挂载到容器内的目标路径)、NodeUnpublishVolume接口(用于从容器中卸载Volume),等等。
    node-driver-registrar容器与kubelet通过Node主机的一个hostPath目录下的unixsocket进行通信。CSI Driver容器与kubelet通过Node主机的另一个hostPath目录下的unixsocket进行通信,同时需要将kubelet的工作目录(默认为/var/lib/kubelet)挂载给CSIDriver容器,用于为Pod进行Volume的管理操作(包括mount、umount等)。

    三 CSI插件使用实践

    3.1 实验说明

    以csi-hostpath插件为例,演示部署CSI插件、用户使用CSI插件提供的存储资源。

    3.2 开启特性

    设置Kubernetes服务启动参数,为kube-apiserver、kubecontroller-manager和kubelet服务的启动参数添加。
    [root@k8smaster01 ~]# vi /etc/kubernetes/manifests/kube-apiserver.yaml
    ……
        - --allow-privileged=true
        - --feature-gates=CSIPersistentVolume=true
        - --runtime-config=storage.k8s.io/v1alpha1=true
    ……
    [root@k8smaster01 ~]# vi /etc/kubernetes/manifests/kube-controller-manager.yaml
    ……
        - --feature-gates=CSIPersistentVolume=true
    ……
    [root@k8smaster01 ~]# vi /usr/lib/systemd/system/kubelet.service.d/10-kubeadm.conf
    # Note: This dropin only works with kubeadm and kubelet v1.11+
    [Service]
    Environment="KUBELET_KUBECONFIG_ARGS=--bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubelet.conf --kubeconfig=/etc/kubernetes/kubelet.conf --feature-gates=CSIPersistentVolume=true"
    ……
    [root@k8smaster01 ~]# systemctl daemon-reload
    [root@k8smaster01 ~]# systemctl restart kubelet.service

    3.3 创建CRD资源对象

    创建CSINodeInfo和CSIDriverRegistry CRD资源对象:
    [root@k8smaster01 ~]# vi csidriver.yaml
    apiVersion: apiextensions.k8s.io/v1beta1
    kind: CustomResourceDefinition
    metadata:
      name: csidrivers.csi.storage.k8s.io
      labels:
        addonmanager.kubernetes.io/mode: Reconcile
    spec:
      group: csi.storage.k8s.io
      names:
        kind: CSIDriver
        plural: csidrivers
      scope: Cluster
      validation:
        openAPIV3Schema:
          properties:
            spec:
              description: Specification of the CSI Driver.
              properties:
                attachRequired:
                  description: Indicates this CSI volume driver requires an attach operation,and that Kubernetes should call attach and wait for any attach operationto complete before proceeding to mount.
                  type: boolean
                podInfoOnMountVersion:
                  description: Indicates this CSI volume driver requires additional pod
                    information (like podName, podUID, etc.) during mount operations.
                  type: string
      version: v1alpha1
    [root@k8smaster01 ~]# vi csinodeinfo.yaml
    apiVersion: apiextensions.k8s.io/v1beta1
    kind: CustomResourceDefinition
    metadata:
      name: csinodeinfos.csi.storage.k8s.io
      labels:
        addonmanager.kubernetes.io/mode: Reconcile
    spec:
      group: csi.storage.k8s.io
      names:
        kind: CSINodeInfo
        plural: csinodeinfos
      scope: Cluster
      validation:
        openAPIV3Schema:
          properties:
            spec:
              description: Specification of CSINodeInfo
              properties:
                drivers:
                  description: List of CSI drivers running on the node and their specs.
                  type: array
                  items:
                    properties:
                      name:
                        description: The CSI driver that this object refers to.
                        type: string
                      nodeID:
                        description: The node from the driver point of view.
                        type: string
                      topologyKeys:
                        description: List of keys supported by the driver.
                        items:
                          type: string
                        type: array
            status:
              description: Status of CSINodeInfo
              properties:
                drivers:
                  description: List of CSI drivers running on the node and their statuses.
                  type: array
                  items:
                    properties:
                      name:
                        description: The CSI driver that this object refers to.
                        type: string
                      available:
                        description: Whether the CSI driver is installed.
                        type: boolean
                      volumePluginMechanism:
                        description: Indicates to external components the required mechanism
                          to use for any in-tree plugins replaced by this driver.
                        pattern: in-tree|csi
                        type: string
      version: v1alpha1
    [root@k8smaster01 ~]# kubectl apply -f csidriver.yaml
    [root@k8smaster01 ~]# kubectl apply -f csinodeinfo.yaml

    3.4 创建相应RBAC

    [root@k8smaster01 ~]# git clone https://github.com/kubernetes-csi/drivers
    [root@k8smaster01 ~]# cd drivers/deploy/hostpath/
    [root@k8smaster01 hostpath]# vi csi-hostpath-attacher-rbac.yaml
    ---
    apiVersion: v1
    kind: ServiceAccount
    metadata:
      name: csi-attacher
      # replace with non-default namespace name
      namespace: default
    ---
    kind: ClusterRole
    apiVersion: rbac.authorization.k8s.io/v1
    metadata:
      name: external-attacher-runner
    rules:
      - apiGroups: [""]
        resources: ["persistentvolumes"]
        verbs: ["get", "list", "watch", "update"]
      - apiGroups: [""]
        resources: ["nodes"]
        verbs: ["get", "list", "watch"]
      - apiGroups: ["csi.storage.k8s.io"]
        resources: ["csinodeinfos"]
        verbs: ["get", "list", "watch"]
      - apiGroups: ["storage.k8s.io"]
        resources: ["volumeattachments"]
        verbs: ["get", "list", "watch", "update"]
    ---
    kind: ClusterRoleBinding
    apiVersion: rbac.authorization.k8s.io/v1
    metadata:
      name: csi-attacher-role
    subjects:
      - kind: ServiceAccount
        name: csi-attacher
        # replace with non-default namespace name
        namespace: default
    roleRef:
      kind: ClusterRole
      name: external-attacher-runner
      apiGroup: rbac.authorization.k8s.io
    ---
    kind: Role
    apiVersion: rbac.authorization.k8s.io/v1
    metadata:
      # replace with non-default namespace name
      namespace: default
      name: external-attacher-cfg
    rules:
    - apiGroups: [""]
      resources: ["configmaps"]
      verbs: ["get", "watch", "list", "delete", "update", "create"]
    ---
    kind: RoleBinding
    apiVersion: rbac.authorization.k8s.io/v1
    metadata:
      name: csi-attacher-role-cfg
      # replace with non-default namespace name
      namespace: default
    subjects:
      - kind: ServiceAccount
        name: csi-attacher
        # replace with non-default namespace name
        namespace: default
    roleRef:
      kind: Role
      name: external-attacher-cfg
      apiGroup: rbac.authorization.k8s.io
    [root@k8smaster01 hostpath]# vi csi-hostpath-provisioner-rbac.yaml
    ---
    apiVersion: v1
    kind: ServiceAccount
    metadata:
      name: csi-provisioner
      # replace with non-default namespace name
      namespace: default
    ---
    kind: ClusterRole
    apiVersion: rbac.authorization.k8s.io/v1
    metadata:
      name: external-provisioner-runner
    rules:
      - apiGroups: [""]
        resources: ["secrets"]
        verbs: ["get", "list"]
      - 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: ["snapshot.storage.k8s.io"]
        resources: ["volumesnapshots"]
        verbs: ["get", "list"]
      - apiGroups: ["snapshot.storage.k8s.io"]
        resources: ["volumesnapshotcontents"]
        verbs: ["get", "list"]
      - apiGroups: ["csi.storage.k8s.io"]
        resources: ["csinodeinfos"]
        verbs: ["get", "list", "watch"]
      - apiGroups: [""]
        resources: ["nodes"]
        verbs: ["get", "list", "watch"]
    ---
    kind: ClusterRoleBinding
    apiVersion: rbac.authorization.k8s.io/v1
    metadata:
      name: csi-provisioner-role
    subjects:
      - kind: ServiceAccount
        name: csi-provisioner
        # replace with non-default namespace name
        namespace: default
    roleRef:
      kind: ClusterRole
      name: external-provisioner-runner
      apiGroup: rbac.authorization.k8s.io
    ---
    kind: Role
    apiVersion: rbac.authorization.k8s.io/v1
    metadata:
      # replace with non-default namespace name
      namespace: default
      name: external-provisioner-cfg
    rules:
    - apiGroups: [""]
      resources: ["endpoints"]
      verbs: ["get", "watch", "list", "delete", "update", "create"]
    ---
    kind: RoleBinding
    apiVersion: rbac.authorization.k8s.io/v1
    metadata:
      name: csi-provisioner-role-cfg
      # replace with non-default namespace name
      namespace: default
    subjects:
      - kind: ServiceAccount
        name: csi-provisioner
        # replace with non-default namespace name
        namespace: default
    roleRef:
      kind: Role
      name: external-provisioner-cfg
      apiGroup: rbac.authorization.k8s.io
    [root@k8smaster01 hostpath]# vi csi-hostpathplugin-rbac.yaml
    ---
    apiVersion: v1
    kind: ServiceAccount
    metadata:
      name: csi-driver-registrar
      # replace with non-default namespace name
      namespace: default
    ---
    kind: ClusterRole
    apiVersion: rbac.authorization.k8s.io/v1
    metadata:
      name: driver-registrar-runner
    rules:
      - apiGroups: [""]
        resources: ["events"]
        verbs: ["get", "list", "watch", "create", "update", "patch"]
      # The following permissions are only needed when running
      # driver-registrar without the --kubelet-registration-path
      # parameter, i.e. when using driver-registrar instead of
      # kubelet to update the csi.volume.kubernetes.io/nodeid
      # annotation. That mode of operation is going to be deprecated
      # and should not be used anymore, but is needed on older
      # Kubernetes versions.
      # - apiGroups: [""]
      #   resources: ["nodes"]
      #   verbs: ["get", "update", "patch"]
    ---
    kind: ClusterRoleBinding
    apiVersion: rbac.authorization.k8s.io/v1
    metadata:
      name: csi-driver-registrar-role
    subjects:
      - kind: ServiceAccount
        name: csi-driver-registrar
        # replace with non-default namespace name
        namespace: default
    roleRef:
      kind: ClusterRole
      name: driver-registrar-runner
      apiGroup: rbac.authorization.k8s.io
    [root@k8smaster01 hostpath]# kubectl create -f csi-hostpath-attacher-rbac.yaml
    [root@k8smaster01 hostpath]# kubectl create -f csi-hostpath-provisioner-rbac.yaml
    [root@k8smaster01 hostpath]# kubectl create -f csi-hostpathplugin-rbac.yaml

    3.5 正式部署

    [root@k8smaster01 ~]# cd drivers/deploy/hostpath/
    [root@k8smaster01 hostpath]# kubectl create -f csi-hostpath-attacher.yaml
    [root@k8smaster01 hostpath]# kubectl create -f csi-hostpath-provisioner.yaml
    [root@k8smaster01 hostpath]# kubectl create -f csi-hostpathplugin.yaml
    提示:如上相应yaml建议修改镜像源为国内:
    gcr.io ----> gcr.azk8s.cn (国内)
    quay.io ----> quay.azk8s.cn (国内)

    四 测试使用

    4.1 确认验证

    [root@k8smaster01 ~]# kubectl get pods
    clipboard

    4.2 创建StorageClass

    [root@k8smaster01 ~]# vi drivers/examples/hostpath/csi-storageclass.yaml
    apiVersion: storage.k8s.io/v1
    kind: StorageClass
    metadata:
      name: csi-hostpath-sc
    provisioner: csi-hostpath
    reclaimPolicy: Delete
    volumeBindingMode: Immediate
    [root@k8smaster01 ~]# kubectl create -f drivers/examples/hostpath/csi-storageclass.yaml

    4.3 创建PVC

    [root@k8smaster01 ~]# vi drivers/examples/hostpath/csi-pvc.yaml
    apiVersion: v1
    kind: PersistentVolumeClaim
    metadata:
      name: csi-pvc
    spec:
      accessModes:
      - ReadWriteOnce
      resources:
        requests:
          storage: 1Gi
      storageClassName: csi-hostpath-sc
    [root@k8smaster01 ~]# kubectl create -f drivers/examples/hostpath/csi-pvc.yaml
    [root@k8smaster01 ~]# kubectl get pvc
    [root@k8smaster01 ~]# kubectl get pv
    clipboard

    4.4 创建应用

    [root@k8smaster01 ~]# vi drivers/examples/hostpath/csi-app.yaml
    kind: Pod
    apiVersion: v1
    metadata:
      name: my-csi-app
    spec:
      containers:
        - name: my-frontend
          image: busybox
          volumeMounts:
          - mountPath: "/data"
            name: my-csi-volume
          command: [ "sleep", "1000000" ]
      volumes:
        - name: my-csi-volume
          persistentVolumeClaim:
            claimName: csi-pvc
    [root@k8smaster01 ~]# kubectl create -f drivers/examples/hostpath/csi-app.yaml
    [root@k8smaster01 ~]# kubectl get pods
    clipboard

    提示:更多CSI插件示例参考:https://feisky.gitbooks.io/kubernetes/plugins/csi.html。
    CSI官方文档:https://kubernetes-csi.github.io/docs/
  • 相关阅读:
    SpringMVC金课-课程大纲
    Type Cannot change version of project facet Dynamic Web Module to 3.0.
    使用maven 创建web项目 + 搭建SSM框架
    多文件上传
    asp.net 连接access数据库方法
    分享代码
    DIV+CSS解决IE6,IE7,IE8,FF兼容问题(转至http://www.douban.com/note/163291324/)
    asp.net发布网站(转)
    Img垂直居中
    http://www.apkbus.com/android-6231-1.html
  • 原文地址:https://www.cnblogs.com/itzgr/p/12626585.html
Copyright © 2020-2023  润新知