最近在研究 OpenStack Manila 的代码,总结成这篇文章,介绍了 Manila Share 主要代码和设计,重点在其网络的实现上。

Manila 网络模块

tags: Manila Network


前言

Manila 是目前比较完善的一个 OpenStack PaaS 服务组件,它需要借助 Neutron 来完成其管理和网络连接,其网络架构主要如下图,本文会主要介绍 Manila 的网络组件代码,而不是其网络架构。

Manila 网络逻辑架构

对于一个类似的 PaaS 项目,其主要需求是在 Neutron 上启动属于自己的 Service Network 和 Service Port,项目的 Agent 可以通过 Service Port SSH 连接到处于 Service Network 的 Service VM。

启动

服务的启动

先看 Manila 的启动过程。Manila share 的启动没有像 Neutron 的 agent 一样直接运行特定的main()函数,而是在manila/bin/manila-service通过service完成实例化,实例化的类并不是一个hard-code的类,而是可以通过share_manager这个配置修改的,其运行过程如下:

Driver 的加载

实例化share_manager时,首先获得配置文件对象,然后加载 driver,默认为GenericShareDriver

GenericShareDriver 中的 service_instance_manager

加载 Nova、Neutron API

加载GenericShareDriver时会维护一个ssh_connections字典和service_instance_manager,这个service_instance_manager将去调用 Nova、Neutron 等的 API,它需要至少指定一个 Service VM 的用户:

实例化 Neutron API 类时,Manila 会尝试去获取一些东西,首先尝试获得admin_tenant_id(这是neutron.API的一个用@property修饰的函数,如果当前没有一个 token 的话,它会用 neutron 的用户名和密码去 keystone 的 endpoint 获取 token,此时 neutron client 会执行_extract_service_catalog,设置auth_tenant_id,如果已经有了 token 说明 client 已经执行过这个过成立,就直接返回),以确定到 Neutron 的连通性,然后再获得 Service Network ID、加载 Interface Driver(默认为manila.network.linux.interface.OVSInterfaceDriver)、配置 Service instance 网络,如果在配置文件打开了connect_share_server_to_tenant_network,还会执行connect_share_server_to_tenant_network给 Service VM 增加一个到用户网络的虚拟网卡,下面为其关键部分代码:

获取 Service Network

_get_service_network()这个函数是同步化的,因为他会根据配置文件里的service_network_name来获取 Network,如果有多个就报错,如果没有就主动建立,为了避免多个实例同时进入,需要在这个函数上加锁(这里的锁只是一个本地锁,所以请尽量避免多节点同时启动 manila-share)。

重要的 _setup_connectivity_with_service_instances

Instance Driver 是 Manila 与 Service VM 连接用的驱动,主要实现了plugunplug这两个方法。
_setup_connectivity_with_service_instances()是 Mainila 网络模块里一个比较重要的函数,这个函数完成了创建 Service port(查找 device id 为 manila-share 的 port,如果数量大于 1 则报错,为空则创建一个并设置好其 device id、device owner 和 host_id。这个函数也是同步化的,头部加了@utils.synchronized的装饰器)、同步 port(检查 Service Network 下有无 port 没有加入的子网,如果有则将其加进去。这个函数也是同步化的)、将 port 连入 ovs 上的 br-int(如果已存在同名的 tap 设备会报错,否则是执行

这个命令,然后执行ip link set tapXXXXXXXX-XX address XX:XX:XX:XX:XX:XX来设置 MAC 地址,最后将其 up 起来,注意当设备处于 UP 状态后,内核将会根据这个设备的 CIDR 地址自动添加路由表,manila 不会去维护这个路由表)、给 port 设置 ip 地址(先检查已有的 IP 地址,如果已有的 IP 里有需要的 IP 则保留,否则删掉)、检查路由表(先执行ip route list proto kernel dev tapXXXXXXXX-XX获取 Service Port 上的路由表,再挨个获取路由项对应的子网,再用ip list proto kernel match SUBNET获取对指定网段的路由表项,检查 Service port 是不是第一个,如果不是则将处于第一个的路由表项删掉然后再通过 append 添加)和清理过期设备(先获取所有 tap 开头的设备,然后检查其 CIDR 地址是否与现在的 Service Port 重复,如果有就执行 VIF Driver 的 unplug 方法)。

服务的初始化检查

至此 Manager 的实例化过程基本结束。之后 service 会执行 start 方法(见附录一),将启动 RPC 服务、做定时状态报告等,在这里我们只关心其调用的 init_host

首先执行 Driver 的do_setup,前面我们知道我们的默认 Driver 是GenericShareDriver,在这里再一次执行了 Nova API 和 Neutron API 的实例化,然后获取 host 在这台机器上的所有 share,依次执行ensure_share方法,确认 Share 和规则的状态,最后向 scheduler 同步状态。

启动一个 Share

接受请求

启动一个 share 将从share.ShareManager.create_share进入,我们简单分析其过程,主要还是看网络方面的操作。首先需要获得 Share Network 的 ID,然后调用_provide_share_server_for_share获取 Share Server,这个函数内部定义了一个同名的 Nested Function 并返回。这个 Nested Function 的逻辑是这样的,首先根据 Host 和 Share Network 检查是否已存在可用的 Service VM,如果没有则现在数据创建一个 Share Server 的相应数据,再调用_setup_server到驱动的_setup_server真正创建 Service Server。

创建 Share Server

Manager 的_form_server_setup_info首先要获取一次 Share Network 的 ID,然后调用 Driver 的allocate_network分配 IP,我们的 Driver 还是前面看到的GenericShareDriver,它不需要这个过程,所以直接跳过去了。然后重新获取一次 Share Network 和 Network info(包括 server_idcidrneutron_net_idnetwork_allocation等信息),再将network_info发给 Driver 的setup_server,因为GenericShareDriver的 Service VM 均由service_instance_manager管理,所以请求会再转给service_instance_managerset_up_service_instance方法最后到_create_service_instance真正建立虚拟机。

获取网络信息

首先要获取镜像、密码或密钥、安全组(由配置选项的service_instance_security_group决定,如果不存在则自己建立,开放 CIFS、NFS、SSH、Ping 所需要的端口/规则,这里 Manila 调用的是 Nova 的 API,而且直接获取所有再过滤,可以优化),然后获取网络信息:

  1. 先获取 Service Subnet,这个 Service Subnet 是 Manila 的 Service Network 下的子网,其名称均为”routed_to_xxx”这样,在获取时如果没有则尝试找一个没有用的(name 为空)子网,将其重命名返回,如果再没有就建立一个;
  2. 然后把用户的子网(Share Network)相连的路由器连接到获得的 Service Subnet;
  3. 在 Service Subnet 里建一个device owner为“manila”的 Port,作为 Service VM 用的 Port,如果打开了connect_share_server_to_tenant_network,还会再建一个 Public Port。

最后再一次执行前面在启动部分介绍过的_setup_connectivity_with_service_instances,完成 Service Port 到 Service VM 的连通。

创建 Service VM 虚拟机

获取网络信息后,Manila 将拿着前面获取网络信息时得到的 Port 去创建 Service VM,在设置的max_time_to_build_instance时间内,不断尝试获取 Service VM 的状态,直到其成为Active状态。之后再将安全组设置到 Service VM,再在max_time_to_build_instance时间内尝试连接 Service VM 的 22 端口。

Service VM 创建完成

至此可以认为 Service VM 已经创建完成,代码将再返回到 manila.share.manager.ShareManager.create_share,继续进行下面的create_share的过程。

完成 Share 的创建

对于用的默认的GenericShareDriver,下面就是就是调用 Cinder API 创建 Volume、Attach Volume,SSH 到 Service VM 执行格式化,挂载等操作,与网络没有多少关系就不分析了,完成后一个 Share 就可以认为已经可以使用了。

删除一个 Share

删除一个 share 将从share.ShareManager.delete_share进入,过程就比较简单了,先删除所有的 ACL 规则,然后对 Volume 执行 Unmount 和 Detach,最后调用 Cinder 的 API 将之删除。如果配置文件开启了delete_share_server_with_last_share那么当 Share Server 上没有 Share 时,就会删除这个 Share Server,包括调用 Nova API 删除 Service VM、移除路由器上的端口、将 Service Subnet 的 name 改为空,最后删除掉 Service Subnet 上所有 Port。因为 Service Port 上的 IP 和路由以后还可以用到,所以 Manila 不会去删除那些 IP 和路由项。


附录一:launcher 启动代码

launcher 启动部分代码,与其他 OpenStack 服务基本相同

One Thought on “Manila 网络模块

  1. 好专业的样子,哇哈哈。

发表评论

电子邮件地址不会被公开。 必填项已用*标注

您可以使用这些HTML标签和属性: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code class="" title="" data-url=""> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre class="" title="" data-url=""> <span class="" title="" data-url="">

你可以管理本篇文章的订阅。

Post Navigation