Kubernetes从1.9版本开始引入容器存储接口Container Storage Interface(CSI)机制,用于在Kubernetes和外部存储系统之间建立一套标准的存储管理接口,通过该接口为容器提供存储服务。
Kubernetes通过PV、PVC、Storageclass已经提供了一种强大的基于插件的存储管理机制,但是各种存储插件提供的存储服务都是基于一种被称为“in-true”(树内)的方式提供的,这要求存储插件的代码必须被放进Kubernetes的主干代码库中才能被Kubernetes调用,属于紧耦合的开发模式。这种“in-tree”方式会带来一些问题:
Kubernetes已有的FlexVolume插件机制试图通过为外部存储暴露一个基于可执行程序(exec)的API来解决这些问题。尽管它允许第三方存储提供商在Kubernetes核心代码之外开发存储驱动,但仍然有两个问题没有得到很好的解决:
基于以上这些问题和考虑,Kubernetes逐步推出与容器对接的存储接口标准,存储提供方只需要基于标准接口进行存储插件的实现,就能使用Kubernetes的原生存储机制为容器提供存储服务。这套标准被称为CSI(容器存储接口)。
在CSI成为Kubernetes的存储供应标准之后,存储提供方的代码就能和Kubernetes代码彻底解耦,部署也与Kubernetes核心组件分离,显然,存储插件的开发由提供方自行维护,就能为Kubernetes用户提供更多的存储功能,也更加安全可靠。
基于CSI的存储插件机制也被称为“out-of-tree”(树外)的服务提供方式,是未来Kubernetes第三方存储插件的标准方案。
KubernetesCSI存储插件的关键组件和推荐的容器化部署架构:
其中主要包括两种组件:CSI Controller和CSI Node。
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容器负责具体的存储卷操作。
CSI Node的主要功能是对主机(Node)上的Volume进行管理和操作。在Kubernetes中建议将其部署为DaemonSet,在每个Node上都运行一个Pod。
在这个Pod中部署以下两个容器:
node-driver-registrar容器与kubelet通过Node主机的一个hostPath目录下的unixsocket进行通信。CSI Driver容器与kubelet通过Node主机的另一个hostPath目录下的unixsocket进行通信,同时需要将kubelet的工作目录(默认为/var/lib/kubelet)挂载给CSIDriver容器,用于为Pod进行Volume的管理操作(包括mount、umount等)。
以csi-hostpath插件为例,演示部署CSI插件、用户使用CSI插件提供的存储资源。
设置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
创建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
[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
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: external-attacher-runner
rules:
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: csi-attacher-role
subjects:
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
# replace with non-default namespace name
namespace: default
name: external-attacher-cfg
rules:
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: csi-attacher-role-cfg
# replace with non-default namespace name
namespace: default
subjects:
[root@k8smaster01 hostpath]# vi csi-hostpath-provisioner-rbac.yaml
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: csi-provisioner
# replace with non-default namespace name
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: external-provisioner-runner
rules:
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: csi-provisioner-role
subjects:
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
# replace with non-default namespace name
namespace: default
name: external-provisioner-cfg
rules:
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: csi-provisioner-role-cfg
# replace with non-default namespace name
namespace: default
subjects:
[root@k8smaster01 hostpath]# vi csi-hostpathplugin-rbac.yaml
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: csi-driver-registrar
# replace with non-default namespace name
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: driver-registrar-runner
rules:
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: csi-driver-registrar-role
subjects:
[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
[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 (国内)
[root@k8smaster01 ~]# kubectl get pods
[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
[root@k8smaster01 ~]# vi drivers/examples/hostpath/csi-pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: csi-pvc
spec:
accessModes:
[root@k8smaster01 ~]# kubectl create -f drivers/examples/hostpath/csi-pvc.yaml
[root@k8smaster01 ~]# kubectl get pvc
[root@k8smaster01 ~]# kubectl get pv
[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
**提示:更多CSI插件示例参考:https://feisky.gitbooks.io/kubernetes/plugins/csi.html。**
**CSI官方文档:https://kubernetes-csi.github.io/docs/**
手机扫一扫
移动阅读更方便
你可能感兴趣的文章