kubernetes ceph-csi分析目录导航

Node Driver Registrar分析

node-driver-registrar是一个sidecar容器,通过Kubelet的插件注册机制将CSI plugin(csi driver,两个名词意义一样)注册到Kubelet,让kubelet做volume的mount/umount操作时知道怎么调用相应的csi plugin。

Node Driver Registrar的内容相对简单,将在本文中对其作用、源码、组件间调用逻辑等进行分析。

repo:https://github.com/kubernetes-csi/node-driver-registrar

关联博客

kubelet之csi driver注册分析

Node Driver Registrar启动参数

// cmd/csi-node-driver-registrar/main.go
// Command line flags
var (
connectionTimeout = flag.Duration("connection-timeout", 0, "The --connection-timeout flag is deprecated")
csiAddress = flag.String("csi-address", "/run/csi/socket", "Path of the CSI driver socket that the node-driver-registrar will connect to.")
kubeletRegistrationPath = flag.String("kubelet-registration-path", "", "Path of the CSI driver socket on the Kubernetes host machine.")
showVersion = flag.Bool("version", false, "Show version.")
version = "unknown" // List of supported versions
supportedVersions = []string{"1.0.0"}
)

下面讲解下最关键的两个启动参数,主要是配置2个socket地址。

(1)csi-address

csi plugin组件暴露的grpc服务socket地址。

(2)kubelet-registration-path

Node Driver Registrar容器暴露的grpc服务socket地址,同时kubelet也会通过该socket地址访问Node Driver Registrar容器的接口,主要用于向kubelet注册csi plugin。

Node Driver Registrar容器权限

(1)RBAC:Node Driver Registrar容器没有访问kubernetes API的需求,所以不用做相关的RBAC配置。

(2)需要将前面提到的2个socket的父目录作为hostPath挂载进容器中,并对socket拥有创建、删除、访问等权限(通过配置containers[].securityContext.privileged=true获得权限)。

Node Driver Registrar容器部署yaml

Node-Driver-Registrar容器与csi plugin NodeServer容器一起,使用daemonset部署,即每个node节点都有。

Node-Driver-Registrar容器的部署yaml如下:

    containers:
- name: driver-registrar-rbd
# This is necessary only for systems with SELinux, where
# non-privileged sidecar containers cannot access unix domain socket
# created by privileged CSI driver container.
securityContext:
privileged: true
image: quay.io/k8scsi/csi/csi-node-driver-registrar:v1.3.0
args:
- "--v=5"
- "--csi-address=/csi/csi.sock"
- "--kubelet-registration-path=/var/lib/kubelet/plugins/rbd.csi.ceph.com/csi.sock"
lifecycle:
preStop:
exec:
command: [
"/bin/sh", "-c",
"rm -rf /registration/rbd.csi.ceph.com \
/registration/rbd.csi.ceph.com-reg.sock"
]
env:
- name: KUBE_NODE_NAME
valueFrom:
fieldRef:
fieldPath: spec.nodeName
volumeMounts:
- name: socket-dir
mountPath: /csi
- name: registration-dir
mountPath: /registration
imagePullPolicy: "Always"
volumes:
- name: socket-dir
hostPath:
path: /var/lib/kubelet/plugins/rbd.csi.ceph.com
type: DirectoryOrCreate
- name: registration-dir
hostPath:
path: /var/lib/kubelet/plugins_registry/
type: Directory

Node Driver Registrar注册csi plugin driver步骤

第 1 步

Node Driver Registrar连接csi plugin组件暴露的grpc服务socket地址,调用GetPluginInfo接口,获取csi plugin的driver名称。

第 2 步

kubelet-registration-path目录下启动一个 socket,对外暴露GetInfo 和 NotifyRegistrationStatus 两个接口。kubelet 通过 Watcher可以发现该socket。

第 3 步

kubelet 通过 Watcher监控/var/lib/kubelet/plugins_registry/目录,发现上述socket 后,通过该 socket 调用 Node-Driver-Registrar 的 GetInfo 接口,获取csi plugin组件暴露的grpc服务socket地址以及csi plugin组件的driver名称。

第 4 步

kubelet 通过csi plugin组件暴露的grpc服务socket地址对其NodeGetInfo接口进行调用,获取csi plugin的nodeID等信息。

第 5 步

kubelet根据上一步获得的信息,去更新node节点的 Annotations、Labels、status.allocatable 等信息,同时创建(或更新)一个 CSINode 对象。

第 6 步

kubelet通过socket调用Node-Driver-Registrar容器的NotifyRegistrationStatus接口,通知注册csi plugin成功。

通过以上 6 步就实现了 csi plugin注册机制。

Node Driver Registrar源码分析

下面结合Node Driver Registrar的源码对注册csi plugin driver步骤进行详细分析。主要分析main()、nodeRegister()、GetInfo()与NotifyRegistrationStatus()。

1.main()

先从main()入手。

主要逻辑:

(1)组件启动参数校验;

(2)连接csi plugin组件暴露的grpc服务socket地址,调用GetPluginInfo接口,获取csi plugin的driver名称;

(3)调用nodeRegister方法做csi plugin注册操作。

// cmd/csi-node-driver-registrar/main.go
func main() {
klog.InitFlags(nil)
flag.Set("logtostderr", "true")
flag.Parse() if *kubeletRegistrationPath == "" {
klog.Error("kubelet-registration-path is a required parameter")
os.Exit(1)
} if *showVersion {
fmt.Println(os.Args[0], version)
return
}
klog.Infof("Version: %s", version) if *connectionTimeout != 0 {
klog.Warning("--connection-timeout is deprecated and will have no effect")
} // Once https://github.com/container-storage-interface/spec/issues/159 is
// resolved, if plugin does not support PUBLISH_UNPUBLISH_VOLUME, then we
// can skip adding mapping to "csi.volume.kubernetes.io/nodeid" annotation. klog.V(1).Infof("Attempting to open a gRPC connection with: %q", *csiAddress)
csiConn, err := connection.Connect(*csiAddress)
if err != nil {
klog.Errorf("error connecting to CSI driver: %v", err)
os.Exit(1)
} klog.V(1).Infof("Calling CSI driver to discover driver name")
ctx, cancel := context.WithTimeout(context.Background(), csiTimeout)
defer cancel() csiDriverName, err := csirpc.GetDriverName(ctx, csiConn)
if err != nil {
klog.Errorf("error retreiving CSI driver name: %v", err)
os.Exit(1)
} klog.V(2).Infof("CSI driver name: %q", csiDriverName) // Run forever
nodeRegister(csiDriverName)
}

2.nodeRegister()

nodeRegister()用于向kubelet注册csi plugin。主要逻辑:

(1)调用newRegistrationServer()初始化registrationServer结构体;

(2)在 kubelet-registration-path目录下启动一个 socket,对外暴露GetInfo 和 NotifyRegistrationStatus 两个接口(kubelet 通过 Watcher可以发现该socket)。

// cmd/csi-node-driver-registrar/node_register.go
func nodeRegister(
csiDriverName string,
) {
// When kubeletRegistrationPath is specified then driver-registrar ONLY acts
// as gRPC server which replies to registration requests initiated by kubelet's
// pluginswatcher infrastructure. Node labeling is done by kubelet's csi code.
registrar := newRegistrationServer(csiDriverName, *kubeletRegistrationPath, supportedVersions)
socketPath := fmt.Sprintf("/registration/%s-reg.sock", csiDriverName)
if err := util.CleanupSocketFile(socketPath); err != nil {
klog.Errorf("%+v", err)
os.Exit(1)
} var oldmask int
if runtime.GOOS == "linux" {
// Default to only user accessible socket, caller can open up later if desired
oldmask, _ = util.Umask(0077)
} klog.Infof("Starting Registration Server at: %s\n", socketPath)
lis, err := net.Listen("unix", socketPath)
if err != nil {
klog.Errorf("failed to listen on socket: %s with error: %+v", socketPath, err)
os.Exit(1)
}
if runtime.GOOS == "linux" {
util.Umask(oldmask)
}
klog.Infof("Registration Server started at: %s\n", socketPath)
grpcServer := grpc.NewServer()
// Registers kubelet plugin watcher api.
registerapi.RegisterRegistrationServer(grpcServer, registrar) // Starts service
if err := grpcServer.Serve(lis); err != nil {
klog.Errorf("Registration Server stopped serving: %v", err)
os.Exit(1)
}
// If gRPC server is gracefully shutdown, exit
os.Exit(0)
}
newRegistrationServer()
// cmd/csi-node-driver-registrar/main.go
// NewregistrationServer returns an initialized registrationServer instance
func newRegistrationServer(driverName string, endpoint string, versions []string) registerapi.RegistrationServer {
return &registrationServer{
driverName: driverName,
endpoint: endpoint,
version: versions,
}
}

3.GetInfo()

GetInfo():kubelet 通过调用 Node-Driver-Registrar 的 GetInfo 接口,获取csi plugin组件暴露的grpc服务socket地址以及csi plugin组件的driver名称。

// GetInfo is the RPC invoked by plugin watcher
func (e registrationServer) GetInfo(ctx context.Context, req *registerapi.InfoRequest) (*registerapi.PluginInfo, error) {
klog.Infof("Received GetInfo call: %+v", req)
return &registerapi.PluginInfo{
Type: registerapi.CSIPlugin,
Name: e.driverName,
Endpoint: e.endpoint,
SupportedVersions: e.version,
}, nil
}

4.NotifyRegistrationStatus()

NotifyRegistrationStatus():kubelet通过调用Node-Driver-Registrar的NotifyRegistrationStatus接口,通知注册csi plugin成功。

// GetInfo is the RPC invoked by plugin watcher
func (e registrationServer) NotifyRegistrationStatus(ctx context.Context, status *registerapi.RegistrationStatus) (*registerapi.RegistrationStatusResponse, error) {
klog.Infof("Received NotifyRegistrationStatus call: %+v", status)
if !status.PluginRegistered {
klog.Errorf("Registration process failed with error: %+v, restarting registration container.", status.Error)
os.Exit(1)
} return &registerapi.RegistrationStatusResponse{}, nil
}

总结

Node Driver Registrar作用

  • [x] node-driver-registrar是一个sidecar容器,通过Kubelet的插件注册机制将CSI plugin(csi driver,两个名词意义一样)注册到Kubelet,让kubelet做volume的mount/umount操作时知道怎么调用相应的csi plugin。

Node Driver Registrar涉及的两个socket

(1)csi-address

csi plugin组件暴露的grpc服务socket地址。

(2)kubelet-registration-path

Node Driver Registrar容器暴露的grpc服务socket地址,同时kubelet也会通过该socket地址访问Node Driver Registrar容器的接口,主要用于向kubelet注册csi plugin。

kubelet分析-csi driver注册分析-Node Driver Registrar源码分析的更多相关文章

  1. Spring事务源码分析专题(一)JdbcTemplate使用及源码分析

    Spring中的数据访问,JdbcTemplate使用及源码分析 前言 本系列文章为事务专栏分析文章,整个事务分析专题将按下面这张图完成 对源码分析前,我希望先介绍一下Spring中数据访问的相关内容 ...

  2. Java源码分析:Guava之不可变集合ImmutableMap的源码分析

    一.案例场景 遇到过这样的场景,在定义一个static修饰的Map时,使用了大量的put()方法赋值,就类似这样-- public static final Map<String,String& ...

  3. [源码分析]Java1.8中StringJoiner的使用以及源码分析

    [源码分析]StringJoiner的使用以及源码分析 StringJoiner是Java里1.8新增的类, 或许有一部分人没有接触过. 所以本文将从使用例子入手, 分析StringJoiner的源码 ...

  4. 从flink-example分析flink组件(1)WordCount batch实战及源码分析

    上一章<windows下flink示例程序的执行> 简单介绍了一下flink在windows下如何通过flink-webui运行已经打包完成的示例程序(jar),那么我们为什么要使用fli ...

  5. Spring Cloud Eureka源码分析之三级缓存的设计原理及源码分析

    Eureka Server 为了提供响应效率,提供了两层的缓存结构,将 Eureka Client 所需要的注册信息,直接存储在缓存结构中,实现原理如下图所示. 第一层缓存:readOnlyCache ...

  6. MyBatis原理分析之四:一次SQL查询的源码分析

    上回我们讲到Mybatis加载相关的配置文件进行初始化,这回我们讲一下一次SQL查询怎么进行的. 准备工作 Mybatis完成一次SQL查询需要使用的代码如下: ) { ); ) { throw ne ...

  7. kubelet分析-csi driver注册源码分析

    kubelet注册csi driver分析 kubelet注册csi driver的相关功能代码与kubelet的pluginManager有关,所以接下来对pluginManager进行分析.分析将 ...

  8. MyBatis 源码分析 - 配置文件解析过程

    * 本文速览 由于本篇文章篇幅比较大,所以这里拿出一节对本文进行快速概括.本篇文章对 MyBatis 配置文件中常用配置的解析过程进行了较为详细的介绍和分析,包括但不限于settings,typeAl ...

  9. 14、master原理与源码分析

    一.主备切换机制原理剖析 1.图解 2.部分源码 ###master.scala中的completeRecovery方法: /* * 完成Master的主备切换 */ def completeReco ...

随机推荐

  1. C++PRIMER第五版练习题答案第一章

    C++PRIMER第五版练习题答案第一章 应该有很多小伙伴和我一样,闲来无事买了本C++的书自己啃,课后的练习题做的很揪心,这里我分享下我写的答案,希望能帮助到你,提供源码,就不跑了哈,毕竟现在是第一 ...

  2. cmake和make

    学计算机的,在写代码的时候,IDE安装好,环境按着教程配置好,就直接代码了,编辑器的具体原理只是一知半解,现在来系统学习一下,为了方便以后学习HElib! make和cmake 写程序大体步骤为: 1 ...

  3. [java] XML DTD XSD

    XML是用来干什么的 https://bbs.csdn.net/topics/120762 https://blog.csdn.net/Rain722/article/details/52925828 ...

  4. [bug] Python AttributeError: module 'web' has no attribute 'application'

    原因 文件名是web.py,与包名web冲突 解决 重命名文件,再运行

  5. Linux硬件与服务

    Linux硬件与服务 Linux Linux硬件与服务 1 Linux磁盘管理与磁盘结构 磁盘的组成结构 盘片的逻辑结构 分区格式化 实例说明: 2 磁盘管理之Block.iNode. super.s ...

  6. cut命令用于按“列”提取文本字符,格式为“cut [参数] 文本”

    8.cut命令 cut命令用于按"列"提取文本字符,格式为"cut [参数] 文本". 在Linux系统中,如何准确地提取出最想要的数据,这也是我们应该重点学习 ...

  7. 054.Python之Ubuntu安装Pycharm

    在学习Django的时候,开始使用的是centos,但是在做的时候,有一个错误,换一个ubuntu环境,安装一个pycharm进行学习开发 1. 下载PyCharm安装包 进入官网下载包 下载后 2. ...

  8. shell应用之下载rpm包

    1 #!/bin/bash 2 read -p "选择下载老师的哪种源:(adv,base,cobbler,docker,mysql,mysql57,open,auto)" dow ...

  9. 【JDK命令行 一】手动编译Java源码与执行字节码命令合集(含外部依赖引用)

    写作目标 记录常见的使用javac手动编译Java源码和java手动执行字节码的命令,一方面用于应对 Maven 和 Gradle 暂时无法使用的情况,临时生成class文件(使用自己的jar包):另 ...

  10. kylin的rowkey优化之调整rowkey顺序

    在以hbase为存储的cuboid中,会有很多计算好的数据行,这每个行的key都是由维度值按顺序生成的rowkey 而这个顺序,在我们做cube设计的时候是可以调整的. 具体调整路径是:cube de ...