一 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存储插件的关键组件和推荐的容器化部署架构:
其中主要包括两种组件: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

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

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

提示:更多CSI插件示例参考:https://feisky.gitbooks.io/kubernetes/plugins/csi.html。


CSI官方文档:https://kubernetes-csi.github.io/docs/

045.集群存储-CSI存储机制的更多相关文章

  1. openstack高可用集群15-后端存储技术—GlusterFS(分布式存储)

         

  2. [How to]HBase集群备份方法--Replication机制

    1.简介 HBase备份的方法在[How to]HBase集群备份方法文章中已经有些介绍,但是这些方法都不是HBase本身的特性在支持,都是通过MR计算框架结合HBase客户端的方式,或者直接拷贝HB ...

  3. Jetty集群配置Session存储到MySQL、MongoDB

    在Web开发中,Session表示HTTP服务器与客户端(例如浏览器)的“会话”,每个客户端会有其对应的Session保存在服务器端,通常用来保存和客户端关联的一些信息,例如是否登录.购物车等. Se ...

  4. Jetty容器集群配置Session存储到MySQL、MongoDB

    在Web开发中,Session表示HTTP服务器与客户端(例如浏览器)的"会话",每个客户端会有其对应的Session保存在服务器端,通常用来保存和客户端关联的一些信息,例如是否登 ...

  5. 通过Heketi管理GlusterFS为K8S集群提供持久化存储

    参考文档: Github project:https://github.com/heketi/heketi MANAGING VOLUMES USING HEKETI:https://access.r ...

  6. 二十八. Ceph概述 部署Ceph集群 Ceph块存储

    client   :192.168.4.10 node1 :192.168.4.11 ndoe2 :192.168.4.12 node3 :192.168.4.13   1.实验环境 准备四台KVM虚 ...

  7. 设置Hadoop+Hbase集群pid文件存储位置

    有时候,我们对运行几天或者几个月的hadoop或者hbase集群做停止操作,会发现,停止命令不管用了,为什么呢? 因为基于java开发的程序,想要停止程序,必须通过进程pid来确定,而hadoop和h ...

  8. k8s教程:Kubernetes集群使用网络存储NFS

    NFS存储 NFS即网络文件系统Network File System,它是一种分布式文件系统协议,最初是由Sun MicroSystems公司开发的类Unix操作系统之上的一款经典网络存储方案,其功 ...

  9. java架构之路-(分布式zookeeper)zookeeper集群配置和选举机制详解

    上次博客我们说了一下zookeeper的配置文件,以及命令的使用https://www.cnblogs.com/cxiaocai/p/11597465.html.我们这次来说一下我们的zookeepe ...

随机推荐

  1. C++走向远洋——(项目二、存储班长信息的学生类、派生)

    */ * Copyright (c) 2016,烟台大学计算机与控制工程学院 * All rights reserved. * 文件名:text.cpp * 作者:常轩 * 微信公众号:Worldhe ...

  2. SpringBoot整合Swagger2案例,以及报错:java.lang.NumberFormatException: For input string: ""原因和解决办法

    原文链接:https://blog.csdn.net/weixin_43724369/article/details/89341949 SpringBoot整合Swagger2案例 先说SpringB ...

  3. [译]HTML&CSS Lesson7: 设置背景和渐变色

    背景对网站的设计有重大的影响.它有利于建立网站的整体感觉,设置分组,分配优先级,对网站的可用性也有相当大的影响. 在CSS中,元素的背景可以是一个纯色,一张图,一个渐变色或者它们的组合.在我们决定如何 ...

  4. DOM3中的自定义事件

    DOM3级还定义了自定义事件,自定义事件不是由DOM原生触发的,它的目的是让开发人员创建自己的事件.要创建的自定义事件可以由createEvent("CustomEvent"); ...

  5. python从一个目录中复制全部文件图片至另一个目录中,及删除指定目录中的图片

    import shutil import os #目录自己改一下即可,复制 path = "./static/imgs/" new_path = "./static/up ...

  6. vue相关坑

    1:vue 动态加载图片路径报错解决方法,循环遍历图片不显示图片 解决方法:https://www.cnblogs.com/qingcui277/p/8930507.html

  7. angular - collapse--TemplateRef

    用的ant  collapse组件 需要自定义Header 请忽略前面的dw... 主要是TemplateRef<void> 查了半天.可以实现效果,直接上代码,我也不懂为什么 反正实现了 ...

  8. web前端问题整理

    1.常用那几种浏览器测试?有哪些内核(Layout Engine)? (Q1)浏览器:IE,Chrome,FireFox,Safari,Opera (Q2)内核:Trident,Gecko,Prest ...

  9. Map - 与君初相识

    前言 生活中,我们常会看到这样一种集合:IP地址与主机名,身份证号与个人等,这种一 一对应的关系,就叫做映射.Java提供了专门的集合类用来存放这种对应关系的对象,即 java.util.Map 接口 ...

  10. python虚拟环境安装使用

    # 安装 pip install virtualenv pip install virtualenvwrapper-win # win环境下 liunx下不需要-win #创建一个文件夹并cd进去mk ...