K8S存储插件-FlexVolume && CSI

21 篇文章 3 订阅
18 篇文章 3 订阅
K8S的自定义存储插件

和K8S的网络不太一样,K8S的网络只有CNI一种接口暴露方式,所有的网络实现基于第三方进行开发实现,但存储的内置实现就多达20多种,#K8S目前支持的插件类型#。但内置的往往不满足定制化的需求,所以和CNI 一样,K8S 也暴露了对外的存储接口,和CNI 一样,通过实现对应的接口方法,即可创建属于自己的存储插件,但和CNI 有点区别的是,K8S的存储插件的自定义实现方式,有FlexVolume 和 CSI 两种,两者的差别可以看做是新老功能的差异,但目前为止,FlexVolume 同样也有用武之地。

FlexVolume

熟悉CNI的编写方法的,对FlexVolume的编写一定不陌生,CNI编写完成后,是会拆分为2个二进制文件(CNI,IPAM)和一个配置文件,放在每个Node节点上,kubelet在创建Pod 时候,会调用对应的二进制文件进行网络的创建,同样也可以使用daemonset的方式容器化部署,FlexVolume 也一样,编写完成后一样以二进制的方式进行部署,和CNI 一样,FlexVolume需要实现类似CNI的cmdadd,cmddel的方法,具体需要实现以下几个方法:

  • init:kubelet/kube-controller-manager 初始化存储插件时调用,插件需要返回是否需要attach 和 detach 操作
  • attach:将存储卷挂载到 Node 上
  • detach:将存储卷从 Node 上卸载
  • waitforattach: 等待 attach 操作成功(超时时间为 10 分钟)
  • isattached:检查存储卷是否已经挂载
  • mountdevice:将设备挂载到指定目录中以便后续 bind mount 使用
  • unmountdevice:将设备取消挂载
  • mount:将存储卷挂载到指定目录中
  • umount:将存储卷取消挂载

基本返回格式:

{
    "status": "<Success/Failure/Not supported>",
    "message": "<Reason for success/failure>",
    "device": "<Path to the device attached. This field is valid only for attach & waitforattach call-outs>"
    "volumeName": "<Cluster wide unique name of the volume. Valid only for getvolumename call-out>"
    "attached": <True/False (Return true if volume is attached on the node. Valid only for isattached call-out)>
    "capabilities": <Only included as part of the Init response>
    {
        "attach": <True/False (Return true if the driver implements attach and detach)>
    }
}

那么kublet和他的调用关系是啥?看一下kubelet调用的FlexVolume的一段代码(pod mount dir):

// SetUpAt creates new directory.
func (f *flexVolumeMounter) SetUpAt(dir string, fsGroup *int64) error {
  ...
  call := f.plugin.NewDriverCall(mountCmd)
  
  // Interface parameters
  call.Append(dir)
  
  extraOptions := make(map[string]string)
  
  // pod metadata
  extraOptions[optionKeyPodName] = f.podName
  extraOptions[optionKeyPodNamespace] = f.podNamespace
  
  ...
  
  call.AppendSpec(f.spec, f.plugin.host, extraOptions)
  
  _, err = call.Run()
  
  ...
  
  return nil
}

再看下一个PV的yml的栗子对比一下:

apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv-flex-nfs
spec:
  capacity:
    storage: 1Gi
  accessModes:
    - ReadWriteMany
  flexVolume:
    driver: "k8s/nfs"
    fsType: "nfs"
    options:
      server: "1.1.1.1" 
      share: "export"

先只看FlexVolume, dirver这里的k8s/nfs 就是FlexVolume的具体位置,注意k8s~nfs解析出来的就是k8s/nfs, FlexVolume的默认位置在/usr/libexec/kubernetes/kubelet-plugins/volume/exec/,所以上述yml用的FlexVolume插件具体位置在/usr/libexec/kubernetes/kubelet-plugins/volume/exec/k8s~nfs/nfs

pv的yml 里面有对应的options, 就是kubelet代码里的extraOptions := make(map[string]string),是一个map类型,kubelet解析yml里面的option参数,传入该map变量,然后执行FlexVolume的具体方法,比如栗子里的mount,将options的参数传入,实现了如下的效果:

/usr/libexec/kubernetes/kubelet-plugins/volume/exec/k8s~nfs/nfs mount <mount dir> <json param>

git 上fork的几个demo,方便查询。

可以看到FlexVolume实现逻辑非常简单,但解决的问题也非常有限,用户还是需要手动创建PV,且每次调用插件执行的都是偏原子操作的,即单次只执行attach,mount,umount等动作,所以,其作用,只是一个针对不同存储自定义创建PV的插件,假设我需要动态生成PV 并动态绑定PVC,FlexVolume就不具备可操作性,所以CSI来了。

CSI

先说下CSI和FlexVolume的基本差异,FlexVolume实现了Attach(挂载存储到Node)和Mount(Node的目录挂载到Pod), 缺少了PV的动态生成(需要运维手动在存储上配置然后再创建手动创建PV),而CSI就是在FlexVolume的基础上,实现了PV的动态生成。

CSI的调用和FlexVolume不一样,在调用的时候,需要有一个注册的过程,找个CSI的代码看下:

简单先描述一下调用顺序:

  1. driver.go, 主要是Run()方法,启动RPC服务,注册到CSI.
  2. identity.go, 主要是GetPluginInfo()方法,获取插件的各类信息,如插件名字等,GetPluginCapabilities,获取CSI插件的各项功能,比如是否支持Attach之类的,还有个Probe()方法,提供给K8s的探针,用于健康检查CSI的状态。
  3. controller.go, CSI实现的具体方法,比如操作存储(CreateVolume 和 DeleteVolume),Attach存储(ControllerPublishVolume 和 ControllerUnpublishVolume方法)
  4. node.go, 这一步主要实现的是mount的操作,即将目录挂载到Pod里,但是和简单的mount方式不一样,这里分为了MountDevice(预处理,挂载到一个临时目录进行格式化) 和 SetUp(最终绑定,将临时目录绑定到实际的目录), 分别对应了NodeStageVolume/NodeUnstageVolume 和 NodePublishVolume/NodeUnpublishVolume 方法。

上面只是描述了CSI插件的调用顺序,那么问题来了,每一步,分别是谁去调用的呢?
回过头先看下CSI的架构图:
在这里插入图片描述


发现CSI的架构实际分了3块,第一块K8S-Core,即K8S的核心组件,第二块Kubernetes External Component, 这是Kubernetes支持CSI的扩展组件,第三块External Component:传统意义上的CSI,即上面的那个demo代码。从官网架构图的箭头可以看到整体的调用关系:

  1. daemonset在每台主机上运行了driver-registrar的container,和kubelet一一对应。
  2. kubelet调用driver-registrar,driver-registrar向CSI indentity(即代码里的driver.go和identity.go)进行了注册,并获取了CSI 插件的基本功能以及信息。
  3. External provisioner watch 了master的apiserver,监听pvc对象,一旦发现有创建, 则External provisioner会调用CSI Controller(调用了controller.go 里的CreateVolume/DeleteVolume方法)进行了存储端的创建,即自动生成了PV。
  4. External attacher,监听了VolumeAttachment对象,一个发现有挂载,则调用CSI Controller 和 CSI Node进行卷的Attach和mount操作(分别调用了controller.go和node.go)。

第二块External Component的下载地址

从上面的调用逻辑可以看出,出了CSI本体(这里暂称为CSI Driver),还需要部署External Component里的三个container,且这3个container里只有driver-registrar需要和kubelet调用,所以在实际部署中,需要以daemonset的方式,将driver-registrar和CSI Driver作为side-car模式的部署方式进行部署,其他2个External provisioner和 External attacher以statefulset的方式,和CSI Driver一起作为side-car模式的部署方式进行部署。
简单画个部署图:
在这里插入图片描述

个人公众号, 分享一些日常开发,运维工作中的日常以及一些学习感悟,欢迎大家互相学习,交流

在这里插入图片描述

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: k8s网络插件-flannel 部署: 1. 安装etcd Flannel需要etcd来存储网络配置信息,因此需要先安装etcd。可以使用以下命令安装: ``` $ sudo apt-get update $ sudo apt-get install etcd ``` 2. 下载flannel二进制文件 可以从github上下载flannel的二进制文件,例如: ``` $ wget https://github.com/coreos/flannel/releases/download/v.13.1/flannel-v.13.1-linux-amd64.tar.gz $ tar -zxvf flannel-v.13.1-linux-amd64.tar.gz ``` 3. 部署flannel 可以使用以下命令部署flannel: ``` $ sudo ./flanneld --etcd-endpoints=http://<etcd-ip>:2379 --iface=<interface> ``` 其中,`<etcd-ip>`是etcd的IP地址,`<interface>`是flannel要使用的网络接口。 4. 配置kubelet 在每个节点上,需要配置kubelet以使用flannel。可以在kubelet的启动参数中添加以下参数: ``` --network-plugin=cni --cni-conf-dir=/etc/cni/net.d --cni-bin-dir=/opt/cni/bin ``` 5. 部署flannel网络 可以使用以下命令部署flannel网络: ``` $ kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml ``` 6. 验证flannel网络 可以使用以下命令验证flannel网络是否正常: ``` $ kubectl get pods --all-namespaces -o wide ``` 如果所有的pod都处于Running状态,则说明flannel网络已经正常部署。 ### 回答2: 在Kubernetes集群中,网络插件是一个非常重要的组件,负责实现集群中各个节点之间的通信,同时也支持容器和宿主机之间的通信。Flannel就是一款常见的Kubernetes网络插件,下面将为你介绍Flannel如何部署。 1. 编写Flannel配置文件 在部署Flannel之前,需要先编写Flannel的配置文件。创建一个yaml文件,填写以下内容: ``` apiVersion: v1 kind: ConfigMap metadata: name: kube-flannel-cfg namespace: kube-system data: cni-conf.json: | { "name": "cbr0", "plugins": [ { "type": "flannel", "delegate": { "hairpinMode": true, "isDefaultGateway": true } }, { "type": "portmap", "capabilities": { "portMappings": true } } ] } ``` 保存文件为flannel-config.yaml。 2. 创建Flannel服务账号 创建一个服务账号,运行以下命令: ``` kubectl apply -f https:/raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml ``` 这个命令将会自动部署Flannel服务并创建相关资源。 3. 部署Flannel 接下来,运行以下命令来部署Flannel: ``` kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/v0.9.1/Documentation/kube-flannel.yml ``` 这个命令会创建一个DeamonSet对象,这个对象会在集群中的每个节点上运行一个Flannel容器。 4. 验证Flannel部署 在完成Flannel安装之后,可以通过运行以下命令来检查是否一切顺利: ``` kubectl get pods -n kube-system ``` 如果输出结果中包含有flannel开头的Pod,则表示Flannel已经成功部署。 总结 刚才我们介绍了如何在Kubernetes集群中部署Flannel网络插件,主要的步骤包括编写Flannel配置文件、创建Flannel服务账号、部署Flannel、验证Flannel部署等。通过这个过程,我们可以更加深入地了解Flannel的配置和使用方法,还可以通过这个代码来学习如何使用Kubernetes的API进行资源的创建和管理。 ### 回答3: k8s网络插件-flannel部署 k8s是一个分布式系统,为了实现各个节点之间的通信,需要有一个网络插件来管理网络连接。其中,Flannel就是最常用的一种网络插件,它主要的作用是将各个节点的IP地址进行转换,而流量则通过这些IP地址进行转发,从而实现多个节点之间的网络通信。 Flannel的部署主要分为以下几个步骤: 1.安装etcd 在节点中安装etcd,可以使用yum或apt-get等包管理器进行安装。在这个过程中,需要注意etcd的版本和操作系统之间的兼容性,以避免出现问题。 2.部署flannel 可以先下载最新的flannel二进制文件,然后将其部署到各个节点上。在这个过程中,需要修改flannel的配置文件,以指定etcd的地址和网络配置等相关信息。 3.配置kubelet和kube-proxy 为了让k8s系统能够正常地使用flannel网络插件,需要对kubelet和kube-proxy进行配置。可以通过修改它们的启动配置文件,将其网络模式设置为flannel,并指定相关参数。 4.测试网络连接 在完成以上步骤后,可以使用一些工具来测试节点之间的网络连接情况,例如ping命令和nslookup命令等。如果连接正常,就可以开始在k8s系统中进行容器的部署和管理了。 总的来说,Flannel是k8s系统中必不可少的一个组件,它可以帮助我们有效地管理节点之间的网络连接,从而达到更好的分布式系统效果。在部署Flannel时需要注意一些细节,以确保其正常运作,并加强系统的可靠性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值