云计算之OpenStack焦点

打印 上一主题 下一主题

主题 692|帖子 692|积分 2076

一、OpenStack架构

1.1 OpenStack概念架构




  • 中间菱形:是虚拟机,围绕 VM 的那些长方形代表 OpenStack 不同的模块或服务;
  • Nova(计算服务,焦点折务):管理 管理计算资源,是 OpenStack 中最焦点的服务;
  • Neutron(网络服务,焦点折务):为 OpenStack 提供网络毗连服务,负责创建和管理L2、L3 网络, 为 VM 提供虚拟网络和物理网络毗连;
  • Glance(镜像服务,焦点折务):管理 VM 的启动镜像,Nova 创建 VM 时将使用 Glance 提供的镜像;
  • Cinder(块存储,焦点折务):为 VM 提供块存储服务。Cinder 提供的每一个 Volume 在 VM 看来是一块虚拟硬盘,一般用作数据盘;
  • Swift(对象存储,可选服务):提供对象存储服务。VM 可以通过 RESTful API 存放对象数据;作为可选的方案,Glance 可以将镜像存放在 Swift 中;Cinder 也可以将 Volume 备份到 Swift 中;
  • Keystone(认证服务,焦点折务):为 OpenStack 的各种服务提供认证和权限管理服务。简单的说,OpenStack 上的每一个操作都必须通过 Keystone 的考核;
  • Ceilometer(监控服务,可选服务):提供 OpenStack监控和计量服务,为报警、统计或计费提供数据;
  • Horizon:为 OpenStack 用户提供一个 Web操作界面;
1.2 OpenStack逻辑架构



  • 在逻辑架构中,可以看到每个服务又由若干组件组成:

  • 上图逻辑架构中,以 Neutron 服务为例,形貌了各个组成部分以及各组件之间的逻辑关系。 而在实际的部署方案上,各个组件可以部署到不同的物理节点上。
  • OpenStack 自己是一个分布式体系,不光各个服务可以分布部署,服务中的组件也可以分布部署。 这种分布式特性让 OpenStack 具备极大的机动性、伸缩性和高可用性。
1.3 拓扑部署



  • OpenStack 是一个分布式体系,由若干不同功能的节点(Node)组成:
    1)控制节点(Controller Node):管理 OpenStack,其上运行的服务有 Keystone、Glance、Horizon 以及 Nova 和 Neutron 中管理相干的组件。 控制节点也运行支持 OpenStack 的服务,比方 SQL 数据库(通常是 MySQL)、消息队列(通常是 RabbitMQ)和网络时间服务 NTP。
    2)计算节点(Compute Node):其上运行 Hypervisor(默认使用 KVM)。 同时运行 Neutron 服务的 agent,为虚拟机提供网络支持。
    3) 网络节点(Network Node):其上运行的服务为 Neutron。 为 OpenStack 提供 L2 和 L3 网络。 包括虚拟机网络、DHCP、路由、NAT 等。
    4) 存储节点(Storage Node):提供块存储(Cinder)或对象存储(Swift)服务。
  • 这几类节点是从功能上举行的逻辑分别,在实际部署时可以根据需求机动设置,好比:在大规模OpenStack生产环境中,每类节点都分别部署在若干台物理服务器上,各司其职并互相协作。 如许的环境具备很好的性能、伸缩性和高可用性。在最小的实验环境中,可以将 4 类节点部署到一个物理的甚至是虚拟服务器上,通常也称为 All-in-One 部署。
  • 在我们的实验环境中,为了使得拓扑简便同时功能完备,我们用两个虚拟机:
    devstack-controller: 控制节点 + 网络节点 + 块存储节点 + 计算节点
    devstack-compute: 计算节点

  • 物理资源需求,可根据实际需求动态调解:

  • 网络规划:

    网络上规划了三个网络
    1)Management Network:用于 OpenStack 内部管理用,好比各服务之间通讯。 这里使用 eth0;
    2)VM(Tenant)Network:OpenStack 部署的虚拟机所使用的网络。OpenStack 支持多租户(Tenant),虚机是放在 Tenant 下的,以是叫 Tenant Network。 这里使用 eth1;
    3)External Network:一般来说,Tenant Network 是内部私有网络,只用于 VM 之间通讯,与其他非 VM 网络是隔离的。这里我们规划了一个外部网络(External Network),通过 devstak-controller 的 eth2 毗连。 Neutron 通过 L3 服务让 VM 能够访问到 External Network。对于公有云,External Network 一般指的是 Internet。对于企业私有云,External Network 则可以是 Intranet 中的某个网络。
  • 创建虚拟机:按照物理资源需求创建 devstack-controller 和 devstak-compute 虚拟机:
    安装操作体系
    安装 Ubuntu 14.04,并设置 eth0 的 IP,如下所示:
  1. 控制节点 devstack-controller  192.168.104.10
  2. 计算节点 devstak-compute      192.168.104.11
复制代码
参考:https://www.xjimmy.com/openstack-5min-17.html
1.4 使用OpenStack CLI

1.4.1 OpenStack 服务都有自己的 CLI



  • 下令很好记,就是服务的名字,好比 Glance 就是 glance,Nova 就是 nova。但 Keystone 比较特殊,如今是用 openstack 来代替老版的 keystone 下令。好比查询用户列表,如果用 keystone user-list:
    会提示 keystone 已经 deprecated 了,用 openstack user list 下令代替:

  • 执行下令之前,必要设置环境变量:
    这些变量包罗用户名、Project、密码等; 如果不设置,每次执行下令都必须设置相干的下令行参数
  • 各个服务的下令都有增、删、改、查的操作,其格式是:
  1. CMD <obj>-create [parm1] [parm2]…
  2. CMD <obj>-delete [parm]
  3. CMD <obj>-update [parm1] [parm2]…
  4. CMD <obj>-list
  5. CMD <obj>-show [parm]
复制代码


  • 比方 glance 管理的是 image,那么:CMD 就是 glance;obj 就是 image,对应的下令就有:
  1. glance image-create
  2. glance image-delete
  3. glance image-update
  4. glance image-list
  5. glance image-show
复制代码


  • 再好比 neutron 管理的是网络和子网等,那么: CMD 就是 neutron;obj 就是 net 和 subnet :
  1. # 网络相关操作
  2. neutron net-create
  3. neutron net -delete
  4. neutron net -update
  5. neutron net -list
  6. neutron net –show
  7. # 子网相关操作
  8. neutron subnet-create
  9. neutron subnet -delete
  10. neutron subnet -update
  11. neutron subnet -list
  12. neutron subnet–show
复制代码


  • 有的下令 可以省略,好比 nova,下面的操作都是针对 instance:
  1. nova boot
  2. nova delete
  3. nova list
  4. nova show
复制代码


  • 没个对象都有ID:delete,show 等操作都以 ID 为参数,比方:

  • 可用 help 查看下令的用法,除了 delete,show 等操作只必要 ID 一个参数,其他操作可能必要更多的参数,用 help 查看所需的参数,格式是:
  1. CMD help [SUB-CMD]
复制代码
比方查看 glance 都有哪些 SUB-CMD:
查看 glance image-update 的用法:

二、OpenStack焦点折务


2.1 认证服务Keystone

2.1.1 基本功能



  • 作为 OpenStack 的基础支持服务,Keystone 做下面这几件事情:
    1)管理用户及其权限;
    2)维护 OpenStack Services 的 Endpoint;
    3)Authentication(认证)和 Authorization(鉴权)。
2.1.2 基本概念




  • user:指代任何使用 OpenStack 的实体,可以是真正的用户,其他体系或者服务,当 User 请求访问 OpenStack 时,Keystone 会对其举行验证;
    Horizon 在 Identity->Users 管理 User:

    除了 admin 和 demo,OpenStack 也为 nova、cinder、glance、neutron 服务创建了相应的 User。 admin 也可以管理这些 User。

  • Credentials:Credentials 是 User 用来证实自己身份的信息,可以是: 1. 用户名/密码 2. Token 3. API Key 4. 其他高级方式。
  • Authentication: 是 Keystone 验证 User 身份的过程。User 访问 OpenStack 时向 Keystone 提交用户名和密码情势的 Credentials,Keystone 验证通过后会给 User 签发一个 Token 作为后续访问的 Credential。
  • Token:Token 是由数字和字母组成的字符串,User 成功 Authentication 后由 Keystone 分配给 User。Token 用做访问 Service 的 Credential;Service 会通过 Keystone 验证 Token 的有用性;Token 的有用期默认是 24 小时。
  • Project: 用于将 OpenStack 的资源(计算、存储和网络)举行分组和隔离。根据 OpenStack 服务的对象不同,Project 可以是一个客户(公有云,也叫租户)、部分或者项目组(私有云)。这里请注意:资源的所有权是属于 Project 的,而不是 User。在 OpenStack 的界面和文档中,Tenant / Project / Account 这几个术语是通用的,但恒久看会倾向使用 Project。每个 User(包括 admin)必须挂在 Project 里才气访问该 Project 的资源。 一个User可以属于多个 Project。admin 相当于 root 用户,具有最高权限
    Horizon 在 Identity->rojects 中管理 Project:

    通过 Manage Members 将 User 添加到 Project 中:

  • Service:OpenStack 的 Service 包括 Compute (Nova)、Block Storage (Cinder)、Object Storage (Swift)、Image Service (Glance) 、Networking Service (Neutron) 等。每个 Service 都会提供若干个 Endpoint,User 通过 Endpoint 访问资源和执行操作。
  • Endpoint:Endpoint 是一个网络上可访问的地址,通常是一个 URL。Service 通过 Endpoint 暴露自己的 API。Keystone 负责管理和维护每个 Service 的 Endpoint。
    可以使用下面的下令来查看 Endpoint:
  1. root@devstack-controller:~# source devstack/openrc admin admin //切换用户
  2. root@devstack-controller:~# openstack catalog list //查询服务的Endpoint
复制代码



  • Role:安全包罗两部分:Authentication(认证)和 Authorization(鉴权)。Keystone 是借助 Role 来实现 Authorization 的。
    Keystone定义Role:

    可以为 User 分配一个或多个 Role,Horizon 的菜单为 Identity->roject->Manage Members:
    Service 决定每个 Role 能做什么事情 Service 通过各自的 policy.json 文件对 Role 举行访问控制。下面是 Nova 服务 /etc/nova/policy.json 中的示例:

    上面设置的寄义是:对于 create、attach_network 和 attach_volume 操作,任何Role的 User 都可以执行; 但只有 admin 这个 Role 的 User 才气执行 forced_host 操作。OpenStack 默认设置只区分 admin 和非 admin Role。 如果必要对特定的 Role 举行授权,可以修改 policy.json。
2.1.3 举例说明:admin用户查看Project中的image



  • 登录:账号密码为admin/admin,点击“Connect”:

    此时OpenStack 内部发生了哪些事情?请看下面:Token 中包罗了 User 的 Role 信息。

  • 显示操作界面:请注意,顶部显示 admin 可访问的 Project 为 “admin” 和 “demo”。

    在此之前发生了什么事情:

    同时,admin 可以访问 Intance, Volume, Image 等服务

    因为 admin 已经从 Keystone 拿到了各 Service 的 Endpoints

  • 显示image列表:点击 “Images”,会显示 image 列表;

    背后发生了这些事:首先,admin 将请求发送到 Glance 的 Endpoint:

    Glance 向 Keystone 询问 admin 身份的有用性:

    接下来 Glance 会查看 /etc/glance/policy.json,判定 admin 是否有查看 image 的权限:

    权限判定通过,Glance 将 image 列表发给 admin。
  • Troubleshoot :OpenStack 排查题目的方法主要是通过日志,每个 Service 都有自己的日志文件。Keystone 主要有两个日志:keystone.log 和 keystone_access.log,生存在 /var/log/apache2/ 目录里。
    devstack 的 screen 窗口已经帮我们打开了这两个日志。可以直接查看:

    如果必要得到最详细的日志信息,可以在 /etc/keystone/keystone.conf 中打开 debug 选项:

    在非 devstack 安装中,日志可能在 /var/log/keystone/ 目录里。
2.2 镜像服务Image

2.2.1 基本概念



  • 在传统 IT 环境下,安装一个体系是要么从安装 CD 重新安装,要么用 Ghost 等克隆工具规复,这两种方式有如下几个题目:
    1)如果要安装的体系多了服从就很低;
    2)时间长,工作量大;
    3)安装完还要举行手工设置,好比安装其他的软件,设置 IP 等;
    4)备份和规复体系不机动。
  • 云环境下必要更高效的解决方案,这就是 Image:
    Image 是一个模板,内里包罗了基本的操作体系和其他的软件。 举例来说,有家公司必要为每位员工设置一套办公用的体系,一般必要一个 Win7 体系再加 MS office 软件。
    OpenStack 是这么玩的,先手工安装好这么一个虚机;然后对虚机执行 snapshot,如许就得到了一个 image;当有新员工入职必要办公环境时,立马启动一个或多个该 image 的 instance(虚机)就可以了。
  • 在这个过程中,第 1 步跟传统方式类似,必要手工操作和一定时间。但第 2、3 步非常快,全自动化,一般都是秒级别。而且 2、3 步可以循环做。好比公司新上了一套 OA 体系,每个员工的 PC 上都得有客户端软件。 那么可以在某个员工的虚机中手工安装好 OA 客户端,然后执行snapshot ,得到新的 image,以后就直接使用新 image 创建虚机就可以了。
  • 另外,snapshot 还有备份的作用,能够非常方便的规复体系。
  • Image Service 的功能是管理 Image,让用户能够发现、获取和生存 Image。在 OpenStack 中,提供 Image Service 的是 Glance,其详细功能如下:
    1)提供 REST API 让用户能够查询和获取 image 的元数据和 image 自己;
    2)支持多种方式存储 image,包括平凡的文件体系、Swift、Amazon S3 等;
    3)对 Instance 执行 Snapshot 创建新的 image。
2.2.2 Glance架构


2.2.2.1 glance-api



  • glance-api 是体系后台运行的服务历程。 对外提供 REST API,响应 image 查询、获取和存储的调用。
  • glance-api 不会真正处理请求。
  • 如果是与 image metadata(元数据)相干的操作,glance-api 会把请求转发给 glance-registry;
  • 如果是与 image 自身存取相干的操作,glance-api 会把请求转发给该 image 的 store backend。
  • 在控制节点上可以查看 glance-api 历程:

2.2.2.2 glance-registry



  • glance-registry 是体系后台运行的服务历程。负责处理和存取 image 的 metadata,比方 image 的巨细和类型。在控制节点上可以查看 glance-registry 历程:

  • Glance 支持多种格式的 image,包括:

2.2.2.3 Database



  • Image 的 metadata 会生存到 database 中,默认是 MySQL。在控制节点上可以查看 glance 的 database 信息:

2.2.2.4 Store backend



  • Glance 自己并不存储 image。 真正的 image 是存放在 backend 中的。 Glance 支持多种 backend,包括:
    1)A directory on a local file system(这是默认设置);
    2)GridFS;
    3)Ceph RBD;
    4)Amazon S3;
    5)Sheepdog;
    6)OpenStack Block Storage (Cinder);
    7)OpenStack Object Storage (Swift);
    8)VMware ESX。
    详细使用哪种 backend,是在 /etc/glance/glance-api.conf 中设置的,在我们的 devstack 环境中,image 存放在控制节点本地目录 /opt/stack/data/glance/images/ 中:

    其他 backend 的设置可参考:https://docs.openstack.org/liberty/config-reference/content/configuring-image-service-backends.html
  • 查看目前已经存在的 image使用glance image-list:

  • 查看生存目录:每个 image 在目录下都对应有一个文件,文件以 image 的 ID 定名。

2.2.3 Glance操作



  • OpenStack 为终端用户提供了 Web UI(Horizon)和下令行 CLI 两种方式创建Image。
2.2.3.1 Web UI操作

2.2.3.1.1 Web UI 创建 image



  • admin 登录后,Project -> Compute -> Images:

  • 点击右上角“Create Image”按钮,为新 image 定名:
    这里我们上传一个 image。 点击“欣赏”,选择镜像文件 cirros-0.3.4-x86_64-disk.img。cirros 是一个很小的 linux 镜像,非常适合测试用。 可以到http://download.cirros-cloud.net/下载。
  • 格式选择 QCOW2:
    如果勾选“Public”,该 image 可以被其他 Project 使用;如果勾选“Protected”,该 image 不允许被删除。
  • 点击“Create Image”,文件上传到 OpenStack 并创建新的 image:

  • 点击 image 的“cirros链接”:
    显示详细信息

2.2.3.1.2 Web UI 删除 image



  • admin 登录后,Project -> Compute -> Images:
    点击“Delete Images”确认删除,操作成功:

2.2.3.2 CLI操作

2.2.3.2.1 CLI 创建 image



  • cirros 这个 linux 镜像很小,通过 Web UI 上传很快,操作会很顺畅。 但如果我们要上传的镜像比较大(好比好几个 G ),那么操作会长时间停留在上传的 Web 界面,我们也不知道目前到底处于什么状态。对于如许的操作,CLI 是更好的选择。
  • 将 image 上传到控制节点的文件体系中,比方 /tmp/cirros-0.3.4-x86_64-disk.img:
  • 设置环境变量:
    Devstack 的安装目录下有个 openrc 文件。source 该文件就可以设置 CLI 的环境变量。这里我们传入了两个参数,第一个参数是 OpenStack 用户名 admin;第二个参数是 Project 名 admin。
  • 执行 image 创建下令:
  1. glance image-create --name cirros --file /tmp/cirros-0.3.4-x86_64-disk.img --disk-format qcow2 --container-format bare --progress
复制代码
在创建 image 的 CLI 参数中我们用 –progress 让其显示文件上传的百分比 %。在 /opt/stack/data/glance/images/ 下查看新的 Image:

2.2.3.2.2 CLI 删除 image



  • 设置环境变量:

  • 查询现有image:

  • 删除image接纳glance image-delete 镜像ID:

2.2.4 怎样 Troubleshooting



  • OpenStack 排查题目的方法主要是通过日志,Service 都有自己单独的日志。Glance 主要有两个日志,glance_api.log 和 glance_registry.log,生存在 /opt/stack/logs/ 目录里。devstack 的 screen 窗口已经帮我们打开了这两个日志,可以直接查看:

  • g-api 窗口显示 glance-api 日志,纪录 REST API 调用环境;g-reg 窗口显示 glance-registry 日志,纪录 Glance 服务处理请求的过程以及数据库操作。如果必要得到最详细的日志信息,可以在 /etc/glance/*.conf 中打开 debug 选项。devstack 默认已经打开了 debug。

  • 在非 devstack 安装中,日志在 /var/log/glance/ 目录里。
2.3 计算服务Nova



  • Compute Service Nova 是 OpenStack 最焦点的服务,负责维护和管理云环境的计算资源。OpenStack 作为 IaaS 的云操作体系,虚拟机生命周期管理也就是通过 Nova 来实现的。

    在上图中可以看到,Nova 处于 Openstak 架构的中心,其他组件都为 Nova 提供支持。Glance 为 VM 提供 image;Cinder 和 Swift 分别为 VM 提供块存储和对象存储 ;Neutron 为 VM 提供网络毗连。
2.3.1 Nova架构


2.3.1.1 API



  • nova-api:接收和响应客户的 API 调用。
    除了提供 OpenStack 自己的API,nova-api 还支持 Amazon EC2 API。也就是说,如果客户以前使用 Amazon EC2,而且用 EC2 的 API 开发工具来管理虚机,那么如果如今要换成 OpenStack,这些工具可以无缝迁移到OpenStack,因为 nova-api 兼容 EC2 API,无需做任何修改。
2.3.1.2 Compute Core



  • nova-scheduler:虚机调度服务,负责决定在哪个计算节点上运行虚机;
  • nova-compute:管理虚机的焦点折务,通过调用 Hypervisor API 实现虚机生命周期管理;
  • Hypervisor:计算节点上跑的虚拟化管理步伐,虚机管理最底层的步伐。 不同虚拟化技术提供自己的 Hypervisor。 常用的 Hypervisor 有 KVM,Xen,VMWare 等;
  • nova-conductor:nova-compute 常常必要更新数据库,好比更新虚机的状态。出于安全性和伸缩性的考虑,nova-compute 并不会直接访问数据库,而是将这个任务委托给 nova-conductor。
2.3.1.3 Console Interface



  • nova-console:用户可以通过多种方式访问虚机的控制台:
    1)nova-novncproxy,基于 Web 欣赏器的VNC 访问;
    2)nova-spicehtml5proxy,基于HTML5 欣赏器的 SPICE 访问;
    3)nova-xvpnvncproxy,基于 Java 客户端的 VNC 访问;
  • nova-consoleauth:负责对访问虚机控制台请求提供 Token 认证;
  • nova-cert:提供 x509 证书支持。
2.3.1.4 Database



  • Nova 会有一些数据必要存放到数据库中,一般使用 MySQL。数据库安装在控制节点上。 Nova 使用定名为 “nova” 的数据库。

2.3.1.5 Message Queue



  • 在前面我们相识到 Nova 包罗浩繁的子服务,这些子服务之间必要相互和谐和通讯。 为解耦各个子服务,Nova 通过 Message Queue 作为子服务的信息中转站。 以是在架构图上我们看到了子服务之间没有直接的连线,它们都通过 Message Queue 联系。

    OpenStack 默认是用 RabbitMQ 作为 Message Queue。MQ 是 OpenStack 的焦点基础组件。
2.3.2 Nova 物理部署方案



  • 对于 Nova,这些服务会部署在两类节点上:计算节点和控制节点。计算节点上安装了 Hypervisor,上面运行虚拟机,由此可知:只有 nova-compute 必要放在计算节点上。其他子服务则是放在控制节点上的。
  • 实验环境的详细部署环境 :
    通过在计算节点和控制节点上运行 ps -elf|grep nova 来查看运行的 nova 子服务:
    1)计算节点上只运行了nova-compute自服务:

    2)控制节点上运行了若干 nova-* 子服务,RabbitMQ 和 MySQL 也是放在控制节点上的,我们发现的控制节点上也运行了 nova-compute:这实际上也就意味着controller 既是一个控制节点,同时也是一个计算节点,也可以在上面运行虚机。


    这也向我们展示了 OpenStack 这种分布式架构部署上的机动性: 可以将所有服务都放在一台物理机上,作为一个 All-in-One 的测试环境; 也可以将服务部署在多台物理机上,获得更好的性能和高可用。
    另外,可以用 nova service-list 查看 nova-* 子服务都分布在哪些节点上:

2.3.3 从虚机创建流程看 nova-* 子服务怎样协同工作



  • 从学习 Nova 的角度看,虚机创建是一个非常好的场景,涉及的 nova-* 子服务很全,下面是流程图:

    1)客户(可以是 OpenStack 最终用户,也可以是其他步伐)向 API(nova-api)发送请求:“帮我创建一个虚机”;
    2)API 对请求做一些须要处理后,向 Messaging(RabbitMQ)发送了一条消息:“让 Scheduler 创建一个虚机”;
    3)Scheduler(nova-scheduler)从 Messaging 获取到 API 发给它的消息,然后执行调度算法,从若干计算节点中选出节点 A;
    4)Scheduler 向 Messaging 发送了一条消息:“在计算节点 A 上创建这个虚机”;
    5)计算节点 A 的 Compute(nova-compute)从 Messaging 中获取到 Scheduler 发给它的消息,然后在本节点的 Hypervisor 上启动虚机;
    5)在虚机创建的过程中,Compute 如果必要查询或更新数据库信息,会通过 Messaging 向Conductor(nova-conductor)发送消息,Conductor 负责数据库访问。
2.3.4 OpenStack 通用计划思路

2.3.4.1 API 前端服务



  • 每个 OpenStack 组件可能包罗若干子服务,其中必定有一个 API 服务负责接收客户请求。以 Nova 为例,nova-api 作为 Nova 组件对外的唯一窗口,向客户暴露 Nova 能够提供的功能。当客户必要执行虚机相干的操作,能且只能向 nova-api 发送 REST 请求。这里的客户包括终端用户、下令行和 OpenStack 其他组件。
  • 计划 API 前端服务的好处在于:对外提供同一接口,隐藏实现细节;API 提供 REST 标准调用服务,便于与第三方体系集成;可以通过运行多个 API 服务实例轻松实现 API 的高可用,好比运行多个 nova-api 历程。
2.3.4.2 Scheduler 调度服务



  • 对于某项操作,如果有多个实体都能够完成任务,那么通常会有一个scheduler 负责从这些实体中挑选出一个最符合的来执行操作。在前面的例子中,Nova 有多个计算节点。当必要创建虚机时,nova-scheduler 会根据计算节点当时的资源使用环境选择一个最符合的计算节点来运行虚机。除了 Nova,块服务组件 Cinder 也有 scheduler 子服务,后面我们会详细讨论。
2.3.4.3 Worker工作服务



  • 调度服务只管分配任务,真正执行任务的是 Worker 工作服务。在 Nova 中,这个 Worker 就是 nova-compute 了。 将 Scheduler 和 Worker 从职能上举行分别使得OpenStack 非常容易扩展:1)当计算资源不敷了无法创建虚机时,可以增加计算节点(增加 Worker);2)当客户的请求量太大调度不过来时,可以增加 Scheduler。
2.3.4.4 Driver 框架



  • OpenStack 作为开放的 Infrastracture as a Service 云操作体系,支持业界各种优秀的技术。
  • 那 OpenStack 的这种开放性表如今哪里呢:一个紧张的方面就是接纳基于 Driver 的框架。以 Nova 为例,OpenStack 的计算节点支持多种 Hypervisor。 包括 KVM, Hyper-V, VMWare, Xen, Docker, LXC 等。Nova-compute 为这些 Hypervisor 定义了同一的接口,hypervisor 只必要实现这些接口,就可以 driver 的情势即插即用到 OpenStack 中。
  • 下面是 nova driver 的架构示意图:

    在 nova-compute 的设置文件 /etc/nova/nova.conf 中由 compute_driver 设置项指定该计算节点使用哪种 Hypervisor 的 driver。

    在我们的环境中因为是 KVM,以是设置的是 Libvirt 的 driver。不知各人是否还记得我们在学习 Glance 时谈到: OpenStack 支持多种 backend 来存放 image。可以是本地文件体系,Cinder,Ceph,Swift 等。实在这也是一个 driver 架构。 只要符合 Glance 定义的规范,新的存储方式可以很方便的参加到 backend 支持列表中。再后面 Cinder 和 Neutron 中我们还会看到 driver 框架的应用。
2.3.4.5 Messaging 服务



  • 在前面创建虚机的流程示意图中,我们看到 nova-* 子服务之间的调用严重依靠 Messaging。Messaging 是 nova-* 子服务交互的中枢。

  • 以前没接触太过布式体系的同砚可能会不太理解为什么不让 API 直接调用Scheduler,或是让Scheuler 直接调用 Compute,而是非要通过 Messaging 举行中转。
  • 步伐之间的调用通常分两种:同步调用和异步调用:
    1)同步调用: API 直接调用 Scheduler 的接口就是同步调用。 其特点是 API 发出请求后必要不停等待,直到 Scheduler 完成对 Compute 的调度,将结果返回给 API 后 API 才气够继续做后面的工作。
    2)异步调用: API 通过 Messaging 间接调用 Scheduler 就是异步调用。 其特点是 API 发出请求后不必要等待,直接返回,继续做后面的工作。Scheduler 从 Messaging 接收到请求后执行调度操作,完成后将结果也通过 Messaging 发送给 API。
  • 在 OpenStack 这类分布式体系中,通常接纳异步调用的方式,其好处是:解耦各子服务:子服务不必要知道其他服务在哪里运行,只必要发送消息给 Messaging 就能完成调用;提高性能:异步调用使得调用者无需等待结果返回。如许可以继续执行更多的工作,提高体系总的吞吐量;提高伸缩性:子服务可以根据必要举行扩展,启动更多的实例处理更多的请求,在提高可用性的同时也提高了整个体系的伸缩性。而且这种变化不会影响到其他子服务,也就是说变化对别人是透明的。
2.3.4.6 Database



  • OpenStack 各组件都必要维护自己的状态信息。好比 Nova 中有虚机的规格、状态,这些信息都是在数据库中维护的。每个 OpenStack 组件在 MySQL 中有自己的数据库。

2.3.5 Nova 组件详解

2.3.5.1 nova-api



  • Nova-api 是整个 Nova 组件的门户,所有对 Nova 的请求都首先由 nova-api 处理。
    Nova-api 向外界暴露若干 HTTP REST API 接口。在 keystone 中我们接纳openstack endpoint show nova下令查询 nova-api 的 endponits。客户端就可以将请求发送到 endponits 指定的地址,向 nova-api 请求操作。

    当然,作为最终用户的我们不会直接发送 Rest AP I请求。OpenStack CLI,Dashboard 和其他必要跟 Nova 交换的组件会使用这些 API。
  • Nova-api 对接收到的 HTTP API 请求会做如下处理:
    1)检查客户端传入的参数是否合法有用 ;
    2)调用 Nova 其他子服务的处理客户端 HTTP 请求 ;
    3)格式化 Nova 其他子服务返回的结果并返回给客户端。
  • nova-api 接收哪些请求?
    简单的说,只要是跟虚拟机生命周期相干的操作,nova-api 都可以响应。大部分操作都可以在 Dashboard 上找到。打开Instance管理界面:

    点击下拉箭头,列表中就是 nova-api 可执行的操作。

    OpenStack 用术语 “Instance” 来表示虚拟机。
2.3.5.2 nova-conductor



  • nova-compute 必要获取和更新数据库中 instance 的信息。但 nova-compute 并不会直接访问数据库,而是通过 nova-conductor 实现数据的访问。

  • 如许做有两个明显好处:更高的体系安全性;更好的体系伸缩性 。
  • 更高的安全性:
    在 OpenStack 的早期版本中,nova-compute 可以直接访问数据库,但如许存在非常大的安全隐患。因为 nova-compute 这个服务是部署在计算节点上的,为了能够访问控制节点上的数据库,就必须在计算节点的 /etc/nova/nova.conf 中设置访问数据库的毗连信息,好比:

    试想恣意一个计算节点被黑客入侵,都会导致部署在控制节点上的数据库面对极大风险。为相识决这个题目,从 G 版本开始,Nova 引入了一个新服务 nova-conductor,将 nova-compute 访问数据库的全部操作都放到 nova-conductor 中,而且 nova-conductor 是部署在控制节点上的。如许就避免了 nova-compute 直接访问数据库,增加了体系的安全性。
  • 更好的伸缩性:
    nova-conductor 将 nova-compute 与数据库解耦之后还带来另一个好处:提高了 nova 的伸缩性。nova-compute 与 conductor 是通过消息中间件交互的。这种疏松的架构允许设置多个 nova-conductor 实例。在一个大规模的 OpenStack 部署环境里,管理员可以通过增加 nova-conductor 的数量来应对日益增长的计算节点对数据库的访问。
2.3.5.3 nova-scheduler



  • 重点介绍 nova-scheduler 的调度机制和实现方法:即解决怎样选择在哪个计算节点上启动 instance 的题目。
  • 创建 Instance 时,用户会提出资源需求,比方 CPU、内存、磁盘各必要多少。OpenStack 将这些需求定义在 flavor(配额) 中,用户只必要指定用哪个 flavor 就可以了。

  • 可用的 flavor 在 System->Flavors 中管理:

    Flavor 主要定义了 VCPU,RAM,DISK 和 Metadata 这四类。 nova-scheduler 会按照 flavor 去选择符合的计算节点。VCPU,RAM,DISK 比较好理解,而 Metatdata 比较有意思,我们后面会详细讨论。下面介绍 nova-scheduler 是怎样实现调度的
    在 /etc/nova/nova.conf 中,nova 通过 scheduler_driver,scheduler_available_filters 和 scheduler_default_filters这三个参数来设置 nova-scheduler。
  • Filter scheduler: Filter scheduler 是 nova-scheduler 默认的调度器,调度过程分为两步。1)通过过滤器(filter)选择满足条件的计算节点(运行 nova-compute);2)通过权重计算(weighting)选择在最优(权重值最大)的计算节点上创建 Instance。

    Nova 允许使用第三方 scheduler,设置 scheduler_driver 即可。这又一次体现了OpenStack的开放性。Scheduler 可以使用多个 filter 依次举行过滤,过滤之后的节点再通过计算权重选出最适合的节点。

    上图是调度过程的一个示例:最开始有 6 个计算节点 Host1-Host6;通过多个 filter 层层过滤,Host2 和 Host4 没有通过,被刷掉了;Host1,Host3,Host5,Host6 计算权重,结果 Host5 得分最高,最终入选。
  • Filter: 当 Filter scheduler 必要执行调度操作时,会让 filter 对计算节点举行判定,filter 返回 True 或 False。Nova.conf 中的 scheduler_available_filters 选项用于设置 scheduler 可用的 filter,默认是所有 nova 自带的 filter 都可以用于过滤操作。

    另外还有一个选项 scheduler_default_filters,用于指定 scheduler 真正使用的 filter,默认值如下 :

    Filter scheduler 将按照列表中的顺序依次过滤。 下面依次介绍每个 filter。
    1)RetryFilter
    RetryFilter 的作用是刷掉之前已经调度过的节点。举个例子方便各人理解: 假设 A,B,C 三个节点都通过了过滤,最终 A 因为权重值最大被选中执行操作。但由于某个原因,操作在 A 上失败了。 默认环境下,nova-scheduler 会重新执行过滤操作(重复次数由 scheduler_max_attempts 选项指定,默认是 3)。那么这时候 RetryFilter 就会将 A 直接刷掉,避免操作再次失败。RetryFilter 通常作为第一个 filter。
    2)AvailabilityZoneFilter
    为提高容灾性和提供隔离服务,可以将计算节点分别到不同的Availability Zone中。比方把一个机架上的机器分别在一个 Availability Zone 中。OpenStack 默认有一个定名为 “Nova” 的 Availability Zone,所有的计算节点初始都是放在 “Nova” 中。用户可以根据必要创建自己的 Availability Zone。

    创建 Instance 时,必要指定将 Instance 部署到在哪个 Availability Zone中。

    nova-scheduler 在做 filtering 时,会使用 AvailabilityZoneFilter 将不属于指定 Availability Zone 的计算节点过滤掉。
    3)RamFilter
    RamFilter 将不能满足 flavor 内存需求的计算节点过滤掉。对于内存有一点必要注意: 为了提高体系的资源使用率,OpenStack 在计算节点可用内存时允许 overcommit(超配),也就是可以超过实际内存巨细。 超过的水平是通过 nova.conf 中 ram_allocation_ratio 这个参数来控制的,默认值为 1.5。

    其寄义是:如果计算节点的内存有 10GB,OpenStack 则会认为它有 15GB(10*1.5)的内存。
    4)DiskFilter
    DiskFilter 将不能满足 flavor 磁盘需求的计算节点过滤掉。Disk 同样允许 overcommit,通过 nova.conf 中 disk_allocation_ratio 控制,默认值为 1。

    5)CoreFilter
    CoreFilter 将不能满足 flavor vCPU 需求的计算节点过滤掉。vCPU 同样允许 overcommit,通过 nova.conf 中 cpu_allocation_ratio 控制,默认值为 16。

    这意味着一个 8 vCPU 的计算节点,nova-scheduler 在调度时认为它有 128 个 vCPU。必要提醒的是: nova-scheduler 默认使用的 filter 并没有包罗 CoreFilter。 如果要用,可以将 CoreFilter 添加到 nova.conf 的 scheduler_default_filters 设置选项中。
    6)ComputeFilter
    ComputeFilter 保证只有 nova-compute 服务正常工作的计算节点才气够被 nova-scheduler调度。ComputeFilter 显然是必选的 filter。
    7)ComputeCapabilitiesFilter:ComputeCapabilitiesFilter 根据计算节点的特性来筛选。这个比较高级,我们举例说明。比方我们的节点有 x86_64 和 ARM 架构的,如果想将 Instance 指定部署到 x86_64 架构的节点上,就可以利用到ComputeCapabilitiesFilter。还记得 flavor 中有个 Metadata 吗,Compute 的 Capabilities就在 Metadata中 指定。

    “Compute Host Capabilities” 列出了所有可设置 Capabilities。

    点击 “Architecture” 后面的 “+”,就可以在右边的列表中指定详细的架构。

    设置好后,ComputeCapabilitiesFilter 在调度时只会筛选出 x86_64 的节点。如果没有设置 Metadata,ComputeCapabilitiesFilter 不会起作用,所有节点都会通过筛选。
    8)ImagePropertiesFilter
    ImagePropertiesFilter 根据所选 image 的属性来筛选匹配的计算节点。 跟 flavor 类似,image 也有 metadata,用于指定其属性。

    比方希望某个 image 只能运行在 kvm 的 hypervisor 上,可以通过 “Hypervisor Type” 属性来指定。

    点击 “+”,然后在右边的列表中选择 “kvm”。

    设置好后,ImagePropertiesFilter 在调度时只会筛选出 kvm 的节点。如果没有设置 Image 的Metadata,ImagePropertiesFilter 不会起作用,所有节点都会通过筛选。
    9)ServerGroupAntiAffinityFilter
    ServerGroupAntiAffinityFilter 可以尽量将 Instance 分散部署到不同的节点上。比方有 inst1,inst2 和 inst3 三个 instance,计算节点有 A,B 和 C。为保证分散部署,举行如下操作:
    创建一个 anti-affinity 计谋的 server group “group-1” :

    请注意,这里的 server group 实在是 instance group,并不是计算节点的 group。
    依次创建 Instance,将inst1, inst2和inst3放到group-1中:

    因为 group-1 的计谋是 AntiAffinity,调度时 ServerGroupAntiAffinityFilter 会将inst1, inst2 和 inst3 部署到不同计算节点 A, B 和 C。目前只能在 CLI 中指定 server group 来创建 instance。创建 instance 时如果没有指定 server group,ServerGroupAntiAffinityFilter 会直接通过,不做任何过滤。
    10)ServerGroupAffinityFilter
    与 ServerGroupAntiAffinityFilter 的作用相反,ServerGroupAffinityFilter 会尽量将 instance 部署到同一个计算节点上。方法类似:
    创建一个 affinity 计谋的 server group “group-2”:

    依次创建 instance,将 inst1, inst2 和 inst3 放到 group-2 中:

    因为 group-2 的计谋是 Affinity,调度时 ServerGroupAffinityFilter 会将 inst1, inst2 和 inst3 部署到同一个计算节点。创建 instance 时如果没有指定 server group,ServerGroupAffinityFilter 会直接通过,不做任何过滤。
  • Weight:
    经过前面一堆 filter 的过滤,nova-scheduler 选出了能够部署 instance 的计算节点。如果有多个计算节点通过了过滤,那么最终选择哪个节点呢?Scheduler 会对每个计算节点打分,得分最高的获胜。打分的过程就是 weight,翻译过来就是计算权重值,那么 scheduler 是根据什么来计算权重值呢?目前 nova-scheduler 的默认实现是根据计算节点空闲的内存量计算权重值:空闲内存越多,权重越大,instance 将被部署到当前空闲内存最多的计算节点上。
  • 日志:
    1)整个过程都被纪录到 nova-scheduler 的日志中。好比当我们部署一个 instance 时,打开 nova-scheduler 的日志 /opt/stack/logs/n-sch.log(非 devstack 安装其日志在 /var/log/nova/scheduler.log):

    日志显示初始有两个 host(在我们的实验环境中就是 devstack-controller 和 devstack-compute1),依次经过 9 个 filter 的过滤(RetryFilter,AvailabilityZoneFilter,RamFilter,DiskFilter,ComputeFilter,ComputeCapabilitiesFilter,ImagePropertiesFilter,ServerGroupAntiAffinityFilter, ServerGroupAffinityFilter),两个计算节点都通过了。
    2)那么接下来就该 weight 了:

    可以看到因为 devstack-controller 的空闲内存比 devstack-compute1 多(7466 > 3434),权重值更大(1.0 > 0.4599),最终选择 devstack-controller。
    注:要显示 DEBUG 日志,必要在 /etc/nova/nova.conf 中打开 debug 选项:

2.3.5.4 nova-compute



  • nova-compute 在计算节点上运行,负责管理节点上的 instance。OpenStack 对 instance 的操作,末了都是交给 nova-compute 来完成的。nova-compute 与 Hypervisor 一起实现 OpenStack 对 instance 生命周期的管理。
  • 通过 Driver 架构支持多种 Hypervisor:如今市面上有这么多 Hypervisor,nova-compute 怎样与它们配合呢?这就是我们之前讨论过的 Driver 架构。nova-compute 为这些 Hypervisor 定义了同一的接口,Hypervisor 只必要实现这些接口,就可以 Driver 的情势即插即用到 OpenStack 体系中。
    下面是Nova Driver的架构示意图:

  • 我们可以在 /opt/stack/nova/nova/virt/ 目录下查看到 OpenStack 源代码中已经自带了上面这几个 Hypervisor 的 Driver:

  • 某个特定的计算节点上只会运行一种 Hypervisor,只需在该节点 nova-compute 的设置文件 /etc/nova/nova.conf 中设置所对应的 compute_driver 就可以了。在我们的环境中因为是 KVM,以是设置的是 Libvirt 的 driver:

  • nova-compute 的功能可以分为两类:1)定时向 OpenStack 陈诉计算节点的状态 ;2)实现 instance 生命周期的管理。
    1)定期向 OpenStack 陈诉计算节点的状态 :
    前面我们看到 nova-scheduler 的许多 Filter 是根据算节点的资源使用环境举行过滤的。好比 RamFilter 要检查计算节点当前可以的内存量;CoreFilter 检查可用的 vCPU 数量;DiskFilter 则会检查可用的磁盘空间。
    那这里有个题目:OpenStack 是怎样得知每个计算节点的这些信息呢? 答案就是:nova-compute 会定期向 OpenStack 陈诉。从 nova-compute 的日志 /opt/stack/logs/n-cpu.log 可以发现:每隔一段时间,nova-compute 就会陈诉当前计算节点的资源使用环境和 nova-compute 服务状态。
    如果我们再深入问一个题目:nova-compute 是怎样获恰当前计算节点的资源使用信息的?

    要得到计算节点的资源使用详细环境,必要知道当前节点上所有 instance 的资源占用信息。这些信息谁最清楚?
    当然是 Hypervisor。各人还记得之前我们讨论的 Nova Driver 架构吧,nova-compute 可以通过 Hypervisor 的 driver 拿到这些信息。举例来说,在我们的实验环境下 Hypervisor 是 KVM,用的 Driver 是 LibvirtDriver。LibvirtDriver 可以调用相干的 API 获得资源信息,这些 API 的作用相当于我们在 CLI 里执行 virsh nodeinfo、virsh dominfo 等下令。
    2)实现 instance 生命周期的管理:
    OpenStack 对 instance 最主要的操作都是通过 nova-compute 实现的:包括 instance 的 launch(部署)、shutdown(关机)、reboot(重启)、suspend(挂起)、resume(规复)、terminate(终止)、resize(重新分配配额)、migration(迁移)、snapshot(快照) 等。
    本小节重点学习 nova-compute 怎样实现 instance launch(部署)操作。当 nova-scheduler 选定了部署 instance 的计算节点后,会通过消息中间件 rabbitMQ 向选定的计算节点发出 launch instance 的下令。该计算节点上运行的 nova-compute 收到消息后会执行 instance 创建操作。
    日志 /opt/stack/logs/n-cpu.log 纪录了整个操作过程。nova-compute 创建 instance 的过程可以分为 4 步:为 instance 准备资源;创建 instance 的镜像文件;创建 instance 的 XML 定义文件 ;创建虚拟网络并启动虚拟机。
    第1步-为instance 准备资源:
    nova-compute 首先会根据指定的 flavor 依次为 instance 分配内存、磁盘空间和 vCPU。可以在日志中看到这些细节:

    网络资源也会提前分配:

    第2步-创建 instance 的镜像文件 :
    资源准备好之后,nova-compute 会为 instance 创建镜像文件,OpenStack 启动一个 instance 时,会选择一个 image,这个 image 由 Glance 管理。nova-compute会:首先将该 image 下载到计算节点;然后将其作为 backing file 创建 instance 的镜像文件。
    从 Glance 下载 image:nova-compute 首先会检查 image 是否已经下载(好比之前已经创建过基于相同 image 的 instance)。
    如果没有,就从 Glance 下载 image 到本地。由此可知,如果计算节点上要运行多个相同 image 的 instance,只会在启动第一个 instance 的时候从 Glance 下载 image,后面的 instance 启动速度就大大加速了。日志如下:

    可以看到:image(ID为 917d60ef-f663-4e2d-b85b-e4511bb56bc2)是 qcow2格式,nova-compute 将其下载,然后通过 qemu-img 转换成 raw 格式。 转换的原因是下一步必要将其作为 instance的镜像文件的 backing file,而 backing file不能是 qcow2 格式。image 的存放目录是 /opt/stack/data/nova/instances/_base,这是由 /etc/nova/nova.conf 的下面两个设置选项决定的。
    instances_path = /opt/stack/data/nova/instances
    base_dir_name = _base
    下载的 image 文件被定名为 60bba5916c6c90ed2ef7d3263de8f653111dd35f,这是 image id 的 SHA1 哈希值。
    为 instance 创建镜像文件:有了 image 之后,instance 的镜像文件直接通过 qemu-img 下令创建,backing file 就是下载的 image:

    这里 instance 的镜像文件位于 /opt/stack/data/nova/instances/f1e22596-6844-4d7a-84a3-e41e6d7618ef/disk,格式为 qcow2,其中 f1e22596-6844-4d7a-84a3-e41e6d7618ef 就是 instance 的 id。
    可以通过 qemu-info 查看 disk 文件的属性:

    这里有两个容易搞混淆的术语,在此特别说明一下
    image,指的是 Glance 上生存的镜像,作为 instance 运行的模板。 计算节点将下载的 image 存放在 /opt/stack/data/nova/instances/_base 目录下。 镜像文件,指的是 instance 启动盘所对应的文件。二者的关系是:image 是镜像文件 的 backing file。image 不会变,而镜像文件会发生变化。 好比安装新的软件后,镜像文件会变大。因为英文中两者都叫 “image”,为避免混淆,我们用 “image” 和 “镜像文件” 作区分。
    第3步-创建 instance 的XML 定义文件 : 创建的 XML 文件会生存到该 instance 目录 /opt/stack/data/nova/instances/f1e22596-6844-4d7a-84a3-e41e6d7618ef,定名为 libvirt.xml:

    第4步-创建虚拟网络并启动 instance :

    本环境用的是 linux-bridge 实现的虚拟网络,在 Neutron 章节我们会详细讨论 OpenStack 虚拟网络的不同实现方式。一切停当,接下来可以启动 instance 了:


    至此,instance 已经成功启动。OpenStack 图形界面和 KVM CLI 都可以查看到 instance 的运行状态:


    在计算节点上,instance 并不是以 OpenStack上 的名字定名,而是用 instance-xxxxx 的格式。
2.3.6 看懂 OpenStack 日志

2.3.6.1 日志位置



  • 我们实验环境使用的是 devstack,日志都同一放在 /opt/stack/logs 目录下,非 devstack日志在var/log目录下。每个服务有自己的日志文件,从定名上很容易区分。

2.3.6.2 日志类型



  • 好比 nova-* 各个子服务的日志都以 “n-” 开头。n-api.log 是 nova-api 的日志;n-cpu.log 是 nova-compute 的日志。
  • Glance 的日志文件都是 “g-” 开头。g-api.log 是 glance-api 的日志;g-reg.log 是 glance-registry 的日志。
  • Cinder、Neutron 的日志分别以 “c-” 和 “q-” 开头。对于非 devstack 安装的 OpenStack,日志一般放在 /var/log/xxx/ 目录下
    好比 Nova 放在 /var/log/nova/ 下,Glance 放在/var/log/glance下……。各个子服务的日志文件也是单独生存,定名也很规范,容易区分。好比 nova-api 的日志一般就定名为 /var/log/nova/api.log,其他日志类似。
2.3.6.3 日志格式



  • OpenStack 的日志格式都是同一的,如下:
    <时间戳><日志等级><代码模块><日志内容><源代码位置>
    简单说明一下:
    1)时间戳:日志纪录的时间,包括年、月、日、时、分、秒、毫秒;
    2)日志等级:有INFO、WARNING、ERROR、DEBUG等;
    3)代码模块:当前运行的模块Request ID,日志会纪录连续不同的操作,为了便于区分和增加可读性,每个操作都被分配唯一的Request ID,便于查找;
    4)日志内容:这是日志的主体,纪录当前正在执行的操作和结果等紧张信息;
    5)源代码位置:日志代码的位置,包括方法名称,源代码文件的目录位置和行号。这一项不是所有日志都有。
  • 下面举例说明:
  1. 2015-12-10 20:46:49.566 DEBUG nova.virt.libvirt.config [req-5c973fff-e9ba-4317-bfd9-76678cc96584 None None] Generated XML ('<cpu>\n  <arch>x86_64</arch>\n  <model>Westmere</model>\n
  2. <vendor>Intel</vendor>\n  <topology sockets="2" cores="3" threads="1"/>\n  
  3. <feature name="avx"/>\n  <feature name="ds"/>\n  <feature name="ht"/>\n  
  4. <feature name="hypervisor"/>\n  <feature name="osxsave"/>\n  <feature name="pclmuldq"/>\n
  5. <feature name="rdtscp"/>\n  <feature name="ss"/>\n  <feature name="vme"/>\n  
  6. <feature name="xsave"/>\n</cpu>\n',)  to_xml /opt/stack/nova/nova/virt/libvirt/config.py:82
复制代码
这条日志我们可以得知:代码模块是 nova.virt.libvirt.config,由此可知应该是 Hypervisor Libvirt 相干的操作;日志内容是天生 XML;如果要跟踪源代码,可以到/opt/stack/nova/nova/virt/libvirt/config.py 的 82 行,方法是 to_xml。


  • 又比方下面这条日志:
  1. 2015-12-10 20:46:49.671 ERROR nova.compute.manager[req-5c973fff-e9ba-4317-bfd9-76678cc96584 None None]No compute node record for host devstack-controller
复制代码
这条日志我们可以得知:这是一个 ERROR 日志;详细内容是 “No compute node record for host devstack-controller”;该日志没有指明源代码位置。
2.3.6.4 日志说明



  • 学习 OpenStack 必要看日志吗?这个题目的答案取决于你是谁。果你只是 OpenStack 的最终用户,那么日志对你不紧张。你只必要在 GUI上 操作,如果出题目直接找管理员就可以了。
    但如果你是 OpenStack 的运维和管理人员,日志对你就非常紧张了。因为 OpenStack 操作如果堕落,GUI 上给出的错误信息是非常笼统和扼要的,日志则提供了大量的线索,特别是当 debug 选项打开之后。如果你正处于 OpenStack 的学习阶段,正如我们如今的状态,那么也强烈建议你多看日志。日志能够帮助你更加深入理解 OpenStack 的运行机制。
  • 日志能够帮助我们深入学习 OpenStack 和排查题目。但要想高效的使用日志还得有个条件:必须先把握 OpenStack 的运行机制,然后针对性的查看日志。 就拿 Instance Launch 操作来说,如果之前不相识 nova-* 各子服务在操作中的协作关系,如果没有理解流程图,面对云云多和分散的日志文件,我们也很难下手不是。
  • 对于 OpenStack 的运维和管理员来说,在大部分环境下,我们都不必要看源代码。因为 OpenStack 的日志纪录得很详细了,足以帮助我们分析和定位题目。 但还是有一些细节日志没有纪录,须要时可以通过查看源代码理解得更清楚。 即便云云,日志也会为我们提供源代码查看的线索,不必要我们大海捞针。
2.3.7 虚拟机生命周期管理

2.3.7.1 Launch-部署虚拟机



  • 客户(可以是 OpenStack 最终用户,也可以是其他步伐)向 API(nova-api)发送请求:“帮我创建一个 Instance”:

    1)API对请求做一些须要处理后,向 Messaging(RabbitMQ)发送了一条消息:“让 Scheduler 创建一个 Instance”;
    2)Scheduler(nova-scheduler)从 Messaging 获取 API 发给它的消息,然后执行调度算法,从若干计算节点中选出节点 A;
    3)Scheduler 向 Messaging 发送了一条消息:“在计算节点 A 上创建这个 Instance”;
    4)计算节点 A 的 Compute(nova-compute)从 Messaging 中获取到 Scheduler 发给它的消息,然后通过本节点的 Hypervisor Driver 创建 Instance;
    5)在 Instance 创建的过程中,Compute 如果必要查询或更新数据库信息,会通过 Messaging 向 Conductor(nova-conductor)发送消息,Conductor 负责数据库访问。
2.3.7.2 Shut Off-关闭虚拟机



  • shut off instance 的流程图如下所示:1)向 nova-api 发送请求;2)nova-api 发送消息;3)nova-compute 执行操作。

    1)向 nova-api 发送请求:
    客户(可以是 OpenStack 最终用户,也可以是其他步伐)向 API(nova-api)发送请求:“帮我关闭这个 Instance”:

    查看日志 /opt/stack/logs/n-api.log:

    对于初学者,这不是一件容易的事情,因为日志里条目和内容许多,特别是 debug 选项打开之后,容易让人眼花缭乱,无从下手。这里给各人几个小窍门:
    a)先确定大的范围,好比在操作之前用 tail -f 打印日志文件,如许必要查看的日志肯定在操作之后的打印输出的这些内容里。 另外也可以通过期间戳来确定必要的日志范围。
    b)利用 “代码模块” 快速定位有用的信息。 nova-* 子服务都有自己特定的代码模块:
    nova-api :
    nova.api.openstack.compute.servers
    nova.compute.api
    nova.api.openstack.wsgi
    nova-compute:
    nova.compute.manager
    nova.virt.libvirt.*
    nova-scheduler:
    nova.scheduler.*
    c)利用 Request ID 查找相干的日志信息。 在上面的日志中,我们可以利用 “req-1758b389-a2d0-44cc-a95a-6f75e4dc07fd” 这个 Request ID 快速定位 n-api.log 中相与 shut off 操作的其他日志条目。 必要增补说明的是,Request ID 是跨日志文件的,这一个特性能帮助我们在其他子服务的日志文件中找到相干信息,我们后面立刻将会看到这个技巧的应用。
    2)nova-api 发送消息:
    nova-api 向 Messaging(RabbitMQ)发送了一条消息:“关闭这个 Instance”。nova-api 没有将发送消息的操作纪录到日志中,不过我们可以通过查看源代码来验证。 一提到源代码,各人可能以为要大海捞针了。实在很简单,上面日志已经清楚地告诉我们必要查看的源代码在 /opt/stack/nova/nova/compute/api.py 的 1977 行,方法是 force_stop。

    force_stop 方法末了调用的是对象 self.compute_rpcapi 的 stop_instance 方法。 在 OpenStack 源码中,以 xxx_rpcapi 定名的对象,表示的就是 xxx 的消息队列。 xxx_rpcapi.yyy() 方法则表示向 xxx 的消息队列发送 yyy 操作的消息。 以是 self.compute_rpcapi.stop_instance() 的作用就是向 RabbitMQ 上 nova-compute 的消息队列里发送一条 stop instance 的消息。这里增补说明一下: 关闭 instance 的条件是 instance 当前已经在某个计算节点上运行,以是这里不必要 nova-scheduler 再帮我们挑选符合的节点,这个跟 launch 操作不同。
    3)nova-compute 执行操作:
    查看计算节点上的日志 /opt/stack/logs/n-cpu.log

    这里我们利用了 Request ID “req-1758b389-a2d0-44cc-a95a-6f75e4dc07fd”在 n-cpu.log 中快速定位到 nova-compute 关闭 instance 的日志条目。
  • 小结:
    分析某个操作时,我们首先要理清该操作的内部流程,然后再到相应的节点上去查看日志
    比方shut off 的流程为:
    1)向 nova-api 发送请求;
    2)nova-api 发送消息;
    3)nova-compute 执行操作。
    1,2 两个步骤是在控制节点上执行的,查看 nova-api 的日志。第 3 步是在计算节点上执行的,查看 nova-compute 的日志。
2.3.7.3 Start-启动虚拟机



  • 下图是 start instance 的流程图,包罗1) 向 nova-api 发送请求;2)nova-api 发送消息;3)nova-compute 执行操作。

    1)向 nova-api 发送请求:
    客户(可以是 OpenStack 最终用户,也可以是其他步伐)向API(nova-api)发送请求:“帮我启动这个 Instance”:

    查看日志 /opt/stack/logs/n-api.log :

    2)nova-api 发送消息:
    nova-api 向 Messaging(RabbitMQ)发送了一条消息:“启动这个 Instance”。查看源代码 /opt/stack/nova/nova/compute/api.py 的 2002 行,方法是 start:

    self.compute_rpcapi.start_instance() 的作用就是向 RabbitMQ 上 nova-compute 的消息队列里发送一条start instance 的消息。
    3)nova-compute 执行操作:
    查看日志 /opt/stack/logs/n-cpu.log。开始启动:

    准备虚拟网卡:

    准备 instance 的 XML 文件:

    准备 instance 镜像文件:

    成功启动:

2.3.7.4 Soft/Hard Reboot-软/硬重启虚拟机



  • Soft/Hard Reboot区别:

    1)soft reboot 只是重启操作体系,整个过程中,instance 依然处于运行状态。相当于在 linux 中执行 reboot 下令;
    2)hard reboot 是重启 instance,相当于关机之后再开机。
  • 提示:soft/hard reboot 在 nova-api 的日志里找不到,这是因为 /opt/stack/nova/nova/compute/api.py 的 reboot 方法中没有输出 log。 可以通过关键字 “nova.api.openstack.wsgi” 或者 “reboot” 搜索;在 nova-compute 的日志中可以看到 “soft reboot” 和 “hard reboot” 二者有明显的区别。
2.3.7.5 Lock/Unlock-加锁/解锁虚拟机



  • 为了避免误操作,好比不测重启或删除 instance,可以将 instance 加锁;对被加锁(Lock)的 instance 执行重启等改变状态的操作会提示操作不允许。执行解锁(Unlock)操作后规复正常。
  • Lock/Unlock 操作都是在 nova-api 中举行的。操作成功后 nova-api 会更新 instance 加锁的状态。执行其他操作时,nova-api 根据加锁状态来判定是否允许。Lock/Unlock 不必要 nova-compute 的参与。
  • 提示:admin 脚色的用户不受 lock 的影响,即无论加锁与否都可以正常执行操作;根据默认 policy 的设置,任何用户都可以 unlock。也就是说如果发现 instance 被加锁了,可以通过 unlock 解锁,然后在执行操作。
2.3.7.6 Terminate -删除虚拟机



  • 下面是 terminate instance 的流程图,包罗:1)向nova-api 发送请;2)nova-api 发送消息;3)nova-compute 执行操作。

    1)向 nova-api 发送请求 :
    客户(可以是 OpenStack 最终用户,也可以是其他步伐)向 API(nova-api)发送请求:“帮我删除这个 Instance”:


    查看日志 /opt/stack/logs/n-api.log:

    2)nova-api 发送消息:
    nova-api 向 Messaging(RabbitMQ)发送了一条消息:“删除这个 Instance”。源代码在 /opt/stack/nova/nova/compute/api.py,方法是 _do_force_delete:

    3)nova-compute 执行操作 :
    查看日志 /opt/stack/logs/n-cpu.log,关闭 instance:

    删除 instance 的镜像文件:

    释放虚拟网络等其他资源:

2.3.7.7 Pause/Resume-暂停(短时间)/规复(暂停后的规复,非故障时规复)虚拟机



  • 有时必要短时间暂停 instance,可以通过 Pause 操作将 instance 的状态生存到宿主机的内存中。当必要规复的时候,执行 Resume 操作,从内存中读回 instance 的状态,然后继续运行 instance。
  • 下面是 pause instance 的流程图,包罗:1)向 nova-api 发送请求;2)nova-api 发送消息;3)nova-compute 执行操作。

    1)向nova-api发送请求:
    客户(可以是 OpenStack 最终用户,也可以是其他步伐)向 API(nova-api)发送请求:“帮我暂停这个 Instance”:

    查看日志 /opt/stack/logs/n-api.log:

    注:对于 Pause 操作,日志没有前面 Start 纪录得那么详细。比方这里就没有纪录 nova.api.openstack.compute.servers 和 nova.compute.api 代码模块的日志,这可能是因为这个操作逻辑比较简单,开发人员在编码时没有参加日志。
    2)nova-api 发送消息:
    nova-api 向 Messaging(RabbitMQ)发送了一条消息:“暂停这个 Instance”。查看源代码 /opt/stack/nova/nova/compute/api.py,方法是 pause:

    3)nova-compute 执行操作:
    查看日志 /opt/stack/logs/n-cpu.log:

    暂停操作成功执行后,instance 的状态变为 Paused:

    Resume 操作的日志分析留给各人训练。 提示:这里的 Resume 操作实际上是 Unpause 操作,可以通过关键字“unpause”定位日志。
2.3.7.8 Suspend/Resume-暂停(长时间)/规复(暂停后的规复,非故障时规复)虚拟机



  • 有时必要长时间暂停 instance,可以通过 Suspend 操作将 instance 的状态生存到宿主机的磁盘上。当必要规复的时候,执行 Resume 操作,从磁盘读回 instance 的状态,使之继续运行。
  • 这里必要对 Suspend 和 Pause 操作做个比较:
    1)相同点:两者都是暂停 instance 的运行,并生存当前状态,之后可以通过 Resume 操作规复;
    2)不同点:
    a)Suspend 将 instance 的状态生存在磁盘上;Pause 是生存在内存中,以是 Resume 被 Pause 的 instance 要比 Suspend 快。
    b)Suspend 之后的 instance,其状态是 Shut Down;而被 Pause 的 instance 状态是Paused。
    c)固然都是通过 Resume 操作规复,Pause 对应的 Resume 在 OpenStack 内部被叫作 “Unpause”;Suspend 对应的 Resume 才是真正的 “Resume”。这个在日志中能体现出来。
2.3.7.9 Rescue/Unrescue-规复(发生故障时规复)/重新引导虚拟机



  • 从这节开始,我们将讨论几种 instance 故障规复的方法,不同方法适用于不同的场景。
  • 首先我们考虑操作体系故障:有时候由于误操作或者突然断电,操作体系重启后却起不来了。为了最大限度挽救数据,我们通常会使用一张体系盘将体系引导起来,然后在实验规复。题目如果不太严重,完全可以通过这种方式让体系重新正常工作。好比某个体系文件不测删除, root 密码忘记等。
  • Nova 也提供了这种故障规复机制,叫做 Rescue。

    Rescue 用指定的 image 作为启动盘引导 instance,将 instance 自己的体系盘作为第二个磁盘挂载到操作体系上。
  • 下面是 rescue instance 的流程图:包罗1)向 nova-api 发送请求;2)nova-api 发送消息;3)nova-compute 执行操作。

    1)向 nova-api 发送请求:
    目前 Rescue 操作只能通过 CLI 执行。这里我们没有指明用哪个 image 作为引导盘,nova 将使用 instance 部署时使用的 image:

    查看日志 /opt/stack/logs/n-api.log:

    2)nova-api 发送消息:
    nova-api 向 Messaging(RabbitMQ)发送了一条消息:“Rescue 这个 Instance”。源代码在 /opt/stack/nova/nova/compute/api.py,方法是 rescue:

    3)nova-compute执行操作:
    查看日志 /opt/stack/logs/n-cpu.log。关闭 instance:


    通过 image 创建新的引导盘,定名为 disk.rescue:

    启动 instance:

    Rescue 执行成功后,可以通过 virsh edit <instance_name> 查看 instance 的 XML 定义。disk.rescue 作为启动盘 vda,真正的启动盘 disk 作为第二个磁盘 vdb:

    登录 instance,通过 fdisk 也可确认,fdisk -l是以列表的情势列出磁盘分区环境:

    此时,instance 处于 Rescue 状态:

    Rescue 操作让我们有机会修复粉碎的操作体系。修好之后,使用 Unrescue 操作从原启动盘重新引导 instance。

2.3.7.10 Snapshot -创建虚拟机快照



  • 有时候操作体系粉碎得很严重,通过 Rescue 操作无法修复,那么我们就得考虑通过备份规复了。当然条件是我们之前对instance做过备份。Nova 备份的操作叫 Snapshot,其工作原理是对 instance 的镜像文件(体系盘)举行全量备份,天生一个类型为 snapshot 的 image,然后将其生存到 Glance 上。从备份规复的操作叫 Rebuild,将在下一节重点讨论。
  • 下面是 snapshot instance 的流程图,包罗1)向 nova-api 发送请求;2)nova-api 发送消息;3)nova-compute 执行操作。
    1)向 nova-api 发送请求:
    客户(可以是 OpenStack 最终用户,也可以是其他步伐)向 API(nova-api)发送请求:“对这个 Instance做个快照”:


    查看日志 /opt/stack/logs/n-api.log:

    2)nova-api 发送消息:
    nova-api 向 Messaging(RabbitMQ)发送了一条消息:“对这个 Instance 做快照”,源代码在 /opt/stack/nova/nova/compute/api.py,方法是 snapshot:

    3)nova-compute 执行操作:
    查看日志 /opt/stack/logs/n-cpu.log。暂停 instance:

    对 instance 的镜像文件做快照:

    规复 instance:


    将快照上传到 Glance:

    Snapshot 成功生存在 Glance 中:

    instance 备份成功,下节我们讨论怎样通过 snapshot 规复。
2.3.7.11 Rebuild -通过快照规复虚拟机



  • 上一节我们讨论了 snapshot,snapshot 的一个紧张作用是对 instance 做备份。如果 instance 粉碎了,可以通过 snapshot 规复,这个规复的操作就是 Rebuild。
    Rebuild 会用 snapshot 更换 instance 当前的镜像文件,同时保持 instance 的其他诸如网络,资源分配属性不变。
  • 下面是 rebuild instance 的流程图 :1)向 nova-api 发送请求;2)nova-api 发送消息;3)nova-compute 执行操作。

    1)向 nova-api 发送请求:
    客户(可以是 OpenStack 最终用户,也可以是其他步伐)向 API(nova-api)发送请求:“Rebuild 这个 Instance”:
    选择用于规复的 image:

    查看日志/opt/stack/logs/n-api.log :

    2)nova-api 发送消息:
    nova-api 向 Messaging(RabbitMQ)发送了一条消息:“Rebuild 这个 Instance”,源代码在 /opt/stack/nova/nova/compute/api.py,方法是 rebuild:

    3)nova-compute 执行操作:
    查看日志 /opt/stack/logs/n-cpu.log
    关闭 instance:


    下载新的 image,并准备 instance 的镜像文件 :


    启动 instance :

    Rebuild 后,GUI 显示 instance 已经使用新的 image :

2.3.7.12 Shelve-搁置虚拟机



  • Instance 被 Suspend 后固然处于 Shut Down 状态,但 Hypervisor 依然在宿主机上为其预留了资源,以便在以后能够成功 Resume。如果希望释放这些预留资源,可以使用 Shelve 操作。Shelve 会将 instance 作为 image 生存到 Glance 中,然后在宿主机上删除该 instance。
  • 下面是 shelve instance 的流程图 :1)向 nova-api 发送请求;2)nova-api 发送消息;3)nova-compute 执行操作。

    1)客户(可以是 OpenStack 最终用户,也可以是其他步伐)向API(nova-api)发送请求:“帮我 shelve 这个 Instance”:

    查看日志 /opt/stack/logs/n-api.log:

    2)nova-api 发送消息:
    nova-api 向 Messaging(RabbitMQ)发送了一条消息:“shelve 这个 Instance”。查看源代码 /opt/stack/nova/nova/compute/api.py,方法是 shelve:

    3)nova-compute 执行操作 :
    查看日志 /opt/stack/logs/n-cpu.log。首先,关闭 instance:

    然后对 instance 执行 snapshot 操作 :

    成功后,snapshot 天生的 image 会生存在 Glance 上,定名为 -shelved:

    末了删除 instance 在宿主机上的资源 :

    暂停操作成功执行后,instance 的状态变为 Shelved Offloaded,电源状态是 Shut Down:

2.3.7.13 Unshelve-取消搁置虚拟机



  • 上一节我们 shelve instance 到 Glance,本节讨论怎样通过 unshelve 操作规复该 instance。因为 Glance 中生存了 instance 的 image,unshelve 的过程实在就是通过该 image launch 一个新的 instance,nova-scheduler 也会调度符合的计算节点来创建该 instance。instance unshelve 后可能运行在与 shelve 之前不同的计算节点上,但 instance 的其他属性(好比 flavor,IP 等)不会改变。
  • 下面是 Unshelve instance 的流程图 :1)向 nova-api 发送请求;2)nova-api 发送消息;3)nova-scheduler 执行调度;4)nova-scheduler 发送消息;5)nova-compute 执行操作。

    1)向 nova-api 发送请求 :
    客户(可以是 OpenStack 最终用户,也可以是其他步伐)向 API(nova-api)发送请求:“帮我 Unshelve 这个 Instance”:

    查看日志 /opt/stack/logs/n-api.log:

    2)nova-api 发送消息:
    nova-api 向 Messaging(RabbitMQ)发送了一条消息:“unshelve 这个 Instance”。查看源代码 /opt/stack/nova/nova/compute/api.py,方法是 unshelve:

    3)nova-scheduler 执行调度:
    nova-scheduler 收到消息后,会为 instance 选择符合的计算节点;查看日志 /opt/stack/logs/n-sch.log:


    经过筛选,最终 devstack-controller 被选中 launch instance。
    4)nova-scheduler 发送消息 :
    nova-scheduler 发送消息,告诉被选中的计算节点可以 launch instance 了。源代码在/opt/stack/nova/nova/scheduler/filter_scheduler.py 第 95 行,方法为 select_destinations:

    5) nova-compute 执行操作 :
    nova-compute 执行 unshelve 的过程与 launch instance 非常类似。一样会经过如下几个步骤:a)为 instance 准备 CPU、内存和磁盘资源;b)创建 instance 镜像文件;c)创建 instance 的 XML 定义文件;d)创建虚拟网络并启动 instance。
2.3.7.14 Migrate -迁移虚拟机



  • Migrate 操作的作用是将 instance 从当前的计算节点迁移到其他节点上。Migrate 不要求源和目标节点必须共享存储,当然共享存储也是可以的。Migrate 前必须满足一个条件:计算节点间必要设置 nova 用户无密码访问。
  • 下面是 Migrate instance 的流程图:1)向 nova-api 发送请求;2)nova-api 发送消息;3)nova-scheduler 执行调度;4)nova-scheduler 发送消息;5)nova-compute 执行操作。

    1)向 nova-api 发送请求 :
    客户(可以是 OpenStack 最终用户,也可以是其他步伐)向 API(nova-api)发送请求:“帮我迁移这个 Instance”;Migrate 操作是特权操作,只能在 Admin 的 instance 菜单中执行:



    查看日志 /opt/stack/logs/n-api.log:

    2) nova-api 发送消息:
    nova-api 向 Messaging(RabbitMQ)发送了一条消息:“迁移这个 Instance”;查看源代码/opt/stack/nova/nova/compute/api.py,方法是 resize。 没错,是 resize 而非 migrate。 这是由于 migrate 实际上是通过 resize 操作实现的,至于为什么要如许计划,我们会在下一节 resize 中详细分析。

    3)nova-scheduler 执行调度
    nova-scheduler 收到消息后,会为 instance 选择符合的目标计算节点。查看日志 /opt/stack/logs/n-sch.log可以看到,因为 devstack-compute1 的权值比 devstack-controller 大,最终选择 devstack-compute1 作为目标节点。

    看到上面的日志,各人发现什么题目没有?
    在分析这段日志的时候,我发现 scheduler 选出来的计算节点有可能是当前节点源节点!因为 scheduler 并没在初始的时候将源节点剔除掉,而是与其他节点放在一起做 filter,按照这个逻辑,只要源节点的权值足够大,是有可能成为目标节点的。
    那紧接着的题目是:如果源节点和目标节点是同一个,migrate 操作会怎样举行呢?
    实验得知,nova-compute 在做 migrate 的时候会检查目标节点,如果发现目标节点与源节点相同,会抛出 UnableToMigrateToSelf 非常。Nova-compute 失败之后,scheduler 会重新调度,由于有 RetryFilter,会将之前选择的源节点过滤掉,如许就能选到不同的计算节点了。 在上面的操作中 sheduler 选择的目标节点是 devstack-compute1,意味着 instance 将从 devstack-controller 迁移到 devstack-compute1。
    4)nova-scheduler 发送消息:
    nova-scheduler 发送消息,通知计算节点可以迁移 instance 了
    源代码在/opt/stack/nova/nova/scheduler/filter_scheduler.py 第 95 行,方法为 select_destinations(选择目标节点):

    4)nova-compute 执行操作 :
    nova-compute 会在源计算节点和目标计算节点上分别执行操作。
    源计算节点 devstack-controller:
    迁移操作在源节点上首先会关闭 instance,然后将 instance 的镜像文件传到目标节点上。日志在 /opt/stack/logs/n-cpu.log,详细步骤如下:
    a)开始 migrate

    b)在目标节点上创建 instance 的目录:
    nova-compute 首先会实验通过 ssh 在目标节点上的 instance 目录里 touch 一个临时文件,日志如下:

    如果 touch 失败,说明目标节点上还没有该 instance 的目录,也就是说,源节点和目标节点没有共享存储。
    那么接下来就要在目标节点上创建 instance 的目录,日志如下:

    关闭 instance:

    将 instance 的镜像文件通过 scp 传到目标节点上:

    目标计算节点 devstack-compute1:
    在目标节点上启动 instance,过程与 launch instance 非常类似。会经过如下几个步骤:为 instance 准备 CPU、内存和磁盘资源;创建 instance 镜像文件;创建 instance 的 XML 定义文件;创建虚拟网络并启动 instance。
    5)Confirm
    这时,instance 会处于 “Confirm or Revert Resize/Migrate”状态,必要用户确认或者回退当前的迁移操作,实际上给了用户一个反悔的机会。

    当我们按下 Confirm 按钮后,会发生如下事情,nova-api 接收到 confirm 的消息:

    源计算节点删除 instance 的目录,并在 Hypervisor 上删除 instance:


    目标计算节点不必要做任何事情。
    6)Revert还原
    如果执行的是 Revert 操作会发生什么事情呢?

    nova-api 接收到 revert 的消息:

    在目标计算节点上关闭 instance,删除 instance 的目录,并在 Hypervisor 上删除 instance:


    源计算节点上启动 instance:
    因为之前迁移的时候只是在源节点上关闭了该 instance,revert 操作只需重新启动 instance。


    以上是 Migrate 操作的完备流程,这里有一点必要特别注意:迁移过程中源和目标节点之前必要使用 ssh 和 scp,为了使操作顺利举行,必须要保证 nova-compute 历程的启动用户(通常是 nova,也可能是 root,可以通过 ps 下令确认)能够在计算节点之间无密码访问。否则 nova-compute 会等待密码输入,但后台服务是无法输入密码的,迁移操作会不停卡在那里。
2.3.7.15 Resize-调解虚拟机的vCPU、内存和磁盘资源



  • Resize 的作用是调解 instance 的 vCPU、内存和磁盘资源。Instance 必要多少资源是定义在 flavor 中的,resize 操作是通过为 instance 选择新的 flavor 来调解资源的分配。
  • 有了前面对 Migrate 的分析,再来看 Resize 的实现就非常简单了。因为 instance 必要分配的资源发生了变化,在 resize 之前必要借助 nova-scheduler 重新为 instance 选择一个符合的计算节点,如果选择的节点与当前节点不是同一个,那么就必要做 Migrate。以是本质上讲:Resize 是在 Migrate 的同时应用新的 flavor。 Migrate 可以看做是 resize 的一个特例:flavor 没发生变化的 resize,这也是为什么我们在上一节日志中看到 migrate 实际上是在执行 resize 操作。
  • 下面是 Resize instance 的流程图:1)向 nova-api 发送请求;2)nova-api 发送消息;3)nova-scheduler 执行调度;4)nova-scheduler 发送消息;5)nova-compute 执行操作。

  • Resize 分两种环境:
    1)nova-scheduler 选择的目标节点与源节点是不同节点。操作过程跟上一节 Migrate 几乎完全一样,只是在目标节点启动 instance 的时候按新的 flavor 分配资源。 同时,因为要跨节点复制文件,也必须要保证 nova-compute 历程的启动用户(通常是 nova,也可能是 root,可以通过 ps 下令确认)能够在计算节点之间无密码访问。 对这一种环境我们不再赘述,请参看前面 Migrate 小节。
    2)目标节点与源节点是同一个节点。则不必要 migrate。下面我们重点讨论这一种环境。
    a) 向 nova-api 发送请求
    客户(可以是 OpenStack 最终用户,也可以是其他步伐)向 API(nova-api)发送请求:“帮我 Resize 这个 Instance”:

    选择新的 flavor:

    点击 Resize 按钮:

    查看日志 /opt/stack/logs/n-api.log:

    b)nova-api 发送消息:
    nova-api 向 Messaging(RabbitMQ)发送了一条消息:“Resize 这个 Instance”。查看源代码/opt/stack/nova/nova/compute/api.py,方法是 resize_instance:

    c)nova-scheduler 执行调度:
    nova-scheduler 收到消息后,会为 instance 选择符合的目标计算节点。查看日志 /opt/stack/logs/n-sch.log:

    在本例中,nova-scheduler 选择了 devstack-compute1 作为的目节点,与源节点相同。
    d)nova-scheduler 发送消息 :
    nova-scheduler 发送消息,通知计算节点可以迁移 instance 了。源代码在 /opt/stack/nova/nova/scheduler/filter_scheduler.py 第 95 行,方法为 select_destinations:

    e)nova-compute 执行操作:
    在目标节点上启动 instance,过程与 launch instance 非常类似。日志纪录在 /opt/stack/logs/n-cpu.log。会经过如下几个步骤:
    按新的 flavor 为 instance 准备 CPU、内存和磁盘资源:

    关闭 instance:

    创建 instance 镜像文件:

    将 instance 的目录备份一份,定名为<instance_id>_resize,以便 revert:

    创建 instance 的 XML 定义文件:

    准备虚拟网络:

    启动 instance:

    f) Confirm
    这时,instance 的状态处于“Confirm or Revert Resize/Migrate”状态,必要用户确认或者回退当前的迁移操作,实际上给了用户一个反悔的机会。

    当我们按下 Confirm 按钮后,会发生如下事情:nova-api 接收到 confirm 的消息:

    删除计算节上备份的 instance 目录 <instance_id>_resize:


    g)revert规复
    反过来,如果执行 Revert 操作会发生什么事情呢?

    nova-api 接收到 revert 的消息:

    在计算节点上关闭 instance:

    通过备份目录 <instance_id>_resize 规复 instance 目录:

    重新启动 instance:

2.3.7.16 Live Migrate-在线迁移虚拟机



  • Migrate 操作会先将 instance 停掉,也就是所谓的“冷迁移”。
    而 Live Migrate 是“热迁移”,也叫“在线迁移”,instance不会停机。
  • Live Migrate 分两种:
    1)源和目标节点没有共享存储,instance 在迁移的时候必要将其镜像文件从源节点传到目标节点,这叫做 Block Migration(块迁移);
    2)源和目标节点共享存储,instance 的镜像文件不必要迁移,只必要将 instance 的状态迁移到目标节点。
  • 源和目标节点必要满足一些条件才气支持 Live Migration:
    1)源和目标节点的 CPU 类型要同等;
    2)源和目标节点的 Libvirt 版本要同等;
    3)源和目标节点能相互识别对方的主机名称,好比可以在 /etc/hosts 中参加对方的条目;

    4)在源和目标节点的 /etc/nova/nova.conf 中指明在线迁移时使用 TCP 协议;

    5)Instance 使用 config driver 生存其 metadata。在 Block Migration 过程中,该 config driver 也必要迁移到目标节点。由于目前 libvirt 只支持迁移 vfat 类型的 config driver,以是必须在 /etc/nova/nova.conf 中明白指明 launch instance 时创建 vfat 类型的 config driver;

    6)源和目标节点的 Libvirt TCP 长途监听服务得打开,必要在下面两个设置文件中做一点设置;

  • 非共享存储 Block Migration:
    我们先讨论非共享存储的 Block Migration流程图如下:1)向 nova-api 发送请求;2)nova-api 发送消息;3)nova-compute 执行操作。
    1)向nova-api发送请求 :
    客户(可以是 OpenStack 最终用户,也可以是其他步伐)向API(nova-api)发送请求:“帮我将这个 Instance 从节点 A Live Migrate 到节点 B”


    这里源节点是 devstack-compute1,目标节点是 devstack-controller,因为是非共享存储,记得将“Block Migration”勾选上。这里还有一个“Disk Over Commit”选项,如果勾选了此选项,nova 在检查目标节点的磁盘空间是否足够时,是以 instance 磁盘镜像文件定义的最大容量为准;否则,以磁盘镜像文件当前的实际巨细为准。
    查看日志 /opt/stack/logs/n-api.log:

    2)nova-api 发送消息 :
    nova-api 向 Messaging(RabbitMQ)发送了一条消息:“Live Migrate 这个 Instance” ;源代码在/opt/stack/nova/nova/compute/api.py,方法是 live_migrate:

    3)nova-compute 执行操作 :
    源和目标节点执行 Live Migrate 的操作过程如下:目标节点执行迁移前的准备工作,首先将 instance 的数据迁移过来,主要包括镜像文件、虚拟网络等资源,日志在 devstack-controller:/opt/stack/logs/n-cpu.log:


    源节点启动迁移操作,暂停 instance:

    在目标节点上 Resume instance:

    在源节点上执行迁移的后处理工作,删除 instance:


    在目标节点上执行迁移的后处理工作,创建 XML,在 Hypervisor 中定义 instance,使之下次能够正常启动。

    Instance 在 Live Migrate 的整个过程中不会停机,我们通过 Ping 操作来观察:

    可见在迁移过程中,Ping 历程没有中断,只是有一个 ping 包的延迟增加了。
  • 共享存储 Live Migration:
    有多种方式可以实现共享存储,好比可以将 instance 的镜像文件放在 NFS 服务器上,或者使用 NAS 服务器,或者分布式文件体系。作为学习和实验,这里我们接纳 NFS 方案。其他共享存储方案对于 Live Migration 本质上是一样的,只是在性能和高可用性上更好。
    1)搭建 NFS 环境
    将 devstack-controller 作为 NFS 服务器,共享其目录 /opt/stack/data/nova/instances。devstack-compute1 作为 NFS 客户端将此目录 mount 到本机,如下所示:

    如许,OpenStack 的 instance 在 devstack-controller 和 devstack-compute1 上就实现共享存储了。共享存储的迁移过程与 Block Migrate 基本上一样,只是几个环节有点区别:向 nova-api 提交请求的时候,不能勾选“Block Migrate”:

    因为源和目标节点都能直接访问 instance 的镜像,以是目标节点在准备阶段不必要传输镜像文件,源节点在迁移后处理阶段也无需删除 instance 的目录。只有 instance 的状态必要从源节点传输到的目标节点,整个迁移速递比 Block Migration 快许多。
2.3.7.17 Evacuate-撤离虚拟机



  • Rebuild 可以规复粉碎的 instance。那如果是宿主机坏了怎么办呢?好比硬件故障或者断电造成整台计算节点无法工作,该节点上运行的 instance 怎样规复呢?用 Shelve 或者 Migrate 可不可以?很不幸,这两个操作都要求 instance 地点计算节点的 nova-compute 服务正常运行。幸运的是,还有 Evacuate 操作。
  • Evacuate 可在 nova-compute 无法工作的环境下将节点上的 instance 迁移到其他计算节点上。但有个条件是 Instance 的镜像文件必须放在共享存储上。
  • 下面是 Evacuate instance 的流程图:1)向 nova-api 发送请求;2)nova-api 发送消息;3)nova-scheduler 执行调度;4)nova-scheduler 发送消息;5)nova-compute 执行操作。

    1)向 nova-api 发送请求 :
    我们的实验场景如下: Instance c2 运行在 devstack-compute1 上,通过断电模仿计算节点故障,然后执行 Evacuate 操作规复 instance c2,目前 Evacuate 只能通过 CLI 执行。


    这里必要指定 –on-shared-storage 这个参数。
    查看日志 /opt/stack/logs/n-api.log:

    2)nova-api 发送消息
    nova-api 向 Messaging(RabbitMQ)发送了一条消息:“Evacuate 这个 Instance”;查看源代码 /opt/stack/nova/nova/compute/api.py,方法是 evacuate:

    各人注意到没有,evacuate 实际上是通过 rebuild 操作实现的。这是可以理解的,因为 evacuate 是用共享存储上 instance 的镜像文件重新创建虚机
    3) nova-scheduler 执行调度 :
    nova-scheduler 收到消息后,会为 instance 选择符合的计算节点
    查看日志 /opt/stack/logs/n-sch.log:

    nova-scheduler 末了选择在 devstack-controller 计算节点上重修 instance。
    4) nova-compute 执行操作 :
    计算节点上的工作是用共享存储上的镜像文件重修 instance。日志在 devstack-controller:/opt/stack/logs/n-cpu.log。为instance分配资源:

    使用共享存储上的镜像文件:

    启动 instance:

    Evacuate 操作完成后,instance 在 devstack-controller 上运行。
2.3.7.18 Nova操作总结


如上图所示,我们把对 Instance 的管理按运维工作的场景分为两类:通例操作和故障处理。


  • 通例操作:通例操作中,Launch、Start、Reboot、Shut Off 和 Terminate 都很好理解。 下面几个操作重点回顾一下:
    1)Resize:通过应用不同的 flavor 调解分配给 instance 的资源。
    2)Lock/Unlock:可以防止对 instance 的误操作。
    3)Pause/Suspend/Resume:暂停当前 instance,并在以后规复。 Pause 和 Suspend 的区别在于 Pause 将 instance 的运行状态生存在计算节点的内存中,而 Suspend 生存在磁盘上。
    Pause 的优点是 Resume 的速度比 Suspend 快;缺点是如果计算节点重启,内存数据丢失,就无法 Resume 了,而 Suspend 则没有这个题目。
    4)Snapshot:备份 instance 到 Glance。产生的 image 可用于故障规复,或者以此为模板部署新的 instance。
  • 故障处理 :故障处理有两种场景:操持内和操持外。操持内是指提前安排时间窗口做的维护工作,好比服务器定期的微码升级,添加更换硬件等。操持外是指发生了没有预料到的突发故障,好比强行关机造成 OS 体系文件粉碎,服务器掉电,硬件故障等。
    1) 操持内故障处理:对于操持内的故障处理,可以在维护窗口中将 instance 迁移到其他计算节点。 涉及如下操作:
    a)Migrate:将 instance 迁移到其他计算节点。迁移之前,instance 会被 Shut Off,支持共享存储和非共享存储。
    b)Live Migrate:与 Migrate 不同,Live Migrate 能不绝机在线地迁移 instance,保证了业务的连续性。也支持共享存储和非共享存储(Block Migration)。
    c)Shelve/Unshelve:Shelve 将 instance 生存到 Glance 上,之后可通过 Unshelve 重新部署。Shelve 操作成功后,instance 会从原来的计算节点上删除。Unshelve 会重新选择节点部署,可能不是原节点。
    2) 操持外故障处理:操持外的故障按照影响的范围又分为两类:Instance 故障和计算节点故障;
    a)Instance 故障:Instance故障只限于某一个 instance 的操作体系层面,体系无法正常启动。可以使用如下操作修复 instance:
    i)Rescue/Unrescue:用指定的启动盘启动,进入 Rescue 模式,修复受损的体系盘。成功修复后,通过 Unrescue 正常启动 instance。
    ii)Rebuild:如果 Rescue 无法修复,则只能通过 Rebuild 从已有的备份规复。Instance 的备份是通过 snapshot 创建的,以是必要有备份计谋定期备份。
    b)计算节点故障:Instance 故障的影响范围局限在特定的 instance,计算节点自己是正常工作的。如果计算节点发生故障,OpenStack 则无法与节点的 nova-compute 通讯,其上运行的所有 instance 都会受到影响。这个时候,只能通过 Evacuate 操作在其他正常节点上重修 Instance。
    i)Evacuate:利用共享存储上 Instance 的镜像文件在其他计算节点上重修 Instance。 以是提前规划共享存储是关键。
2.4 块存储服务Cinder:为 instance 提供虚拟磁盘




  • 理解 Block Storage
    操作体系获得存储空间的方式一般有两种:1)通过某种协议(SAS,SCSI,SAN,iSCSI 等)挂接裸硬盘,然后分区、格式化、创建文件体系;或者直接使用裸硬盘存储数据(数据库);2)通过 NFS、CIFS 等 协议,mount 长途的文件体系。
    第一种裸硬盘的方式叫做 Block Storage(块存储),每个裸硬盘通常也称作 Volume(卷);
    第二种叫做文件体系存储。NAS 和 NFS 服务器,以及各种分布式文件体系提供的都是这种存储。
  • 理解 Block Storage Service
    Block Storage Service提供对 volume 从创建到删除整个生命周期的管理。从 instance 的角度看,挂载的每一个 Volume 都是一块硬盘。OpenStack 提供 Block Storage Service 的是 Cinder,其详细功能是:1)提供 REST API 使用户能够查询和管理 volume、volume snapshot 以及 volume type;2)提供 scheduler 调度 volume 创建请求,公道优化存储资源的分配;3)通过 driver 架构支持多种 back-end(后端)存储方式,包括 LVM,NFS,Ceph 和其他诸如 EMC、IBM 等贸易存储产物和方案。
2.4.1 Cider架构




  • 上图是cider的逻辑架构,包罗如下组件:
    1)cinder-api:接收 API 请求,调用 cinder-volume 执行操作;
    2)cinder-volume:管理 volume 的服务,与 volume provider 和谐工作,管理 volume 的生命周期。运行 cinder-volume 服务的节点被称作为存储节点;
    3)cinder-scheduler:scheduler 通过调度算法选择最符合的存储节点创建 volume;
    4)volume provider:数据的存储装备,为 volume 提供物理存储空间。cinder-volume 支持多种 volume provider,每种 volume provider 通过自己的 driver 与cinder-volume 和谐工作。
    5)Message Queue:Cinder 各个子服务通过消息队列实现历程间通讯和相互协作。因为有了消息队列,子服务之间实现相识耦,这种疏松的布局也是分布式体系的紧张特征。
    6)Database:Cinder 有一些数据必要存放到数据库中,一般使用 MySQL。数据库是安装在控制节点上的,好比在我们的实验环境中,可以访问名称为“cinder”的数据库。

2.4.2 物理部署方案



  • Cinder 的服务会部署在两类节点上,控制节点和存储节点。我们来看看控制节点 devstack-controller 上都运行了哪些 cinder-* 子服务:

    inder-api 和 cinder-scheduler 部署在控制节点上,这个很公道。至于 cinder-volume 也在控制节点上可能有些同砚就会迷糊了:cinder-volume 不是应该部署在存储节点上吗?
    要回答这个题目,首先要搞清楚一个究竟:OpenStack 是分布式体系,其每个子服务都可以部署在任何地方,只要网络能够连通。无论是哪个节点,只要上面运行了 cinder-volume,它就是一个存储节点,当然,该节点上也可以运行其他 OpenStack服务。
    cinder-volume 是一顶存储节点帽子,cinder-api 是一顶控制节点帽子。在我们的环境中,devstack-controller 同时戴上了这两顶帽子,以是它既是控制节点,又是存储节点。当然,我们也可以用一个专门的节点来运行 cinder-volume。这再一次展示了 OpenStack 分布式架构部署上的机动性:可以将所有服务都放在一台物理机上,用作一个 All-in-One 的测试环境;而在生产环境中可以将服务部署在多台物理机上,获得更好的性能和高可用。RabbitMQ 和 MySQL 通常是放在控制节点上的。
  • 另外,也可以用 cinder service list 查看 cinder-* 子服务都分布在哪些节点上:

  • 还有一个题目:volume provider 放在那里:一般来讲,volume provider 是独立的。cinder-volume 使用 driver 与 volume provider 通讯并和谐工作。以是只必要将 driver 与 cinder-volume 放到一起就可以了。在 cinder-volume 的源代码目录下有许多 driver,支持不同的 volume provider。

    后面我们会以 LVM 和 NFS 这两种 volume provider 为例讨论 cinder-volume 的使用,其他 volume provider 可以查看 OpenStack 的 configuration 文档。
2.4.3 Cinder计划思想



  • 从 volume 创建流程看 cinder-* 子服务怎样协同工作 ,对于 Cinder 学习来说,Volume 创建是一个非常好的场景,涉及各个 cinder-* 子服务,下面是流程图:

    1)客户(可以是 OpenStack 最终用户,也可以是其他步伐)向 API(cinder-api)发送请求:“帮我创建一个volume”;
    2)API 对请求做一些须要处理后,向 Messaging(RabbitMQ)发送了一条消息:“让 Scheduler 创建一个 volume” ;
    3)Scheduler(cinder-scheduler)从 Messaging 获取到 API 发给它的消息,然后执行调度算法,从若干计存储点中选出节点 A ;
    4)Scheduler 向 Messaging 发送了一条消息:“让存储节点 A 创建这个 volume”;
    5)存储节点 A 的 Volume(cinder-volume)从 Messaging 中获取到 Scheduler 发给它的消息,然后通过 driver 在 volume provider 上创建 volume。
  • Cinder计划思想:Cinder 连续了 Nova 的以及其他组件的计划思想。
    1)API 前端服务:
    cinder-api 作为 Cinder 组件对外的唯一窗口,向客户暴露 Cinder 能够提供的功能,当客户必要执行 volume 相干的操作,只能向 cinder-api 发送 REST 请求。这里的客户包括终端用户、下令行和 OpenStack 其他组件。
    计划 API 前端服务的好处在于:
    a)对外提供同一接口,隐藏实现细节;
    b)API 提供 REST 标准调用服务,便于与第三方体系集成;
    c)可以通过运行多个 API 服务实例轻松实现 API 的高可用,好比运行多个 cinder-api 历程。
    2)Scheduler 调度服务:
    Cinder 可以有多个存储节点,当必要创建 volume 时,cinder-scheduler 会根据存储节点的属性和资源使用环境选择一个最符合的节点来创建 volume。
    3)Worker 工作服务:
    调度服务只管分配任务,真正执行任务的是 Worker 工作服务。 在 Cinder 中,这个 Worker 就是 cinder-volume 了。这种 Scheduler 和 Worker 之间职能上的分别使得 OpenStack 非常容易扩展:当存储资源不敷时可以增加存储节点(增加 Worker)。当客户的请求量太大调度不过来时,可以增加 Scheduler。
    4)Driver 框架:
    以 Cinder 为例,存储节点支持多种 volume provider,包括 LVM, NFS, Ceph, GlusterFS,以及 EMC, IBM 等贸易存储体系。cinder-volume 为这些 volume provider 定义了同一的 driver 接口,volume provider 只必要实现这些接口,就可以 driver 的情势即插即用到 OpenStack 中。
    下面是 cinder driver 的架构示意图:

    在 cinder-volume 的设置文件 /etc/cinder/cinder.conf 中 volume_driver 设置项设置该存储节点使用哪种 volume provider 的 driver,下面的示例表示使用的是 LVM。

2.4.4 Cinder 组件详解

2.4.4.1 cinder-api



  • cinder-api 是整个 Cinder 组件的门户,所有 cinder 的请求都首先由 cinder-api 处理。cinder-api 向外界暴露若干 HTTP REST API 接口。在 keystone 中我们可以查询 cinder-api 的 endponits。

    客户端可以将请求发送到 endponits 指定的地址,向 cinder-api 请求操作。当然,作为最终用户的我们不会直接发送 Rest API 请求。OpenStack CLI,Dashboard 和其他必要跟 Cinder 交换的组件会使用这些 API。
  • cinder-api 对接收到的 HTTP API 请求会做如下处理:1)检查客户端传人的参数是否合法有用;2)调用 cinder 其他子服务的处理客户端请求;3)将 cinder 其他子服务返回的结果序列号并返回给客户端。
  • cinder-api 接受哪些请求呢?
    简单的说,只要是 Volume 生命周期相干的操作,cinder-api 都可以响应。大部分操作都可以在 Dashboard 上看到。打开 Volume 管理界面:

    点击下拉箭头,列表中就是 cinder-api 可执行的操作:

2.4.4.2 cinder-scheduler



  • 创建 Volume 时,cinder-scheduler 会基于容量、Volume Type 等条件选择出最符合的存储节点,然后让其创建 Volume。
  • 在 /etc/cinder/cinder.conf 中,cinder 通过 scheduler_driver, scheduler_default_filters 和 scheduler_default_weighers 这三个参数来设置 cinder-scheduler。
    1)Filter scheduler:
    Filter scheduler 是 cinder-scheduler 默认的调度器

    与 Nova 一样,Cinder 也允许使用第三方 scheduler,设置 scheduler_driver 即可。
    scheduler 调度过程如下:
    i)通过过滤器(filter)选择满足条件的存储节点(运行 cinder-volume);
    ii)通过权重计算(weighting)选择最优(权重值最大)的存储节点。
    可见,cinder-scheduler 的运行机制与 nova-scheduler 完全一样。
    2)Filter :
    当 Filter scheduler 必要执行调度操作时,会让 filter 对存储节点举行判定,filter 返回 True 或者 False。cinder.conf 中 scheduler_default_filters 选项指定 filter scheduler 使用的 filter,默认值如下:

    a)AvailabilityZoneFilter:
    为提高容灾性和提供隔离服务,可以将存储节点和计算节点分别到不同的 Availability Zone 中。比方把一个机架上的机器分别在一个 Availability Zone 中。OpenStack 默认有一个定名为“Nova” Availability Zone 的,所有的节点初始都是放在“Nova”中。用户可以根据必要创建自己的 Availability Zone。

    创建 Volume 时,必要指定 Volume 所属的 Availability Zone。

    cinder-scheduler 在做 filtering 时,会使用 AvailabilityZoneFilter 将不属于指定 Availability Zone 的存储节点过滤掉。
    b)CapacityFilter:
    创建 Volume 时,用户会指定 Volume 的巨细。CapacityFilter 的作用是将存储空间不能满足 Volume 创建需求的存储节点过滤掉。

    c)CapabilitiesFilter:
    不同的 Volume Provider 有自己的特性(Capabilities),好比是否支持 thin provision 等。Cinder 允许用户创建 Volume 时通过 Volume Type 指定必要的 Capabilities。

    Volume Type 可以根据必要定义若干 Capabilities,详细形貌 Volume 的属性。VolumeVolume Type 的作用与 Nova 的 flavor 类似。Volume Type 在 Admin -> System -> Volume 菜单里管理:

    通过 Volume Type 的 Extra Specs 定义 Capabilities:

    Extra Specs 是用 Key-Value 的情势定义。不同的 Volume Provider 支持的 Extra Specs 不同,必要参考 Volume Provider 的文档。

    上图所示的 Volume Type 只有一个 Extra Specs “volume_backend_name”,这是最紧张也是必须的 Extra Specs。cinder-volume 会在自己的设置文件 /etc/cinder/cinder.conf 中设置“volume_backend_name”这个参数,其作用是为存储节点的 Volume Provider 定名。如许,CapabilitiesFilter 就可以通过 Volume Type 的“volume_backend_name”筛选出指定的 Volume Provider。不同的存储节点可以在各自的 cinder.conf 中设置相同的 volume_backend_name,这是允许的。因为固然存储节点不同,但它们可能使用的是一种 Volume Provider。如果在第一步 filtering 环节选出了多个存储节点,那么接下来的 weighting 环节会挑选出最符合的一个节点。
    3)Weighter :
    Filter Scheduler 通过 scheduler_default_weighers 指定计算权重的 weigher,默认为 CapacityWeigher。

    如定名所示,CapacityWeigher 基于存储节点的空闲容量计算权重值,空闲容量最大的胜出。
2.4.4.3 cinder-volume



  • cinder-volume 在存储节点上运行,OpenStack 对 Volume 的操作,末了都是交给 cinder-volume 来完成的。cinder-volume 自身并不管理真正的存储装备,存储装备是由 volume provider 管理的。cinder-volume 与 volume provider 一起实现 volume 生命周期的管理。
  • 通过 Driver 架构支持多种 Volume Provider
    接着的题目是:如今市面上有这么多块存储产物和方案(volume provider),cinder-volume 怎样与它们配合呢?
  • 这就是我们之前讨论过的 Driver 架构。cinder-volume 为这些 volume provider 定义了同一的接口,volume provider 只必要实现这些接口,就可以 Driver 的情势即插即用到 OpenStack 体系中。
    下面是 Cinder Driver 的架构示意图:

    我们可以在 /opt/stack/cinder/cinder/volume/drivers/ 目录下查看到,OpenStack 源代码中已经自带了许多 volume provider 的 Driver:

    存储节点在设置文件 /etc/cinder/cinder.conf 中用 volume_driver 选项设置使用的driver:设置使用的driver

    这里 LVM 是我们使用的 volume provider。
  • 定期向 OpenStack 陈诉计算节点的状态
    在前面 cinder-scheduler 会用到 CapacityFilter 和 CapacityWeigher,它们都是通过存储节点的空闲容量来做筛选。那这里有个题目:Cinder 是怎样得知每个存储节点的空闲容量信息的呢?答案就是:cinder-volume 会定期向 Cinder 陈诉。
  • 从 cinder-volume 的日志 /opt/stack/logs/c-vol.log 可以发现每隔一段时间,cinder-volume 就会陈诉当前存储节点的资源使用环境。

    因为在我们的实验环境中存储节点使用的是 LVM,以是在上面的日志看到存储节点通过“vgs”和”lvs”这两个下令获取 LVM 的容量使用信息。
  • 实现 volume 生命周期管理
    Cinder 对 volume 的生命周期的管理最终都是通过 cinder-volume 完成的,包括 volume 的 create、extend、attach、snapshot、delete 等,后面我们会详细讨论。
2.4.5 通过场景学习Cinder

2.4.5.1 准备LVM Volume Provider



  • Cinder 真正负责 Volume 管理的组件是 volume provider。cinder 支持多种 volume provider,LVM 是默认的 volume provider。
  • Devstack 安装之后,/etc/cinder/cinder 已经设置好了 LVM,如下图所示:

    上面的设置定义了名为“lvmdriver-1”的 volume provider,也称作 back-end。其 driver 是 LVM,LVM 的 volume group 名为“stack-volumes-lvmdriver-1”。
  • Devstack 安装时并没有自动创建 volume group,以是必要我们手工创建。如下步骤演示了在 /dev/sdb 上创建 VG “stack-volumes-lvmdriver-1”:
    1)首先创建 physical volume /dev/sdb:

    Linux 的 lvm 默认设置不允许在 /dev/sdb 上创建 PV,必要将 sdb 添加到 /etc/lvm.conf 的 filter 中。


    2)然后创建 VG stack-volumes-lvmdriver-1:

    打开 Web GUI,可以看到 OpenStack 已经创建了 Volume Type “lvmdriver-1”:

    其 Extra Specs volume_backend_name 为 lvmdriver-1:

2.4.5.2 创建volume



  • Create 操作流程如下:

    1)客户(可以是 OpenStack 最终用户,也可以是其他步伐)向 API(cinder-api)发送请求:“帮我创建一个 volume”。
    2)API 对请求做一些须要处理后,向 Messaging(RabbitMQ)发送了一条消息:“让 Scheduler 创建一个 volume”。
    3)Scheduler(cinder-scheduler)从 Messaging 获取到 API 发给它的消息,然后执行调度算法,从若干计存储点中选出节点 A。
    4)Scheduler 向 Messaging 发送了一条消息:“让存储节点 A 创建这个 volume”。
    5)存储节点 A 的 Volume(cinder-volume)从 Messaging 中获取到 Scheduler 发给它的消息,然后通过 driver 在 volume provider 上创建 volume。
  • 向 cinder-api 发送请求:
    客户(可以是 OpenStack最终用户,也可以是其他步伐)向 cinder-api发送请求:“帮我创建一个 volume。GUI 上操作的菜单为 Project -> Compute -> Volumes -> Create Volume:

    设置 volume 的名称,volume type,巨细,Availability Zone 等基本信息。这里我们没有设置 Volume Source,如许会创建一个空缺的 volume。点击“Create Volume” 按钮,cinder-api 将接收到创建 volume 的请求。

    查看 cinder-api 日志 /opt/stack/logs/c-api.log:

    日志显示 cinder-api 接收到一个 POST 类型的 REST API,经过对 HTTP body 的分析,该请求是:创建一个 1GB 的 volume。紧接着,cinder-api 启动了一个 Flow(工作流)volume_create_api。Flow 的执行状态依次为 PENDING(待定), RUNNING 和 SUCCESS。volume_create_api 当前的状态由 PENDING 变为 RUNNING。

    volume_create_api 工作流包罗若干 Task,每个 Task 完成特定的任务
    这些任务依次为 ExtractVolumeRequestTask, QuotaReserveTask, EntryCreateTask, QuotaCommitTask, VolumeCastTask。Task 的执行状态也会经历 PENDING, RUNNING 和 SUCCESS 三个阶段。Task 的名称基本上说明白任务的工作内容,前面几个 Task 主要是做一些创建 volume 的准备工作,好比:
    1)ExtractVolumeRequestTask 获取 request 信息:

    2)QuotaReserveTask 预留配额:

    3)EntryCreateTask 在数据库中创建 volume 条目:

    4)QuotaCommitTask 确认配额:

    5)末了 VolumeCastTask 是向 cinder-sheduler 发送消息,开始调度工作:

    6)至此,Flow volume_create_api 已经完成,状态由 RUNNING 变为 SUCCESS,volume 创建成功。日志如下:

    必要特别注意的是,“volume 创建成功”只是指 cinder-api 已经成功处理了 volume create 请求,将消息发给了 cinder-scheduler,但并不意味 volume 在存储节点上已经成功创建, 这一点是容易引起误解的。我们可以通过 cinder-volume 创建 volume 日志的时间戳验证。
    cinder-api 发送消息:
    cinder-api 向 RabbitMQ 发送了一条消息:“让cinder-scheduler 创建一个 volume”。前面我们提到消息是由 VolumeCastTask 发出的,因为 VolumeCastTask 没有打印相干日志,我们只能通过源代码查看
    /opt/stack/cinder/cinder/volume/flows/api/create_volume.py ,方法为 create_volume。

  • cinder-scheduler 执行调度:
    cinder-scheduler 执行调度算法,通过 Filter 和 Weigher 挑选最优的存储节点,日志为 /opt/stack/logs/c-sch.log。
    1)cinder-scheduler 通过 Flow volume_create_scheduler 执行调度工作:

    2)该 Flow 依次执行 ExtractSchedulerSpecTask 和 ScheduleCreateVolumeTask:

    3)主要的 filter 和 weighting 工作由 ScheduleCreateVolumeTask 完成
    ScheduleCreateVolumeTask:

    经过 AvailabilityZoneFilter, CapacityFilter, CapabilitiesFilter 和 CapacityWeigher 的层层筛选,最终选择了存储节点 devstack-controller@lvmdriver-1#lvmdriver-1。
    4)Flow volume_create_scheduler 完成调度,状态变为 SUCCESS:
    5)cinder-scheduler 发送消息 :
    cinder-scheduler 发送消息给 cinder-volume,让其创建 volume。源码 /opt/stack/cinder/cinder/scheduler/filter_scheduler.py,方法为 schedule_create_volume:

  • cinder-volume 的处理过程:
    cinder-volume 通过 driver 创建 volume,日志为 /opt/stack/logs/c-vol.log。
    1)与 cinder-api 和 cinder-scheduler 执行方式类似,cinder-volume 也启动了一个 Flow 来完成 volume 创建工作。Flow 的名称为 volume_create_manager:

    2)volume_create_manager 执行操作:
    首先执行ExtractVolumeRefTask, OnFailureRescheduleTask, ExtractVolumeSpecTask, NotifyVolumeActionTask 为 volume 创建做准备。




    3)接下来 CreateVolumeFromSpecTask 执行 volume 创建任务
    创建任务:

    因为 volume provider 为 LVM, CreateVolumeFromSpecTask 通过 lvcreate 下令在 VG stack-volumes-lvmdriver-1 中创建了一个 1G 的 LV,cinder-volume 将这个 LV 作为volume。新创建的 LV 定名为“volume-1e7f6bd7-ce11-4a73-b95e-aabd65a5b188”,其格式为“volume-”。


    4)末了,CreateVolumeOnFinishTask 完成扫尾工作:

    5)至此,volume 成功创建,Flow volume_create_manager 竣事:


2.4.5.3 Attach附加磁盘

本节讨论 cinder-volume 和 nova-compute 怎样将 volume attach 到 Instance。


  • cinder-volume 初始化 volume 的毗连:
    cinder-volume 接收到 initialize_connection 消息后,会通过 tgt 创建 target,并将 volume 所对应的LV 通过 target export 出来。日志为 /opt/stack/logs/c-vol.log:

    下面的日志显示:
    通过下令tgtadm –lld iscsi –op show –mode target 看到已经将 1GB(1074MB)的 LV /dev/stack-volumes-lvmdriver-1/volume-1e7f6bd7-ce11-4a73-b95e-aabd65a5b188 通过 Target 1 export 出来了。

    Initialize connection 完成:

  • nova-compute 将 volume attach 到 instance:
    1)iSCSI是由IBM发明的基于以太网的存储协议,该协议与SUN的NFS协议都是为相识决存储资源共享题目的解决方案。两者意图同等,只不过两者是不同的实现方式,前者在客户机上呈现的是一个块装备,概括的说,iSCSI是一种存储装备长途映射技术,它可以将一个长途服务器上的存储装备映射到本地,并呈现为一个块装备(明白话就是磁盘)。从平凡用户的角度,映射过来的磁盘与本地安装的磁盘毫无差异。这种映射方式基于是基于SCSI协议的,SCSI协议是计算机与外围装备(比方硬盘、光盘等)通讯的协议。而iSCSI则是通过TCP协议对SCSI举行封装的一种协议,也就是通过以太网传输SCSI协议的内容。
    2)计算节点作为 iSCSI initiator 访问存储节点 Iscsi Target 上的 volume,并将其 attach 到 instance。日志文件为 /opt/stack/logs/n-cpu.log:

    3)nova-compute 依次执行 iscsiadm 的 new, update, login, rescan 操作访问 target 上的 volume:(iscsiadm是基于下令行的iscsi管理工具,提供了对iSCSI节点、会话、毗连以及发现纪录的操作。)




    4)计算节点将 iSCSI target 上的 volume 识别为一个磁盘文件:

    5)然后通过更新 instance 的 XML 设置文件将 volume 映射给 instance:

    6)我们也可以通过 virsh edit 查看更新后的 XML:

    可以看到,instance 增加了一个类型为 block 的虚拟磁盘,source 就是要 attach 的 volume,该虚拟磁盘的装备名为 vdb。
    7)手工 Shut off 并 Start instance,通过 fdisk -l 查看到 volume 已经 attach 上来,装备为 vdb:

    8)GUI 界面也会更新相干 attach 信息:

    如今如果我们在存储节点执行 tgt-admin –show –mode target,会看到计算节点作为 initiator 已经毗连到 target 1。cinder-volume 刚刚创建 target 的时候是没有 initiator 毗连的,各人可以将下面的截图与之前的日志做个对比。

2.4.5.4 Detach卸载磁盘



  • 下图是Detach操作流程图,包罗1)向 cinder-api 发送 detach 请求;2)cinder-api 发送消息;3)nova-compute detach volume;4)cinder-volume 删除 target。

    1)向 cinder-api 发送 attach 请求:
    客户(可以是 OpenStack 最终用户,也可以是其他步伐)向 cinder-api 发送请求:“请 detach 指定 instance 上的 volume。这里我们将 detach instance “c2”上的 volume “vol-1” 。进入 GUI 操作菜单Project -> Compute -> Volumes:

    选择 volume “vol-1”,点击“Manage Attachments” :

    点击 “Detach Volume”:

    再次确认:

    cinder-api 将接收到 detach volume 的请求。日志文件在 /opt/stack/logs/c-api.log:

    2)cinder-api 发送消息
    cinder-api 发送消息 detach 消息。cinder-api 没有打印发送消息的日志,只能通过源代码查看 /opt/stack/cinder/cinder/volume/api.py,方法为 detach:

    Detach 的操作由 nova-compute 和 cinder-volume 共同完成。首先 nova-compute 将 volume 从 instance 上 detach,然后断开与 iSCSI target 的毗连;末了 cinder-volume 删除 volume 相干的 iSCSI target。
    a)nova-compute detach volume:
    nova-compute 首先将 volume 从 instance 上 detach,日志为 /opt/stack/logs/n-cpu.log。

    这时通过 virsh edit 可以看到 XML 设置文件中已经不在有 volume 的虚拟磁盘:

    接下来断开与 iSCSI target 的毗连:

    详细步骤如下:
    i)将缓存中的数据 Flush 到 volume。

    ii)删除计算节点上 volume 对应的 SCSI 装备。

    iii)通过 iscsiadm 的 logout,delete 操作断开与 iSCSI target 的毗连。

    compue-nova 完成了 detach 工作,接下来 cinder-volume 就可以删除 volume 相干的 target 了。
    b)cinder-volume 删除 target:
    存储节点 cinder-volume 通过 tgt-admin 下令删除 volume 对应的 target;日志文件为 /opt/stack/logs/c-vol.log。

    至此 detach volume 操作已经完成,GUI 也会更新 volume 的 attach 信息:

2.4.5.5 Extend扩展磁盘



  • 为了保护现有数据,cinder 不允许缩小 volume。Extend 操作用于扩大 Volume 的容量,状态为 Available 的 volume 才气够被 extend。如果 volume 当前已经 attach 给 instance,必要先 detach 后才气 extend。
  • Extend 实现比较简单,流程图如下所示:1)向 cinder-api 发送 extend 请求;2)cinder-api 发送消息;3)cinder-volume 执行 extend 操作。

    1)向 cinder-api 发送 extend 请求:
    客户(可以是 OpenStack 最终用户,也可以是其他步伐)向 cinder-api 发送请求:“请 extend 指定的 volume。这里我们将 extend volume “vol-2”。进入 GUI 操作菜单 Project -> Compute -> Volumes:

    vol-2 当前巨细为 1GB。其在存储节点上对应的 LV 信息如下
    LV 信息如下:

    选择 volume “vol-2”,点击 “Extend Volume”:

    指定新的容量为 3GB,点击 “Extend Volume”:

    cinder-api 将接收到 extend volume 的请求,日志文件在 /opt/stack/logs/c-api.log:

    2)cinder-api 发送消息:
    cinder-api 发送extend 消息。cinder-api 没有打印发送消息的日志,只能通过源代码查看。/opt/stack/cinder/cinder/volume/api.py,方法为 extend:

    3) cinder-volume extend volume:
    cinder-volume 执行 lvextend 下令 extend volume。日志为 /opt/stack/logs/c-vol.log:

    LV 被 extend 到 3GB:

    Extend 操作完成后,GUI 也会更新 volume 的状态信息:

2.4.5.6 Delete删除磁盘



  • 今天讨论 cinder 怎样删除 volume ,状态为 Available 的 volume 才气够被 delete,如果 volume 当前已经 attach 到 instance,必要先 detach 后才气 delete。
  • Delete操作实现比较简单,流程图如下:1)向 cinder-api 发送delete 请求;2)cinder-api 发送消息;3)cinder-volume 执行 delete 操作。

    1)向 cinder-api 发送 delete 请求:
    客户(可以是 OpenStack 最终用户,也可以是其他步伐)向 cinder-api 发送请求:“请 delete 指定的 volume。这里我们将 delete volume “vol-2”。进入 GUI 操作菜单 Project -> Compute -> Volumes:

    选择volume “vol-2”,点击“Delete Volume”:

    再次确认:

    cinder-api 将接收到 delete volume 的请求。日志文件在 /opt/stack/logs/c-api.log:

    2)cinder-api 发送消息:
    cinder-api 发送消息 delete 消息。cinder-api 没有打印发送消息的日志,只能通过源代码查看。opt/stack/cinder/cinder/volume/api.py,方法为 extend。

    3)cinder-volume delete volume:
    cinder-volume 执行 lvremove 下令 delete volume,日志为 /opt/stack/logs/c-vol.log。

    这里比较有意思的是:cinder-volume 执行的是“安全”删除。所谓“安全”实际上就是将 volume 中的数据抹掉,LVM driver 使用的是 dd 操作将 LV 的数据清零,日志如下:

    然后删除 LV:

2.4.5.7 Snapshot磁盘快照



  • Snapshot 可以为 volume 创建快照,快照中生存了 volume 当前的状态,以后可以通过 snapshot 回溯。
  • snapshot 操作实现比较简单,流程图如下所示:1)向 cinder-api 发送 snapshot 请求;2)cinder-api 发送消息;3)cinder-volume 执行 snapshot 操作。

    1)向 cinder-api 发送 snapshot 请求:
    客户(可以是 OpenStack 最终用户,也可以是其他步伐)向 cinder-api 发送请求:“请 snapshot 指定的 volume。这里我们将 snapshot volume “vol-1”。进入 GUI 操作菜单 Project -> Compute -> Volumes:

    选择 volume “vol-1”,点击 “Create Snapshot”:

    为 snapshot 定名:

    这里我们看到界面提示当前 volume 已经 attach 到某个 instance,创建 snapshot 可能导致数据不同等。我们可以先 pause instance,或者确认当前 instance 没有大量的磁盘 IO,处于相对稳定的状态,则可以创建 snapshot,否则还是建议先 detach volume 再做 sanpshot。
    cinder-api 将接收到 snapshot volume 的请求,日志文件在 /opt/stack/logs/c-api.log:

    2)cinder-api 发送消息:
    cinder-api 发送消息 snapshot 消息。cinder-api 没有打印发送消息的日志,只能通过源代码查看 /opt/stack/cinder/cinder/volume/api.py,方法为 _create_snapshot:

    3)cinder-volume 执行 snapshot 操作:
    cinder-volume 执行 lvcreate 下令创建 snapshot。日志为 /opt/stack/logs/c-vol.log:

    对于 LVM volume provider,snapshot 实际上也是一个 LV,同时纪录了与源 LV 的 snapshot 关系,可以通过 lvdisplay 查看:

    GUI 的 Volume Snapshots 标签中可以看到新创建的 “vol-1-snapshot”:

    有了 snapshot,我们就可以将 volume 回溯到创建 snapshot 时的状态,方法是通过 snapshot 创建新的 volume:

    新创建的 volume 容量必须大于或等于 snapshot 的容量:

    其过程与 Create Volume 类似,不同之处在于 LV 创建之后会通过 dd 将 snapshot 的数据 copy 到新的 volume。如果一个 volume 存在 snapshot,则这个 volume 是无法删除的。这是因为 snapshot 依靠于 volume,snapshot 无法独立存在。 在 LVM 作为 volume provider 的环境中,snapshot 是从源 volume 完全 copy 而来,以是这种依靠关系不强。但在其他 volume provider(好比贸易存储装备或者分布式文件体系),snapshot 通常是源 volume 创建快照时数据状态的一个引用(指针),占用空间非常小,在这种实现方式里 snapshot 对源 volume 的依靠就非常明显了。
2.4.5.8 Backup磁盘备份



  • 本节我们讨论 volume 的 Backup 操作。Backup 是将 volume 备份到别的地方(备份装备),将来可以通过 restore 操作规复。
  • Backup VS Snapshot:
    初看 backup 功能好像与 snapshot 很相似,都可以生存 volume 的当前状态,以备以后规复。但二者在用途和实现上还是有区别的,详细表如今:
    1)Snapshot 依靠于源 volume,不能独立存在;而 backup 不依靠源 volume,即便源 volume 不存在了,也可以 restore。
    2)Snapshot 与源 volume 通常存放在一起,都由同一个 volume provider 管理;而 backup 存放在独立的备份装备中,有自己的备份方案和实现,与 volume provider 没有关系。
    3)上面两点决定了 backup 具有容灾功能;而 snapshot 则提供 volume provider 内便捷的回溯功能。
  • 设置 cinder-backup:
    Cinder 的 backup 功能是由 cinder-backup 服务提供的,devstack 默认没有启用该服务,必要手工启用
    与 cinder-volume 类似,cinder-backup 也通过 driver 架构支持多种备份 backend,包括 POSIX 文件体系、NFS、Ceph、GlusterFS、Swift 和 IBM TSM。支持的driver 源文件放在 /opt/stack/cinder/cinder/backup/drivers/:

  • 本节我们将以 NFS 为 backend 来研究 backup 操作 :
    在实验环境中,存放 volume backup 的 NFS 长途目录为 192.168.104.11:/backup,cinder-backup 服务节点上 mount point 为 /backup_mount。必要在 /etc/cinder/cinder.conf 中作相应设置:

    然后手工启动 cinder-backup 服务:

  • 一切准备停当,下面我们来看 backup 操作的流程:1)向 cinder-api 发送 backup 请求;2)cinder-api 发送消息;3)cinder-backup 执行 backup 操作。

    1)向 cinder-api 发送 backup 请求:
    客户(可以是 OpenStack 最终用户,也可以是其他步伐)向 cinder-api 发送请求:“请 backup 指定的 volume。这里我们将 backup volume “vol-1”,目前 backup 只能在 CLI 中执行,接纳cinder backup-create vol-1 --force下令。

    这里因为 vol-1 已经 attach 到 instance,必要使用 –force 选项。cinder-api 接收到 backup volume 的请求。日志文件在 /opt/stack/logs/c-api.log。

2)cinder-api 发送消息:
cinder-api 发送 backup 消息。cinder-api 没有打印发送消息的日志,只能通过源代码查看
/opt/stack/cinder/cinder/backup/api.py,方法为 create:

3)cinder-backup 执行 backup 操作:
cinder-backup 收到消息后,通过如下步骤完成 backup 操作,日志为 /opt/stack/logs/c-vol.log。
i)启动 backup 操作,mount NFS。

ii)创建 volume 的临时快照。

iii)创建存放 backup 的 container 目录。

iv)对临时快照数据举行压缩,并生存到 container 目录。

v)创建并生存 sha256(加密)文件和 metadata 文件。

vi)删除临时快照。

Backup 完成后,我们可以查看一下 container 目录的内容:内里有三个文件,根据前面的日志我们可以知道:backup-00001,压缩后的 backup 文件。backup_metadata,metadata 文件。backup_sha256file,加密文件。

可以通过 cinder backup-list 查看当前存在的 backup:

另外我们接纳cinder help backup-create下令可以查看一下 cinder backup-create 的用法:

这里有--incremental 选项,表示可以执行增量备份。如果之前做过平凡(全量)备份,之后可以通过增量备份大大淘汰必要备份的数据量,是个很不错的功能。
2.4.5.9 restore磁盘规复



  • 前面我们 backup 了 voluem,今天我们将讨论怎样 restore volume。restore 的过程实在很简单,两步走:1)在存储节点上创建一个空缺 volume。2)将 backup 的数据 copy 到空缺 voluem 上。
  • 下面我们来看 restore 操作的详细流程:1)向 cinder-api 发送 restore 请求;2)cinder-api 发送消息;3)cinder-scheduler 挑选最符合的 cinder-volume;4)cinder-volume 创建空缺 volume;5)cinder-backup 将 backup 数据 copy 到空缺 volume 上。

    1) 向 cinder-api 发送 restore 请求:
    客户(可以是 OpenStack 最终用户,也可以是其他步伐)向 cinder-api 发送请求:“请 restore 指定的 backup”。这里我们将 restore 之前创建的 backup,目前 restore 只能在 CLI 中执行,先接纳cinder backup-list下令查看backup,接纳cinder backup-restore 备份volume的ID下令举行规复:


    cinder-api 接收到 restore 请求,日志文件在 /opt/stack/logs/c-api.log:

    这里看到 cinder-api 转发请求,为 restore 创建 volume。 之后 cinder-scheduler 和 cinder-volume 将创建空缺 volume,这个过程与 create volume 一样,不再赘述。
    2)接下来分析数据规复的过程
    a)首先,在 cinder-api 日志中可以看到相干信息:

    这里注意日志中的 volume_id 和 backup_id 与前面 backup-restore 下令的输出是同等的。
    b)下面来看 cinder-backup 是怎样规复数据的。cinder-backup 执行 restore 操作:日志为 /opt/stack/logs/c-vol.log。
    i)启动 restore 操作,mount NFS。

    ii)读取 container 目录中的 metadata。

    iii)将数据解压并写到 volume 中。

    iv)规复 volume 的 metadata,完成 restore 操作。

    c)此时,在 GUI 中已经可以看到 restore 创建的 volume:

2.4.5.10 Boot From Volume 将Volume作为虚拟机的启动盘



  • Volume 除了可以用作 instance 的数据盘,也可以作为启动盘(Bootable Volume)。
    那么怎样使 volume 成为 bootable 呢?如今我们打开 instance 的 launch 操作界面:

    这里有一个下拉菜单“Instance Boot Source”。以前我们 launch(部署)instance 要么直接从 image launch(Boot from image),要么从 instance 的 snapshot launch(Boot from snapshot)。 这两种 launch 方式下,instance 的启动盘 vda 均为镜像文件,存放路径为计算节点 /opt/stack/data/nova/instances/<Instance ID>/disk,比方:

    下拉列表的后三项则可以将 volume 作为 instance 的启动盘 vda,分别为:
    1)Boot from volume:直接从现有的 bootable volume launch;
    2)Boot from image (create a new volume):创建一个新的 volume,将 image 的数据 copy 到 volume,然后从该 volume launch;
    3)Boot from volume snapshot (create a new volume):通过指定的 volume snapshot 创建 volume,然后从该 volume launch,当然条件是该snapshot 对应的源 volume 是 bootable 的。
    下面我们以 Boot from image (create a new volume)为例,看怎样从 volume 启动:

    选择 cirros 作为 image,instance 定名为“c3” ,如果希望 terminate instance 的时候同时删除 volume,可以勾选“Delete on Terminate”。
    c3 成功 Launch 后,volume 列表中可以看到一个新 bootable volume,以 volume ID 定名,而且已经 attach 到 c3。

    该 volume 已经设置为 c3 的启动盘 vda:

    如果用该 volume 创建 snapshot,之后就可以通过 Boot from volume snapshot (create a new volume) 部署新的instance。boot from volume 的 instance 也可以执行 live migrate。前面的实验使用的是 LVM provider,cinder 当然也支持其他 provider。
2.4.5.11 NFS Volume Provider



  • cinder-volume 支持多种 volume provider,前面我们不停使用的是默认的 LVM,本节我们将增加 NFS volume provider。固然 NFS 更多地应用在实验或小规模 cinder 环境,由于性能和缺乏高可用的原因在生产环境中不太可能使用。
  • 但是学习 NFS volume provider 的意义在于:
    1)理解 cinder-volume 怎样支持多 backend;
    2)更紧张的,可以理解 cinder-volume,nova-compute 和 volume provider 是怎样协同工作,共同为 instance 提供块存储;
    3)举一反三,能够快速理解并接入其他生产级 backend ,好比 Ceph,贸易存储等。
  • 下图展示了 cinder、nova 是怎样与 NFS volume provider 和谐工作的:

    1)NFS Volume Provider:就是我们通常说的 NFS Server,提供长途 NFS 目录,NFS Clinet 可以 mount 这些长途目录到本地,然后像使用本地目录一样创建、读写文件以及子目录。
    2)cinder-volume:存储节点通过 NFS driver 管理 NFS volume provider 中的 volume,这些 volume 在 NFS 中实际上是一个个文件。
    3)nova-compute:计算节点将 NFS volume provider 存放 volume 的目录 mount 到本地,然后将 volume 文件作为虚拟硬盘映射给 instance。
  • 这里有几点必要夸大
    1)在 Cinder 的 driver 架构中,运行 cinder-volume 的存储节点和 Volume Provider 可以是完全独立的两个实体。cinder-volume 通过 driver 与 Volume Provider 通讯,控制和管理 volume。
    2)Instance 读写 volume 时,数据流不必要经过存储节点,而是直接对 Volume Provider 中的 volume 举行读写。 正如上图所示,存储节点与 NFS Volume Provider 的毗连只用作 volume 的管理和控制(绿色连线);真正的数据读写,是通过计算节点和 NFS Volume Proiver 之间的毗连完成的(紫色连线)。这种计划淘汰了中间环节,存储节点不直接参与数据传输,保证了读写服从。
    3)其他 Volume Provider(比方 ceph,swift,贸易存储等)均遵循这种控制流与数据流分离的计划。
  • 设置 NFS Volume Provider:
    在实验环境中,NFS volume provider 的 NFS 长途目录为 192.168.104.11:/storage,cinder-volume 服务节点上 mount point 为 /nfs_storage。在 /etc/cinder/cinder.conf 中添加 nfs backend:

    设置enabled_backends = lvmdriver-1,nfs是 让 cinder-volume 使用 nfs backend。[nfs]中详细设置 nfs backend。包括:
    a) 使用nfs_mount_point_base = /nfs_storage下令,指定存储节点上 /nfs_storage 为 nfs 的 mount point。

    b) 查看 /etc/cinder/nfs_shares 活动 nfs 共享目录列表。 nfs_shares_config = /etc/cinder/nfs_shares,其内容为:

    列表中只有 192.168.104.11:/storage。如果希望有多个 nfs 共享目录存放 volume,则可以添加到该文件中。
    c) nfs volume driver。
    volume_driver=cinder.volume.drivers.nfs.NfsDriver

    d) 设置 volume backend name。在 cinder 中必要根据这里的 volume_backend_name 创建对应的 volume type,这个非常紧张,volume_backend_name = nfs。
  • 重启 cinder-volume,cinder service-list 确认 nfs cinder-volume 服务正常工作:

  • 创建 nfs volume type
    打开GUI页面Admin -> System -> Volumes -> Volume Types,点击 “Create Volume Type”:

    定名 nfs,点击“Create Volume Type”:

    选择 nfs volume type,点击下拉菜单“View Extra Specs”:

    点击“Create”,Key 输入 volume_backend_name ;Value 输入 nfs:


    NFS volume provider 准备停当,下一节我们将创建 NFS 为 backend 的 volume。
  • 创建volume
    1)创建 NFS volume 操作方法与 LVM volume 一样,唯一区别是在 volume type 的下拉列表中选择“nfs”:

    点击“Create Volume”,cinder-api,cinder-scheduler 和 cinder-volume 共同协作创建 volume “nfs-vol-1”。这个流程与 LVM volume 一样。
    2)分析 cinder-volume 的日志:
    看看 NFS volume provider 是怎样创建 volume 的,日志在 /opt/stack/logs/c-vol.log。
    i)cinder-volume 也会启动 Flow 来完成 volume 创建工作,Flow 的名称为 volume_create_manager:

    volume_create_manager 首先执行 ExtractVolumeRefTask, OnFailureRescheduleTask, ExtractVolumeSpecTask, NotifyVolumeActionTask 为 volume创建做准备。
    ii)然后由 CreateVolumeFromSpecTask 真正创建 volume:

    iii)首先 mount 长途 NFS 目录:

    iv)执行 stat、du 下令检查 NFS 目录:

    v)执行 truncate 创建 volume 文件:

    vi)接纳chmod ugo+rw下令设置 volume 文件为可读写:

    vii)create 操作完成:

    viii)Volume 在 NFS 上以文件存在,定名为“volume-”:

    ix)GUI volume 列表中可以看到新创建的 volume:

    GUI volume 列表中可以看到新创建的 volume。
  • nova-compute 怎样将“nfs-vol-1” attach 到“c2” :
    通过日志分析,nova-compute 会将存放 volume 文件的 NFS 目录 mount 到本地 /opt/stack/data/nova/mnt 目录下,然后修改 instance 的 XML 将 volume 文件设置为虚拟磁盘,日志为 /opt/stack/logs/n-cpu.log。
    1)通过 findmnt 和 mkdir 测试和创建 mount point:

    2)mount NFS 目录:

    3)更新 instance 的XML,将 volume 文件映射给 instance:

    4)我们也可以通过 virsh edit 查看更新后的XML:

    5)GUI 界面也会更新相干 attach 信息:

2.5 网络服务Neutron


2.5.1 Neutron概述

2.5.1.1 Neutron功能



  • 二层交换 Switching
    1)Nova 的 Instance 是通过虚拟交换机毗连到虚拟二层网络的。
    2)Neutron 支持多种虚拟交换机,包括 Linux 原生的 Linux Bridge 和 Open vSwitch。Open vSwitch(OVS)是一个开源的虚拟交换机,它支持标准的管理接口和协议。
    3)利用 Linux Bridge 和 OVS,Neutron 除了可以创建传统的 VLAN 网络,还可以创建基于隧道技术的 Overlay 网络,好比 VxLAN 和 GRE(Linux Bridge 目前只支持 VxLAN)。
  • 三层路由 Routing
    1)Instance 可以设置不同网段的 IP,Neutron 的 router(虚拟路由器)实现 instance 跨网段通讯。
    2)router 通过 IP forwarding,iptables 等技术来实现路由和 NAT。(IP forwarding是IP转发,一种路由协议。IP转发是操作体系的一种选项,支持主机起到路由器的功能。在一个体系中含有两块以上的网卡,并将IP转发选项打开,如许该体系就可以作为路由器举利用用了)。
  • 负载均衡 Load Balancing
    1)Openstack 在 Grizzly 版本第一次引入了 Load-Balancing-as-a-Service(LBaaS),提供了将负载分发到多个 instance 的本事。LBaaS 支持多种负载均衡产物和方案,不同的实现以 Plugin(插件) 的情势集成到 Neutron,目前默认的 Plugin 是 HAProxy。
  • 防火墙 Firewalling
    Neutron 通过下面两种方式来保障 instance 和网络的安全性。
    1)Security Group:通过 iptables 限定进出 instance 的网络包。
    2)Firewall-as-a-Service:FWaaS,限定进出虚拟路由器的网络包,通过 iptables 实现。
2.5.1.2 Neutron网络基本概念



  • network :
    network 是一个隔离的二层广播域。Neutron 支持多种类型的 network,包括 local, flat, VLAN, VxLAN 和 GRE。
    1)local
    local 网络与其他网络和节点隔离。local 网络中的 instance 只能与位于同一节点上同一网络的 instance 通讯,local 网络主要用于单机测试。
    2)flat
    flat 网络是无 vlan tagging 的网络。flat 网络中的 instance 能与位于同一网络的 instance 通讯,而且可以跨多个节点。
    3)vlan
    vlan 网络是具有 802.1q tagging 的网络。vlan 是一个二层的广播域,同一 vlan 中的 instance 可以通讯,不同 vlan 只能通过 router 通讯。vlan 网络可以跨节点,是应用最广泛的网络类型。
    4)vxlan
    vxlan 是基于隧道技术的 overlay 网络。vxlan 网络通过唯一的 segmentation ID(也叫 VNI)与其他 vxlan 网络区分。vxlan 中数据包会通过 VNI 封装成 UDP 包举行传输。因为二层的包通过封装在三层传输,能够克服 vlan 和物理网络基础设施的限定。
    5)gre
    gre 是与 vxlan 类似的一种 overlay 网络。主要区别在于使用 IP 包而非 UDP 举行封装。
    6)不同 network 之间在二层上是隔离的
    以 vlan 网络为例,network A 和 network B 会分配不同的 VLAN ID,如许就保证了 network A 中的广播包不会跑到 network B 中。当然,这里的隔离是指二层上的隔离,借助路由器不同 network 是可能在三层上通讯的。network 必须属于某个 Project( Tenant 租户),Project 中可以创建多个 network。 network 与 Project 之间是 1对多 关系。
  • subnet:
    subnet 是一个 IPv4 或者 IPv6 地址段。instance 的 IP 从 subnet 中分配。每个 subnet 必要定义 IP 地址的范围和掩码。subnet 与 network 是 1对多 关系。一个 subnet 只能属于某个 network;一个 network 可以有多个 subnet,这些 subnet 可以是不同的 IP 段,但不能重叠。
    下面的设置是有用的:

    但下面的设置则无效,因为 subnet 有重叠:

    这里不是判定 IP 是否有重叠,而是 subnet 的 CIDR 重叠(都是 10.10.1.0/24)。
    但是,如果 subnet 在不同的 network 中,CIDR 和 IP 都是可以重叠的,好比:

    这里各人不免会疑惑: 如果上面的IP地址是可以重叠的,那么就可能存在具有相同 IP 的两个 instance,如许会不会冲突? 简单的回答是:不会!详细原因: 因为 Neutron 的 router 是通过 Linux network namespace 实现的。network namespace 是一种网络的隔离机制。通过它,每个 router 有自己独立的路由表。
    上面的设置有两种结果:
    1)如果两个 subnet 是通过同一个 router 路由,根据 router 的设置,只有指定的一个 subnet 可被路由。
    2)如果上面的两个 subnet 是通过不同 router 路由,因为 router 的路由表是独立的,以是两个 subnet 都可以被路由。
  • port:
    1)port 可以看做虚拟交换机上的一个端口。port 上定义了 MAC 地址和 IP 地址,当 instance 的虚拟网卡 VIF(Virtual Interface)绑定到 port 时,port 会将 MAC 和 IP 分配给 VIF。
    2)port 与 subnet 是 1对多 关系。一个 port 必须属于某个 subnet;一个 subnet 可以有多个 port。
  • 小节
    下面总结了 Project,Network,Subnet,Port 和 VIF 之间关系。Project 1 : m Network 1 : m Subnet 1 : m Port 1 : 1 VIF m : 1 Instance,即一个租户有多个网络,一个网络有多个子网,一个子网有多个端口,一个端口有一个虚拟网卡,一个虚拟机有多个虚拟网卡。
2.5.2 Neutron架构

2.5.2.1 Neutron组件概括



  • 与 OpenStack 的其他服务的计划思路一样,Neutron 也是接纳分布式架构,由多个组件(子服务)共同对外提供网络服务。

  • Neutron由如下组件构成:
    1)Neutron Server:对外提供 OpenStack 网络 API,接收请求,并调用 Plugin 处理请求。
    2)Plugin:处理 Neutron Server 发来的请求,维护 OpenStack 逻辑网络的状态, 并调用 Agent 处理请求。
    3)Agent:处理 Plugin 的请求,负责在 network provider 上真正实现各种网络功能。
    4)network provider:提供网络服务的虚拟或物理网络装备,比方 Linux Bridge,Open vSwitch 或者其他支持 Neutron 的物理交换机。
    5)Queue:Neutron Server,Plugin 和 Agent 之间通过 Messaging Queue 通讯和调用。
    6)Database:存放 OpenStack 的网络状态信息,包括 Network, Subnet, Port, Router 等。

  • 以创建一个 VLAN100 的 network 为例,假设 network provider 是 linux bridge, 流程如下:
    1)Neutron Server 接收到创建 network 的请求,通过 Message Queue(RabbitMQ)通知已注册的 Linux Bridge Plugin。
    2)Plugin 将要创建的 network 的信息(比方名称、VLAN ID等)生存到数据库中,并通过 Message Queue 通知运行在各节点上的 Agent。
    3)Agent 收到消息后会在节点上的物理网卡(好比 eth2)上创建 VLAN 装备(好比 eth2.100),并创建 bridge (好比 brqXXX) 桥接 VLAN 装备。
  • 这里举行几点说明:
    1)plugin 解决的是 What 的题目,即网络要设置成什么样子?而至于怎样设置 How 的工作则交由 agent 完成。
    2)plugin,agent 和 network provider 是配套使用的,好比上例中 network provider 是 linux bridge,那么就得使用 linux bridge 的 plungin 和 agent;如果 network provider 换成了 OVS 或者物理交换机,plugin 和 agent 也得更换。
    3)plugin 的一个主要的职责是在数据库中维护 Neutron 网络的状态信息,这就造成一个题目:所有 network provider 的 plugin 都要编写一套非常类似的数据库访问代码。为相识决这个题目,Neutron 在 Havana 版本实现了一个 ML2(Modular Layer 2)plugin,对 plgin 的功能举行抽象和封装。有了 ML2 plugin,各种 network provider 无需开发自己的 plugin,只必要针对 ML2 开发相应的 driver 就可以了,工作量和难度都大大淘汰。ML2 会在后面详细讨论。
    4)plugin 按照功能分为两类: core plugin 和 service plugin。core plugin 维护 Neutron 的 netowrk, subnet 和 port 相干资源的信息,与 core plugin 对应的 agent 包括 linux bridge, OVS 等; service plugin 提供 routing, firewall, load balance 等服务,也有相应的 agent。
2.5.2.2 Neutron物理部署方案



  • 方案1:控制节点 + 计算节点:
    1)控制节点:部署的服务包括:neutron server, core plugin 的 agent 和 service plugin 的 agent。
    2)计算节点:部署 core plugin 的agent,负责提供二层网络功能。
    NOTE:这里有几点必要说明:
    1)core plugin 和 service plugin 已经集成到 neutron server,不必要运行独立的 plugin 服务。
    2)控制节点和计算节点都必要部署 core plugin 的 agent,因为通过该 agent 控制节点与计算节点才气建立二层毗连。
    3)可以部署多个控制节点和计算节点。

  • 方案1:控制节点 +网络节点+ 计算节点:
    1)控制节点:部署 neutron server 服务。
    2)网络节点:部署的服务包括:core plugin 的 agent 和 service plugin 的 agent。
    3)计算节点:部署 core plugin 的agent,负责提供二层网络功能。
    这个方案的要点是将所有的 agent 从控制节点分离出来,部署到独立的网络节点上。控制节点只负责通过 neutron server 响应 API 请求。由独立的网络节点实现数据的交换,路由以及 load balance等高级网络服务。可以通过增加网络节点承担更大的负载。可以部署多个控制节点、网络节点和计算节点。该方案特别适合规模较大的 OpenStack 环境。

2.5.3 Neutron组件详细说明

2.5.3.1 Neutron Server



  • 下图是 Neutron Server 的分层布局,至上而下依次为:

    1)Core API:对外提供管理 network, subnet 和 port 的 RESTful API。
    2)Extension API:对外提供管理 router, load balance, firewall 等资源 的 RESTful API。
    3)Commnon Service:认证和校验 API 请求。
    4)Neutron Core:Neutron server 的焦点处理步伐,通过调用相应的 Plugin 处理请求。
    5)Core Plugin API:定义了 Core Plgin 的抽象功能聚集,Neutron Core 通过该 API 调用相应的 Core Plgin。
    6)Extension Plugin API:定义了 Service Plgin 的抽象功能聚集,Neutron Core 通过该 API 调用相应的 Service Plgin。
    7)Core Plugin:实现了 Core Plugin API,在数据库中维护 network, subnet 和 port 的状态,并负责调用相应的 agent 在 network provider 上执行相干操作,好比创建 network。
    8)Service Plugin:实现了 Extension Plugin API,在数据库中维护 router, load balance, security group 等资源的状态,
    并负责调用相应的 agent 在 network provider 上执行相干操作,好比创建 router。
  • 归纳起来,Neutron Server 包括两部分:1)提供 API 服务。2)运行 Plugin。
    即 Neutron Server = API + Plugins

2.5.3.2 Neutron怎样支持多种network provider



  • 根据我们上一节讨论的 Neutron Server 的分层模子,我们必要实现两个东西:linux bridge core plugin 和 linux bridge agent。
  • linux bridge core plugin
    1)与 neutron server 一起运行。
    2)实现了 core plugin API。
    3)负责维护数据库信息。
    4)通知 linux bridge agent 实现详细的网络功能。
  • linux bridge agent
    1)在计算节点和网络节点(或控制节点)上运行。
    2)接收来自 plugin 的请求。
    3)通过设置本节点上的 linux bridge 实现 neutron 网络功能。

  • 同样的道理,如果要支持 open vswitch,只必要实现 open vswitch plugin 和 open vswitch agent

  • 由此可见:Neutron 可以通过开发不同的 plugin 和 agent 支持不同的网络技术。这是一种相当开放的架构。不过随着支持的 network provider 数量的增加,开发人员发现了两个突出的题目:只能在 OpenStack 中使用一种 core plugin,多种 network provider 无法共存。不同 plugin 之间存在大量重复代码,开发新的 plugin 工作量大。
2.5.3.3 ML2 Core Plugin



  • Moduler Layer 2(ML2)是 Neutron 在 Havana 版本实现的一个新的 core plugin,用于替代原有的 linux bridge plugin 和 open vswitch plugin。
  • ML2 能解决传统 core plugin 的题目。ML2 作为新一代的 core plugin,提供了一个框架,允许在 OpenStack 网络中同时使用多种 Layer 2 网络技术,不同的节点可以使用不同的网络实现机制。

    如上图所示,接纳 ML2 plugin 后,可以在不同节点上分别部署 linux bridge agent, open vswitch agent, hyper-v agent 以及其他第三方 agent。(Hyper-V 是 Microsoft 的硬件虚拟化产物。 它用于创建并运行虚拟机。 每个虚拟机都像一台完备的计算机一样运行操作体系和步伐。)
  • ML2 不光支持异构部署方案,同时能够与现有的 agent 无缝集成:以前用的 agent 不必要变,只必要将 Neutron server 上的传统 core plugin 更换为 ML2。有了 ML2,要支持新的 network provider 就变得简单多了:无需重新开发 core plugin,只必要开发相应的 mechanism driver,大大淘汰了要编写和维护的代码。
  • ML2 对二层网络举行抽象和建模,引入了 type driver 和 mechanism driver。这两类 driver 解耦了 Neutron 所支持的网络类型(type)与访问这些网络类型的机制(mechanism),其结果就是使得 ML2 具有非常好的弹性,易于扩展,能够机动支持多种 type 和 mechanism。

  • Type Driver:Neutron 支持的每一种网络类型都有一个对应的 ML2 type driver。type driver 负责维护网络类型的状态,执行验证,创建网络等。ML2 支持的网络类型包括 local, flat, vlan, vxlan 和 gre。
  • Mechanism Driver:Neutron 支持的每一种网络机制都有一个对应的 ML2 mechanism driver。mechanism driver 负责获取由 type driver 维护的网络状态,并确保在相应的网络装备(物理或虚拟)上正确实现这些状态。
  • type 和 mechanisim 都太抽象,如今我们举一个详细的例子:type driver 为 vlan,mechanism driver 为 linux bridge,我们要完成的操作是创建 network vlan100,那么:vlan type driver 会确保将 vlan100 的信息生存到 Neutron 数据库中,包括 network 的名称,vlan ID 等。linux bridge mechanism driver 会确保各节点上的 linux brige agent 在物理网卡上创建 ID 为 100 的 vlan 装备 和 brige 装备,并将两者举行桥接。
  • mechanism driver 有三种类型
    1)Agent-based:包括 linux bridge, open vswitch 等。
    2)Controller-based:包括 OpenDaylight, VMWare NSX 等。
    3)基于物理交换机:包括 Cisco Nexus, Arista, Mellanox 等。
    好比前面那个例子如果换成 Cisco 的 mechanism driver,则会在 Cisco 物理交换机的指定 trunk 端口上添加 vlan100。
  • linux bridge 和 open vswitch 的 ML2 mechanism driver 的作用是设置各节点上的虚拟交换机。linux bridge driver 支持的 type 包括 local, flat, vlan, and vxlan。open vswitch driver 除了这 4 种 type 还支持 gre。L2 population driver 作用是优化和限定 overlay 网络中的广播流量。vxlan 和 gre 都属于 overlay 网络。
2.5.3.4 Service Plugin/Agent



  • Core Plugin/Agent 负责管理焦点实体:net, subnet 和 port。而对于更高级的网络服务,则由 Service Plugin/Agent 管理。
    Service Plugin 及其 Agent 提供更丰富的扩展功能,包括路由,load balance,firewall等。
  • Neutron架构如图所示:

    1)DHCP:dhcp agent 通过 dnsmasq 为 instance 提供 dhcp 服务。
    2)Routing:l3 agent 可以为 project(租户)创建 router,提供 Neutron subnet 之间的路由服务。路由功能默认通过 IPtables 实现。
    3)Firewall:l3 agent 可以在 router 上设置防火墙计谋,提供网络安全防护。
    另一个与安全相干的功能是 Security Group,也是通过 IPtables 实现。Firewall 与 Security Group 的区别在于:Firewall 安全计谋位于 router,保护的是某个 project 的所有 network。Security Group 安全计谋位于 instance,保护的是单个 instance。
    4)Load Balance:Neutron 默认通过 HAProxy 为 project 中的多个 instance 提供 load balance 服务。
2.5.3.5 小结




  • 与 OpenStack 其他服务一样,Neutron 接纳的是分布式架构,包括 Neutorn Server、各种 plugin/agent、database 和 message queue。
    1)Neutron server 接收 api 请求。
    2)plugin/agent 实现请求。
    3)database 生存 neutron 网络状态。
    4)message queue 实现组件之间通讯。
  • metadata-agent 之前没有讲到,这里做个增补:
    instance 在启动时必要访问 nova-metadata-api 服务获取 metadata 和 userdata,这些 data 是该 instance 的定制化信息,好比 hostname, ip, public key 等。但 instance 启动时并没有 ip,怎样能够通过网络访问到 nova-metadata-api 服务呢?
    答案就是 neutron-metadata-agent。该 agent 让 instance 能够通过 dhcp-agent 或者 l3-agent 与 nova-metadata-api 通讯
  • 如果我们将 Neutron 架构展开,则会得到下面第二张图:

    1)Neutron 通过 plugin 和 agent 提供的网络服务。
    2)plugin 位于 Neutron server,包括 core plugin 和 service plugin。
    3)agent 位于各个节点,负责实现网络服务。
    4)core plugin 提供 L2 功能,ML2 是推荐的 plugin。
    5)使用最广泛的 L2 agent 是 linux bridage 和 open vswitch。
    6)service plugin 和 agent 提供扩展功能,包括 dhcp, routing, load balance, firewall, vpn 等。
2.5.4 为Neutron准备底层基础设施



  • 1个控制节点 +1个计算节点的部署方案:控制节点合并了网络节点的功能,同时也是一个计算节点 。

  • 设置多个网卡区分不同类型的网络数据:Management、API、VM、External。
    1)Management 网络
    用于节点之间 message queue 内部通讯以及访问 database 服务,所有的节点都必要毗连到 management 网络。
    2)API 网络
    OpenStack 各组件通过该网络向用户暴露 API 服务。Keystone, Nova, Neutron, Glance, Cinder, Horizon 的 endpoints 均设置在 API 网络上。通常,管理员也通过 API 网络 SSH 管理各个节点。
    3)VM 网络
    VM 网络也叫 tenant 网络,用于 instance 之间通讯。 VM 网络可以选择的类型包括 local, flat, vlan, vxlan 和 gre。 VM 网络由 Neutron 设置和管理。
    4)External网络
    External 网络指的是 VM 网络之外的网络,该网络不由 Neutron 管理。 Neutron 可以将 router attach 到 External 网络,为 instance 提供访问外部网络的本事。 External 网络可能是企业的 intranet,也可能是 internet。
  • 我们可以为每种网络分配单独的网卡; 也可以多种网络共同使用一个网卡;为提高带宽和硬件冗余,可以使用 bonding 技术将多个物理网卡绑定成一个逻辑的网卡,我们的实验环境接纳下面的网卡分配方式:

  • 网络拓扑:(节点安装设置参考:https://www.xjimmy.com/openstack-5min-76.html)

2.5.5 Linux Bridge实现Neutron网络


2.5.5.1 设置 Linux-Bridge Mechanism Driver



  • 下图中,br0 是 linux bridge,br0 充当虚拟交换机的作用,负责将物理网卡 eth0 和虚拟网卡 tap 装备 vnet0/vent1 毗连到同一个二层网络,实现虚拟机 VM1 和 VM2,以及虚拟机与外网之间的通讯。

  • 设置linux-bridge mechanism driver
    1)要在 Neutron 中使用 linux bridge,首先必要设置 linux-bridge mechanism driver:
    Neutron 默认使用 ML2 作为 core plugin,其设置位于 /etc/neutron/neutron.conf。控制节点和计算节点都必要在各自的 neutron.conf 中设置 core_plugin 选项。

    2)然后必要让 ML2 使用 linux-bridge mechanism driver:
    ML2 的设置文件位于 /etc/neutron/plugins/ml2/ml2_conf.ini。

    mechanism_drivers 选项指明当前节点可以使用的 mechanism driver,这里可以指定多种 driver,ML2 会负责加载。上面的设置指明我们只使用 linux-bridge driver。控制节点和计算节点都必要在各自的 ml2_conf.ini 中设置 mechanism_drivers 选项。
    3)Neutron 服务正常启动后,所有节点上都会运行 neutron-linuxbridge-agent:

2.5.5.2 初始网络状态



  • 控制节点:


  • 计算节点:


  • 在 linux bridge 环境中,一个数据包从 instance 发送到物理网卡会经过下面几个类型的装备:
    1)tap interface:定名为 tapN (N 为 0, 1, 2, 3……)。
    2)linux bridge:定名为 brqXXXX。
    3)vlan interface:定名为 ethX.Y(X 为 interface 的序号,Y 为 vlan id)。
    4)vxlan interface:定名为 vxlan-Z(z 是 VNI)。
    5)物理 interface:定名为 ethX(X 为 interface 的序号)。
    linux-bridge 支持 local, flat, vlan 和 vxlan 四种 network type,目前不支持 gre。
2.5.5.3 local network



  • local 网络与其他网络和节点隔离。local 网络中的 instance 只能与位于同一节点上同一网络的 instance 通讯,local 网络主要用于单机测试。
  • local network 的特点是不会与宿主机的任何物理网卡相连,也不关联任何的 VLAN ID。对于每个 local netwrok,ML2 linux-bridge 会创建一个 bridge,instance 的 tap 装备会毗连到 bridge。位于同一个 local network 的 instance 会毗连到相同的 bridge,如许 instance 之间就可以通讯了。因为 bridge 没有与物理网卡毗连,以是 instance 无法与宿主机之外的网络通讯。同时因为每个 local network 有自己的 bridge,bridge 之间是没有连通的,以是两个 local network 之间也不能通讯,即使它们位于同一宿主机上。
  • 下图是 local network 的示例:

    1)创建了两个 local network,分别对应两个网桥 brqXXXX 和 brqYYYY。
    2)VM0 和 VM1 通过 tap0 和 tap1 毗连到 brqXXXX。
    3)VM2 通过 tap2 毗连到 brqYYYY。
    4)VM0 与 VM1 在同一个 local network中,它们之间可以通讯。
    5)VM2 位于另一个 local network,由于 brqXXXX 和 brqYYYY 没有联通,以是 VM2 无法与 VM0 和 VM1 通讯。
  • 在 ML2 设置中 enable local network:
    1)创建 local 网络之前请先确保 ML2 已经加载了 local type driver,ML2 的设置文件位于 /etc/neutron/plugins/ml2/ml2_conf.ini:

    2)type_drivers 告诉 ML2 加载所有 5 种网络的 type driver。

    3)平凡用户和 admin 都可以通过 CLI 或者 Web GUI 创建网络,但只有 amdin 才气指定网络的 type,以是必要用 tenant_network_types 告诉 ML2 当平凡用户在自己的 Tenant(Project)中创建网络时,默认创建哪种 type 的网络,这里 type 是 local。tenant_network_types 可以指定多种 type,好比:

    4)其作用是先创建 vlan 网络,当没有 vlan 可创建时(好比 vlan id 用完),便创建 local 网络。当设置文件发生了变化,必要重启 Neutron 相干服务使之生效。
  • 创建第一个 Local Network:
    1)首先确保各个节点上的 neutorn agent 状态正常。GUI 菜单 为 Admin -> System -> System Infomation -> Neutron Agents:

    2)GUI 中有两个地方可以创建 network :1)Project -> Network -> Networks这是平凡用户在自己的 tenant 中创建 network 的地方。2)Admin -> Networks 这是 admin 创建 network 的地方。我们先用第一种方式创建,点击 “Create Network” 按钮:

    3)在创建网络的向导页面给 network 定名为 “first_local_net”,点击 “Next”:

    4)创建 subnet,定名为 “subnet_172_16_1_0”,地址为 “172.16.1.0/24”,点击 “Next”。如果 Gateway IP 不设置,默认为 subnet 的第一个 IP,即 172.16.1.1:

    5)设置 subnet 的 IP 地址范围为 172.16.1.2-172.16.1.100,instance 的 IP 会从这里分配,点击 “Create”。默认会“Enable DHCP”,同时还可以设置 subnet 的 DNS 和添加静态路由条目。

    6)network 创建成功:

    7)点击 “first_local_net” 链接,显示 network 的 subnet 和 port 信息:

    8)在 Ports 列表中已经创建了一个 port,名称为 “(a5bd3746-3f89)”,IP 为 172.16.1.2, Attached Device 是 network:dhcp。打开控制节点的 shell 终端,用 brctl show 查看当前 linux bridge 的状态:

    9)可以看到 Neutron 自动创建了如下两个装备:
    brqbb9b6d21-c6 对应 local network “first_local_net”,定名规则为 brqXXX,XXX 为 network ID 的前 11 个字符。tapa5bd3746-3f 对应 port (a5bd3746-3f89),定名规则为 tapYYY, YYY 为 port ID 的前 11 个字符。该 tap 装备已经毗连到 bridge,即毗连到该 local 网络。
  • 将 instance 毗连到 first_local_net:
    1)launch 一个 instance,在“Networking”标签页面选择 first_local_net 网络:

    2)instance 部署成功,分配的 IP 地址为 172.16.1.3:

    3)对于 instance “cirros-vm1”,Neutron 会在 subnet 中创建一个 port,分配 IP 和 MAC 地址,并将 port 分配给 cirros-vm1:

    4)如上图所示,port 列表中增加了一个 port “(fa7e090e-a29c)”,IP 为 172.16.1.3。点击 port 名称查看 MAC 信息:

    5)当 cirros-vm1 启动时,宿主机上的 neutron-linuxbridge-agent 会根据 port 信息创建 tap 装备,并毗连到 local 网络地点的 bridge;同时该 tap 会映射成 cirros-vm1 的虚拟网卡,即 virtual interface (VIF)。cirros-vm1 部署到了控制节点,通过 brctl show 查看 bridge 的设置:

    6)可以看到 bridge brqbb9b6d21-c6 上毗连了一个新的 tap 装备 tapfa7e090e-a2 从定名上可知 tapfa7e090e-a2 对应着 port “(fa7e090e-a29c)”。virsh list 中显示的虚拟机 instance-00000001 即为 “cirros-vm1”,定名方式有所不同,需注意。通过 virsh edit 下令查看 cirros-vm1 的设置,确认 VIF 就是 tapfa7e090e-a2:

    7)另外,VIF 的 MAC 地址为 fa:16:3e:c1:66:a5,这个数据就是从 port “(fa7e090e-a29c)” 取过来的。在 cirros-vm1 中执行 ifconfig,通过 MAC 地址可以确认 eth0 与 tapfa7e090e-a2 对应。

    8)下图展示了创建 cirros-vm1 后宿主机当前的网络布局 :

  • 毗连第二个 Insance 到 First_local_net:
    1)以同样的方式 launch instance “cirros-vm2”分配的 IP 为 172.16.1.4:

    2)cirros-vm2 也被 schedule 到控制节点。virsh list 和 brctl show 输出如下 cirros-vm2 对于的 tap 装备为 tapa5bd3746-3f。

    3)在 cirros-vm2 的控制台运行 ifconfig,instance 已经拿到了 DCHP 的 IP 地址:

    4)能够 Ping 通 cirros-vm1 的 IP 地址 172.16.1.3:

    5)前宿主机的网络布局如下 :

    6)两个 instance 的 VIF 挂在同一个 linux bridge 上,可以相互通讯。这里请各人思考一个题目:如果 cirros-vm2 launch 时被 schedule 到计算节点而非控制节点,它能获得 DHCP 的 IP 吗?答案:不能。 因为 DHCP agent 在控制节点上运行,cirros-vm2 在计算节点的 local 网络上,两者位于不同物理节点。由于 local 网络的流量只能局限在本节点之内,发送的 DHCP 请求无法到达控制节点。
  • 创建第二个 Local Network:
    1)GUI 中有两个地方可以创建 network:Project -> Network -> Networks这是平凡用户在自己的 tenant 中创建 network 的地方、Admin -> Networks 这是 admin 创建 network 的地方。前面我们已经用第一种方式创建了 “first_local_net”。本节将以第二种方式创建 local network “second_local_net” 。菜单路径为 Admin -> Networks,此菜单只有 admin 用户才气够访问,点击 “Create Network” 按钮:

    2)显示创建页面,点击 “Create Network”,second_local_net 创建成功:

    3)可以看到几个与平凡用户创建 network 不同的地方:
    a)可以选择该 network 属于哪个 Project(租户)。
    b)可以选择 network type。
    c)可以指定 network 是否与其他 Project 共享。
    d)可以指定是否为 external network。
    可见,这种方式赋予 admin 用户创建 network 更大的机动性,后面我们都将接纳这种方式创建 network。
    4)点击 second_local_net 链接,进入 network 设置页面:

    5)目前还没有 subnet,点击 “Create Subnet” 按钮:

    6)设置 IP 地址为 “172.16.1.0/24”,点击 “Next”:

    7)设置 IP 地址范围为 172.16.1.101-172.16.1.200,点击 “Create”:

    8)subnet 创建成功:

    9)查看控制节点的网络布局。增加了 second_local_net 对应的网桥 brq161e0b25-58,以及 dhcp 的 tap 装备 tapae547b6b-2a:

  • 将 Instance 毗连到 Second_local_net:
    1)launch 新的 instance “cirros-vm3”,网络选择 second_local_net:

    2)cirros-vm3 分配到的 IP 为 172.16.1.102:

    3)cirros-vm3 被 schedule 到控制节点,对应的 tap 装备为 tap5395d19b-ed:

    4)控制台显示 cirros-vm3 已经成功从 DHCP 拿到 IP 地址 172.16.1.102:

    5)但是 cirros-vm3 无法 Ping 到 cirros-vm1:

    6)这是在预料之中的,因为 cirros-vm3 和 cirros-vm1 位于不同的 local network,之间没有连通,即使都位于同一个宿主机也不能通讯。网络布局如下:

    小结:位于同一 local network 的 instance 可以通讯; 位于不同 local network 的 instance 无法通讯;一个 local network 只能位于一个物理节点,无法跨节点。
2.5.5.4 flat network



  • flat network 是不带 tag 的网络,要求宿主机的物理网卡直接与 linux bridge 毗连,这意味着:每个 flat network 都会独占一个物理网卡。
  • 下图中 eth1 桥接到 brqXXX,为 instance 提供 flat 网络。

  • 如果必要创建多个 flat network,就得准备多个物理网卡,如下图所示:

  • Flat Network 原理与设置:
    1)在 ML2 设置中 enable flat network,在 /etc/neutron/plugins/ml2/ml2_conf.ini 设置 flat network 相干参数:

    指定平凡用户创建的网络类型为 flat。 必要注意的是:因为 flat 网络与物理网卡一一对应,一般环境下租户网络不会接纳 flat,这里只是示例。
    2)接着必要指明 flat 网络与物理网卡的对应关系:


    如上所示:a)在 [ml2_type_flat] 中通过 flat_networks 定义了一个 flat 网络,label 为 “default”。b)在 [linux_bridge] 中通过 physical_interface_mappings 指明 default 对应的物理网卡为 eth1。
    3)理解 label 与 ethX 的关系:label 是 flat 网络的标识,在创建 flat 时必要指定 label(后面演示)。label 的名字可以是恣意字符串,只要确保各个节点 ml2_conf.ini 中的 label 定名同等就可以了。各个节点中 label 与物理网卡的对应关系可能不一样。这是因为每个节点可以使用不同的物理网卡将 instance 毗连到 flat network。
    比方对于 label 为 “default” 的 flat network,节点 A 可能使用 eth1,设置为:

    而节点 B 则可能使用 eth2,设置为:

    4)支持多个 flat :如果要创建多个 flat 网络,必要定义多个 label,用逗号隔开,当然也必要用到多个物理网卡,如下所示:

  • 创建 Flat Network:
    1)打开菜单 Admin -> Networks,点击 “Create Network” 按钮:

    2)显示创建页面, 点击 “Create Network”,flat_net 创建成功。Provider Network Type 选择 “Flat”。Physical Network 填写 “default”,与 ml2_conf.ini 中 flat_networks 参数保持同等:

    3)点击 flat_net 链接,进入 network 设置页面:

    4)目前还没有 subnet,点击 “Create Subnet” 按钮:

    5)设置 IP 地址为 “172.16.1.0/24”,点击 “Next”:

    6)设置 IP 地址范围为 172.16.1.101-172.16.1.200,点击 “Create”:

    7)subnet 创建成功:

    8)底层网络发生了什么变化 。执行 brctl show,查看控制节点当前的网络布局:

    Neutron 自动新建了 flat_net 对应的网桥 brqf153b42f-c3,以及 dhcp 的 tap 装备 tap19a0ed3d-fe。另外,tap19a0ed3d-fe 和物理网卡 eth1 都已经毗连到 bridge。此时 flat_net 布局如图所示:

  • 将 Instance 毗连到 Flat_net:
    1)launch 新的 instance “cirros-vm1”,选择网络 falt_net:

    2)cirros-vm1 分配到的 IP 为 172.16.1.103:

    3)cirros-vm1 被 schedule 到控制节点,对应的 tap 装备为 tapc1875c7f-cb,而且已经毗连到 bridge :

    4)当前 flat_net 的布局如下:

    5)继续用同样的方式 launch instance cirros-vm2,分配到的 IP 为 172.16.1.104:

    6)cirros-vm2 被 schedule 到计算节点,对应的 tap 装备为 tapfb3fb197-24,而且毗连到 bridge:

    这里有两点必要提醒:因为计算节点上没有 dhcp 服务,以是 brctl show 中没有 dhcp 对应的 tap 装备。计算节点上 bridge 的名称与控制节点上同等,都是 brqf153b42f-c3,表明是同一个 network。
    7)当前 flat_net 的布局如下:

    8)cirros-vm1(172.16.1.103) 与 cirros-vm2(172.16.1.104) 位于不同节点,通过 flat_net 相连,下面执行 PING 验证连通性。 在 cirros-vm1 控制台中执行 ping 172.16.1.104:

2.5.5.5 DHCP服务



  • Neutron 提供 DHCP 服务的组件是 DHCP agent。 DHCP agent 在网络节点运行上,默认通过 dnsmasq 实现 DHCP 功能。

  • 设置 DHCP agent:
    1)DHCP agent 的设置文件位于 /etc/neutron/dhcp_agent.ini:

    dhcp_driver :使用 dnsmasq 实现 DHCP。
    interface_driver :使用 linux bridge 毗连 DHCP namespace interface。
    2)当创建 network 并在 subnet 上 enable DHCP:
    网络节点上的 DHCP agent 会启动一个dnsmasq 历程为该network 提供 DHCP 服务,dnsmasq 是一个提供 DHCP 和 DNS 服务的开源软件。dnsmasq 与 network 是一对一关系,一个 dnsmasq 历程可以为同一 netowrk 中所有 enable 了 DHCP 的 subnet 提供服务。
    3)回到我们的实验环境,之前创建了 flat_net,而且在 subnet 上启用了 DHCP,执行 ps 查看 dnsmasq 历程,如下图所示:

    DHCP agent 会为每个 network 创建一个目录 /opt/stack/data/neutron/dhcp/,用于存放该 network 的 dnsmasq 设置文件。
    4)讨论 dnsmasq 紧张的启动参数:
    --dhcp-hostsfile:存放 DHCP host 信息的文件,这里的 host 在我们这里实际上就是 instance。dnsmasq 从该文件获取 host 的 IP 与 MAC 的对应关系。每个 host 对应一个条目,信息泉源于 Neutron 数据库。对于 flat_net,hostsfile 是 /opt/stack/data/neutron/dhcp/f153b42f-c3a1-4b6c-8865-c09b5b2aa274/host,纪录了 DHCP,cirros-vm1 和 cirros-vm2 的 interface 信息。

    --interface:指定提供 DHCP 服务的 interface。dnsmasq 会在该 interface 上监听 instance 的 DHCP 请求。对于 flat_net,interface 是 ns-19a0ed3d-fe。大概各人还记得,之前我们看到的 DHCP interface 叫 tap19a0ed3d-fe(如下图所示),并非 ns-19a0ed3d-fe。

    从名称上看,ns-19a0ed3d-fe 和 tap19a0ed3d-fe 应该存在某种联系,但那是什么呢?要回答这个题目,必要先搞懂一个概念:Linux Network Namespace,我们下一节详细讨论。
  • 用 Namspace 隔离 DHCP 服务:
    1)Neutron 通过 dnsmasq 提供 DHCP 服务,而 dnsmasq 怎样独立的为每个 network 服务呢?
    2)答案是通过 Linux Network Namespace 隔离。在二层网络上,VLAN 可以将一个物理交换机分割成几个独立的虚拟交换机。 类似地,在三层网络上,Linux network namespace 可以将一个物理三层网络分割成几个独立的虚拟三层网络。
    3)每个 namespace 都有自己独立的网络栈,包括 route table,firewall rule,network interface device 等。
    4)Neutron 通过 namespace 为每个 network 提供独立的 DHCP 和路由服务,从而允许租户创建重叠的网络。如果没有 namespace,网络就不能重叠,如许就失去了许多机动性。
  • 每个 dnsmasq 历程都位于独立的 namespace,定名为 qdhcp-<network id>,比方 flat_net,我们有:

    1)ip netns list 下令列出所有的 namespace。
    qdhcp-f153b42f-c3a1-4b6c-8865-c09b5b2aa274 就是 flat_net 的 namespace。
    2)实在,宿主机自己也有一个 namespace,叫 root namespace,拥有所有物理和虚拟 interface device。物理interface 只能位于 root namespace。新创建的 namespace 默认只有一个 loopback device。管理员可以将虚拟 interface,比方 bridge,tap 等装备添加到某个 namespace。对于 flat_net 的 DHCP 装备 tap19a0ed3d-fe,必要将其放到 namespace qdhcp-f153b42f-c3a1-4b6c-8865-c09b5b2aa274 中,但如许会带来一个题目: tap19a0ed3d-fe 将无法直接与 root namespace 中的 bridge 装备 brqf153b42f-c3 毗连。
  • Neutron 使用 veth pair 解决了这个题目:
    1)veth pair 是一种成对出现的特殊网络装备,它们象一根虚拟的网线,可用于毗连两个 namespace。向 veth pair 一端输入数据,在另一端就能读到此数据。
    2)tap19a0ed3d-fe 与 ns-19a0ed3d-fe 就是一对 veth pair,它们将 qdhcp-f153b42f-c3a1-4b6c-8865-c09b5b2aa274 毗连到 brqf153b42f-c3。

  • 可以通过 ip netns exec <network namespace name> <command> 管理 namespace:
    1)比方查看 ns-19a0ed3d-fe 的设置:

  • 分析instance怎样从dnsmasq获取IP:
    1)在创建 instance 时,Neutron 会为其分配一个 port,内里包罗了 MAC 和 IP 地址信息,这些信息会同步更新到 dnsmasq 的 host 文件。如下图所示:

    2)同时 nova-compute 会设置 cirros-vm1 VIF 的 MAC 地址:

    3)一切准备停当,instance 获取 IP 的过程如下:
    a)cirros-vm1 开机启动,发出 DHCPDISCOVER 广播,该广播消息在整个 flat_net 中都可以被收到。
    b)广播到达 veth tap19a0ed3d-fe,然后传送给 veth pair 的另一端 ns-19a0ed3d-fe。dnsmasq 在它上面监听,dnsmasq 检查其 host 文件,发现有对应项,于是dnsmasq 以 DHCPOFFER 消息将 IP(172.16.1.103)、子网掩码(255.255.255.0)、地址租用期限等信息发送给 cirros-vm1。
    c)cirros-vm1 发送 DHCPREQUEST 消息确认接受此 DHCPOFFER。
    d)dnsmasq 发送确认消息 DHCPACK,整个过程竣事。
  • 这个过程我们可以在 dnsmasq 日志中查看,dnsmasq 默认将日志纪录到 /var/log/syslog:

2.5.5.6 vlan network



  • 下图是 vlan100 网络的示例,三个 instance 通过 TAP 装备毗连到名为 “brqXXXX” linux bridge。在物理网卡 eth1 上创建了 eth1.100 的 vlan interface,eth1.100 毗连到 brqXXXX。instance 通过 eth1.100 发送到 eth1 的数据包就会打上 vlan100 的 tag。

  • 如果再创建一个 network vlan101,eth1 上会相应的创建 vlan interface eth1.101,而且毗连的新的 lingux bridge “brqYYYY”。
    每个 vlan network 有自己的 bridge,从而也就实现了基于 vlan 的隔离。

  • 这里有一点要特别提醒:因为物理网卡 eth1 上面可以走多个 vlan 的数据,那么物理交换机上与 eth1 相连的的 port 要设置成 trunk 模式,而不是 access 模式。
  • 在 ML2 中设置 Vlan Network:
    1)首先在 /etc/neutron/plugins/ml2/ml2_conf.ini 中设置 vlan network 相干参数,指定平凡用户创建的网络类型为 vlan:

    2)然后指定 vlan 的范围:

    上面设置定义了 label 为 “default” 的 vlan network,vlan id 的范围是 3001 – 4000。这个范围是针对平凡用户在自己的租户里创建 network 的范围。因为平凡用户创建 network 时并不能指定 vlan id,Neutron 会按顺序自动从这个范围中取值。对于 admin 则没有 vlan id 的限定,admin 可以创建 id 范围为 1-4094 的 vlan network。
    3)接着必要指明 vlan network 与物理网卡的对应关系:

    如上所示: 在 [ml2_type_vlan] 中定义了 lable “default”,[linux_bridge] 中则指明 default 对应的物理网卡为 eth1。这里 label 的作用与前面 flat network 中的 label 一样,只是一个标识,可以是任何字符串。设置完成,重启 Neutron 服务后生效。
  • 创建第一个 Vlan Network Vlan100:
    1)打开菜单 Admin -> Networks,点击 “Create Network” 按钮:

    2)显示创建页面,点击 “Create Network”,vlan100 创建成功:
    Provider Network Type 选择 “VLAN”。Physical Network 填写 “default”,必须与 ml2_conf.ini中network_vlan_ranges 参数值保持同等。Segmentation ID 即 VLAN ID,设置为 100。

    3)点击 vlan100 链接,进入 network 设置页面:

    4)目前还没有 subnet,点击 “Create Subnet” 按钮:

    5)subnet_172_16_100_0,IP 地址为 172.16.100.0/24:


    6)底层网络发生了什么变化:
    在控制节点上执行 brctl show,查看当前网络布局:

    Neutron 自动新建了三个装备:

    • vlan100 对应的网桥 brq3fcfdb98-9d。
    • vlan interface eth1.100。
    • dhcp 的 tap 装备 tap1180bbe8-06。
      eth1.100 和 tap19a0ed3d-fe 已经毗连到了 brq3fcfdb98-9d,VLAN 100 的二层网络停当
      7)此时 vlan100 布局如图所示:


  • 将instance毗连到vlan100:
    1)launch 新的 instance “cirros-vm1”,网络选择 vlan100:

    2)cirros-vm1 分配到的 IP 为 172.16.100.3:

    3)cirros-vm1 被 schedule 到控制节点,对应的 tap 装备为 tapc1875c7f-cb,而且毗连到 bridge:

    4)当前 vlan100 的布局如下 :

    5)继续用同样的方式 launch instance cirros-vm2,分配到的 IP 为 172.16.100.104:

    6)cirros-vm2 被 schedule 到计算节点,对应的 tap 装备为 tap238437b8-50,而且毗连到 bridge:

    因为计算节点上没有 hdcp 服务,以是没有相应的 tap 装备。 另外,bridge 的名称与控制节点上同等,都是 brq3fcfdb98-9d,表明是同一个 network。
    7)当前 vlan100 的布局如下:

    8)cirros-vm1(172.16.100.3) 与 cirros-vm2(172.16.100.4) 位于不同节点,通过 vlan100 相连,下面执行 PING 验证连通性。 在 cirros-vm1 控制台中执行 ping 172.16.100.4:

  • 创建第二个 Vlan Network Vlan101:
    1)创建第二个 vlan network vlan101:

    2)subnet IP 地址为 172.16.101.0/24:

    3) 底层网络发生了什么变化:
    Neutron 自动创建了 vlan101 对应的网桥 brq1d7040b8-01,vlan interface eth1.101,以及 dhcp 的 tap 装备 tap5b1a2247-32。eth1.101 和 tap5b1a2247-32 已经毗连到 brq1d7040b8-01,VLAN 101 的二层网络停当。

    4)网络布局如下:

  • 毗连 Insance 到 Vlan101:
    1)launch 新的 instance “cirros-vm3”,网络选择 vlan101:

    2)cirros-vm3 分配到的 IP 为 172.16.101.103:

    3)cirros-vm3 被 schedule 到计算节点,对应的 tap 装备为 tapadb5cc6a-7a,而且毗连到 bridge:

    4)当前网络布局如下:

    cirros-vm1 位于控制节点,属于 vlan100。
    cirros-vm2 位于计算节点,属于 vlan100。
    cirros-vm3 位于计算节点,属于 vlan101。
    cirros-vm1 与 cirros-vm2 都在 vlan100,它们之间能通讯。
    cirros-vm3 在 vlan101,不能与 cirros-vm1 和 cirros-vm2 通讯。
    那怎么样才气让 vlan100 与 vlan101 中的 instance 通讯呢?单靠二层 vlan 是不可的,还得在三层通过路由器转发。
2.5.5.7 Routing



  • Routing 功能概述:
    1)路由服务(Routing)提供跨 subnet 互联互通功能。比方前面我们搭建了实验环境:
    cirros-vm1 172.16.100.3 vlan100
    cirros-vm3 172.16.101.3 vlan101
    这两个 instance 要通讯必须借助 router。 可以是物理 router 或者虚拟 router。
    2)物理路由:

    接入的物理 router 有两个 interface ip:
    172.16.100.1 对应 vlan100 的网关。
    172.16.101.1 对应 vlan101 的网关。
    当 cirros-vm1 要跟 cirros-vm3 通讯时,数据包的流向是如许的:a)因为 cirros-vm1 的默认网关指向 172.16.100.1,cirros-vm1 发送到 cirros-vm3 的数据包首先通过 vlan100 的 interface 进入物理 router。b)router 发现目的地址 172.16.101.3 与 172.16.101.1 为同一个 vlan,则从 vlan101 的 interface 发出。c)数据包经过 brq1d7040b8-01 最终到达 cirros-vm3。
    3)虚拟路由:
    虚拟 router 的路由机制与物理 router 一样,只是由软件实现。Neutron 两种方案都支持。如果要使用虚拟 router,必要启用 L3 agent。L3 agent 会在控制节点或者网络节点上运行虚拟 router,为 subnet 提供路由服务。
  • 设置 L3 Agent:
    1)Neutron 的路由服务是由 l3 agent 提供的,除此之外,l3 agent 通过 iptables 提供 firewall 和 floating ip 服务。

    2)l3 agent 必要正确设置才气工作,设置文件为 /etc/neutron/l3_agent.ini,位于控制节点或网络节点上:
    interface_driver 是最紧张的选项,如果 mechanism driver 是 linux bridge,则:interface_driver = neutron.agent.linux.interface.BridgeInterfaceDriver;如果选用 open vswitch,则:interface_driver = neutron.agent.linux.interface.OVSInterfaceDriver。
    3)l3 agent 运行在控制或网络节点上:

    可以看到 l3 agnet 已经正常启动。
  • 创建 Router 连通 Subnet:
    1)创建虚拟路由器“router_100_101”,买通 vlan100 和 vlan101。打开操作菜单 Project -> Network -> Routers:

    2)点击 “Create Router” 按钮:

    3)router 定名为 “router_100_101”,点击 “Create Router” 按钮确认:

    4)router_100_101 创建成功:

    5)接下来必要将 vlan100 和 vlan101 毗连到 router_100_101 。点击 “router_100_101” 链接进入 router 的设置页面,在 “Interfaces” 标签中点击 “Add Interface” 按钮

    6)选择 vlan101 的 subnet_172_16_101_0,点击 “Add Interface” 确认:

    7)用同样的方法添加 vlan100 的 subnet_172_16_100_0:

    完成后,可以看到 router_100_101 有了两个 interface,其 IP 恰恰是 subnet 的 Gateway IP 172.16.100.1 和 172.16.101.1。
    8)router_100_101 已经毗连了 subnet_172_16_100_0 和 subnet_172_16_101_0。router_100_101 上已经设置好了两个 subnet 的 Gateway IP。cirros-vm1 和 cirros-vm3 应该可以通讯了。通过 PING 测试一下:

    9)查看 cirros-vm1 的路由表,默认网关为 172.16.100.1。同时 traceroute 告诉我们,cirros-vm1 确实是通过 router_100_101 访问到 cirros-vm3 的:

  • 虚拟 ​Router 原理分析:
    1)首先我们查看控制节点的 linux bridge 布局发生了什么变化:

    vlan101 的 bridge 上多了一个 tape17162c5-00,从定名上可以推断该 TAP 装备对应 router_100_101 的 interface (e17162c5-00fa)。vlan100 的 bridge 上多了一个 tapd568ba1a-74,从定名上可以推断该 TAP 装备对应 router_100_101 的 interface (d568ba1a-740e)。
    2)当前网络布局如图所示:

    3)两个 TAP 装备上并没有设置相应的 Gateway IP:

    4)如果没有 Gateway IP,router_100_101 是怎样完成路由的呢?
    答案是:l3 agent 会为每个 router 创建了一个 namespace,通过 veth pair 与 TAP 相连,然后将 Gateway IP 设置在位于 namespace 内里的 veth interface 上,如许就能提供路由了。
    5)通过 ip netns 查看 namespace:router 对应的 namespace 定名为 qrouter-<router id>。

    6)通过 ip netns exec <namespace name> ip a 下令查看 router_100_101 namespace 中的 veth interface 设置:

    namespace 中有两个 interface:qr-e17162c5-00 上设置了 Gateway IP 172.16.101.1,与 root namespace 中的 tape17162c5-00 组成 veth pair。qr-d568ba1a-74 上设置了 Gateway IP 172.16.100.1,与 root namespace 中的 tapd568ba1a-74 组成 veth pair。
    7)网络布局如图所示:

    8)namespace 中的路由表也保证了 subnet_172_16_100_0 和 subnet_172_16_101_0 之间是可以路由的,下令为ip nets exec <namespace name> IP routing table:

  • 为什么要使用Namespace:
    1)为什么不直接在 tape17162c5-00 和 tapd568ba1a-74 上设置 Gateway IP,而是引入一个 namespace,在 namespace 内里设置 Gateway IP 呢?首先考虑另外一个题目:如果不用 namespace,直接 Gareway IP 设置到 tape17162c5-00 和 tapd568ba1a-74 上,能不能连通 subnet_172_16_100_0 和 subnet_172_16_101_0 呢?
    答案是可以的,只要控制节点上设置了类似下面的路由:

    既然不必要 namespace 也可以路由,为什么还要加一层 namespace 增加复杂性呢?其根本原因是:增加namespace是为了支持网络重叠。 云环境下,租户可以按照自己的规划创建网络,不同租户的网络是可能重叠的。 将路由功能放到 namespace 中,就能隔离不同租户的网络,从而支持网络重叠。
    2)通过例子进一步表明:A,B 两个租户定义了完全相同的两个 subnet,网络完全重叠。如下图所示:

    3)不使用namespace的场景:

    其特征是网关 IP 设置在 TAP interface 上。因为没有 namespace 隔离,router_100_101 和 router_102_103 的路由条目都只能纪录到控制节点操作体系(root namespace)的路由表中,内容如下:

    如许的路由表是无法工作的。按照路由表优先匹配原则,Tenant B 的数据包总是错误地被 Tenant A 的 router 路由。比方 vlan102 上有数据包要发到 vlan103。选择路由时,会匹配路由表的第二个条目,结果数据被错误地发到了 vlan101。
    4) 使用 namespace 的场景:如果使用 namespace,网络布局如下:

    其特征是网关 IP 设置在 namespace 中的 veth interface 上。每个 namespace 拥有自己的路由表。router_100_101 的路由表内容如下:

    router_102_103 的路由表内容如下:

    如许的路由表是可以工作的。比方 vlan102 上有数据包要发到 vlan103。选择路由时,会查看 router_102_103 的路由表, 匹配第二个条目,数据通过 qr-4 被正确地发送到 vlan103。同样当 vlan100 上有数据包要发到 vlan101时,会匹配 router_100_101 路由表的第二个条目,数据通过 qr-2 被正确地发送到 vlan101。可见,namespace 使得每个 router 有自己的路由表,而且不会与其他 router 冲突,以是能很好地支持网络重叠。
  • instance访问外网 ML2 的设置:
    1)这里的外部网络是指的租户网络以外的网络。租户网络是由 Neutron 创建和维护的网络。 外部网络不由 Neutron 创建。如果是私有云,外部网络通常指的是公司 intranet;如果是公有云,外部网络通常指的是 internet。详细到我们的实验网络环境: 计算节点和控制节点 eth1 提供的是租户网络,IP 段租户可以自由设置。 控制节点 eth2 毗连的就是外部网络,IP 网段为 10.10.10.0/24。如下图所示:

    2)设置准备:为了毗连外部网络,必要在设置文件中告诉 Neutron 外部网络的类型以及对应的物理网卡
    因为外部网络是已经存在的物理网络,一般都是 flat 或者 vlan 类型。这里我们将外部网络的 label 定名为 “external”。
    如果类型为 flat,控制节点 /etc/neutron/plugins/ml2/ml2_conf.ini 设置如下:

    如果类型为 vlan,设置如下

    修改设置后,必要重启 neutron 的相干服务。在我们的网络环境中,外部网络是 flat 类型。
  • 创建外网 Ext_net:
    1)进入 Admin -> Networks 菜单,点击 “Create Network” 按钮:

    2)显示创建页面,点击 “Create Network”,ext_net 创建成功,其中Provider Network Type 选择 “Flat”;Physical Network 填写 “external”,与 ml2_conf.ini 中 flat_networks 参数的设置保持同等;勾选 External Network 选择框。

    3)点击 ext_net 链接,进入 network 设置页面:

    4)目前还没有 subnet,点击 “Create Subnet” 按钮:

    5)创建 subnet_10_10_10_0,IP 地址为 10.10.10.0/24,点击 “Next”。这里 Gateway 我们使用默认地址 10.10.10.1。
    通常我们必要询问网络管理员外网 subnet 的 Gateway IP,然后填在这里:

    6)因为我们不会直接为 instance 分配外网 IP,以是一般不必要 enable DHCP,点击 “Create”:

    7)subnet 创建成功,网关为 10.10.10.1:

    8)查看控制节点网络布局的变化,执行 brctl show:

    增加了一个网桥 brqe496d3d2-53,物理网卡 eth2 已经毗连到该 bridge。
  • 外网访问原理分析:
    1)将外网毗连到 Neutron 的虚拟路由器,如许 instance 才气访问外网 。点击菜单 Project -> Network -> Routers 进入 router 列表,点击 router_100_101 的 “Set Gateway” 按钮:

    2) “External Network” 下拉列表中选择 ext_net,点击 “Set Gateway” :

    3)外网设置成功:

    4) 我们必要看看 router 发生了什么变化 。点击 “router_100_101” 链接,打开 “Interfaces” 标签页:router 多了一个新的 interface,IP 为 10.10.10.2。 该 interface 用于毗连外网 ext_net。

    5)查看控制节点的网络布局,外网 bridge 上已经毗连了 router 的 tap 装备 tapb8b32a88-03:

    6)ip netns list 下令列出所有的 namespace。在 router 的 namespace 中查看 tapb8b32a88-03 的 veth pair 装备:

    该 veth pair 定名为 qg-b8b32a88-03,上面设置了 IP 10.10.10.2。router 的每个 interface 在 namespace 中都有对应的 veth。如果 veth 用于毗连租户网络,定名格式为 qr-xxx,好比 qr-d568ba1a-74 和 qr-e17162c5-00。如果 veth 用于毗连外部网络,定名格式为 qg-xxx,好比 qg-b8b32a88-03。
    7)查看 router 的路由表信息:

    可以看到默认网关为 10.10.10.1。 意味着对于访问 vlan100 和 vlan101 租户网络以外的所有流量,router_100_101 都将转发给 ext_net 的网关 10.10.10.1。
    8)如今 router_100_101 已经同时毗连了 vlan100, vlan101 和 ext_net 三个网络,如下图所示:

    9)下面我们在 cirros-vm3 上测试一下:irros-vm3 位于计算节点,如今已经可以 Ping 到 ext_net 网关 10.10.10.1 了。

    10)通过 traceroute 查看一下 cirros-vm3 到 10.10.10.1 的路径 :

    数据包经过两跳到达 10.10.10.1 网关。数据包首先发送到 router_100_101 毗连 vlan101 的 interface(172.16.101.1)。然后通过毗连 ext_net 的 interface(10.10.10.2) 转发出去,末了到达 10.10.10.1。
    当数据包从 router 毗连外网的接口 qg-b8b32a88-03 发出的时候,会做一次 Source NAT,即将包的源地址修改为 router 的接口地址 10.10.10.2,如许就能够保证目的端能够将应答的包发回给 router,然后再转发回源端 instance。
    11)可以通过 iptables 下令查看 SNAT 的规则:

    当 cirros-vm3(172.16.101.3) Ping 10.10.10.1 时,可用通过 tcpdump 分别观察 router 两个 interface 的icmp 数据包来验证 SNAT 的举动。
    12)vlan101 interface qr-e17162c5-00 的 tcpdump 输出:

    13)ext_net interface qg-b8b32a88-03 的 tcpdump 输出:

    SNAT 让 instance 能够直接访问外网,但外网还不能直接访问 instance。因为 instance 没有外网 IP。这里 “直接访问 instance” 是指通讯毗连由外网发起,比方从外网 SSH cirros-vm3。 这个题目可以通过 floating IP 解决,下一节我们将讨论浮动 IP。
  • 创建 Floating IP:
    1)先复习一下前面我们讨论的知识:
    当租户网络毗连到 Neutron router,通常将 router 作为默认网关。当 router 接收到 instance 的数据包,并将其转发到外网时:a)router 会修改包的源地址为自己的外网地址,如许确保数据包转发到外网,并能够从外网返回。b)router 修改返回的数据包,并转发给真正的 instance。这个举动被称作 Source NAT。
    如果必要从外网直接访问 instance,则可以利用 floating IP。下面是关于 floating IP 必须知道的究竟:a)floating IP 提供静态 NAT 功能,建立外网 IP 与 instance 租户网络 IP 的一对一映射。b)floating IP 是设置在 router 提供网关的外网 interface 上的,而非 instance 中。c)router 会根据通讯的方向修改数据包的源或者目的地址。
    2)下面我们通过实验深入学习 floating IP 。点击 Project -> Compute -> Access & Security 菜单,打开 Floating IPs 标签页点击 “Allocate IP To Project” 按钮:

    3)floating IP Pool 为 ext_net,点击 “Allocate IP” 按钮:

    从 Pool 中成功分配了一个 IP 10.10.10.3。
    4)下面我们将它分配给 cirror-vm3,点击 “Associate” 按钮:

    5)在下拉列表中选择 cirror-vm3,点击 “Associate” 按钮:

    6)分配成功,floating IP 10.10.10.3 已经对应到 cirros-vm3 的租户 IP 172.16.101.3:

    7)执行ip netns exec <namespace> ip a首先查看 router 的 interface 设置:

    可以看到,floating IP 已经设置到 router 的外网 interface qg-b8b32a88-03 上。
    8)执行ip netns exec <namespace> iptables -t nat -S查看 router 的 NAT 规则:

    iptables 增加了两条处理 floating IP 的规则: a)当 router 接收到从外网发来的包,如果目的地址是 floating IP 10.10.10.3,将目的地址修改为 cirros-vm3 的 IP 172.16.101.3。如许外网的包就能送达到 cirros-vm3。b)当 cirros-vm3 发送数据到外网,源地址 172.16.101.3 将被修改为 floating IP 10.10.10.3。
    9)在我的实验环境中,10.10.10.1 是外网中的物理交换机,如今让它 PING cirros-vm3,能PING通:

    10)ext_net interface qg-b8b32a88-03 的 tcpdump 输出:

    可见,在外网接口 qg-b8b32a88-03 上,始终是通过 floating IP 10.10.10.3 与外网通讯。
    11)vlan101 interface qr-e17162c5-00 的 tcpdump 输出:

    当数据转发到租户网络,地址已经变为 cirros-vm3 的租户 IP 172.16.101.3 了。
    12)小结:
    a)floating IP 能够让外网直接访问租户网络中的 instance。这是通过在 router 上应用 iptalbes 的 NAT 规则实现的。
    b)floating IP 是设置在 router 的外网 interface 上的,而非 instance,这一点必要特别注意。
    至此,我们已经完成了 Neutron L3 服务毗连不同 subnet,访问外网,以及 floating IP 的学习。
2.5.5.8 vxlan network



  • 前言: 除了前面讨论的 local, flat, vlan 这几类网络,OpenStack 还支持 vxlan 和 gre 这两种 overlay network。overlay network 是指建立在其他网络上的网络。 该网络中的节点可以看作通过虚拟(或逻辑)链路毗连起来的。 overlay network 在底层可能由若干物理链路组成,但对于节点,不必要关心这些底层实现。比方 P2P 网络就是 overlay network,隧道也是。 vxlan 和 gre 都是基于隧道技术实现的,它们也都是 overlay network。目前 linux bridge 只支持 vxlan,不支持 gre;open vswitch 两者都支持。 vxlan 与 gre 实现非常类似,而且 vxlan 用得较多,以是本教程只介绍 vxlan。
  • VXLAN 全称 Virtual eXtensible Local Area Network(虚拟扩展局域网),VXLAN 提供与 VLAN 相同的以太网二层服务,但是拥有更强的扩展性和机动性。与 VLAN 相比,VXLAN 有下面几个优势:
    1)支持更多的二层网段。 VLAN 使用 12-bit 标志 VLAN ID,最多支持 4094 个 VLAN,这对于大型云部署会成为瓶颈。VXLAN 的 ID (VNI 或者 VNID)则用 24-bit 标志,支持 16777216 个二层网段;
    2)VXLAN 的数据包是封装到 UDP 通过三层传输和转发的;
    3)避免物理交换机 MAC 表耗尽。 由于接纳隧道机制, 交换机无需在 MAC 表中纪录虚拟机的信息。
  • VXLAN 封装和包格式:
    1)VXLAN 是将二层建立在三层上的网络。 通过将二层数据封装到 UDP 的方式来扩展数据中心的二层网段数量;
    2)VXLAN 是一种在现有物理网络设施中支持大规模多租户网络环境的解决方案。 VXLAN 的传输协议是 IP + UDP;
    3)VXLAN 定义了一个 MAC-in-UDP 的封装格式。 在原始的 Layer 2 网络包前加上 VXLAN header,然后放到 UDP 和 IP 包中。 通过 MAC-in-UDP 封装,VXLAN 能够在 Layer 3 网络上建立起了一条 Layer 2 的隧道;
    4)VXLAN 包的格式如下:

    如上图所示,VXLAN 引入了 8-byte VXLAN header,其中 VNI 占 24-bit。VXLAN 和原始的 L2 frame 被封装到 UDP 包中。这 24-bit 的 VNI 用于标示不同的二层网段,能够支持 16777216 个 LAN。
  • VXLAN Tunnel Endpoint
    1)VXLAN 使用 VXLAN tunnel endpoint (VTEP) 装备处理 VXLAN 的封装和解封。每个 VTEP 有一个 IP interface,设置了一个 IP 地址。VTEP 使用该 IP 封装 Layer 2 frame,并通过该 IP interface 传输和接收封装后的 VXLAN 数据包。
    2)下面是 VTEP 的示意图:

    3)VXLAN 独立于底层的网络拓扑;反过来,两个 VTEP 之间的底层 IP 网络也独立于 VXLAN。 VXLAN 数据包是根据外层的 IP header 路由的,该 header 将两头的 VTEP IP 作为源和目标 IP。
  • VXLAN包转发流程:

    VXLAN 在 VTEP 间建立隧道,通过 Layer 3 网络传输封装后的 Layer 2 数据。数据传输过程如下:
    1)Host-A 向 Host-B 发送数据时,Host-B 的 MAC 和 IP 作为数据包的目标 MAC 和 IP,Host-A 的 MAC 作为数据包的源 MAC 和 IP,然后通过 VTEP-1 将数据发送出去。
    2)VTEP-1 从自己维护的映射表中找到 MAC-B 对应的 VTEP-2,然后执行 VXLAN 封装,加上 VXLAN头,UDP 头,以及外层 IP 和 MAC 头。此时的外层 IP 头,目标地址为 VTEP-2 的 IP,源地址为 VTEP-1 的IP。同时由于下一跳是 Router-1,以是外层 MAC 头中目标地址为 Router-1 的 MAC。
    3)数据包从 VTEP-1 发送出去后,外部网络的路由器会依据外层 IP 头举行包路由,末了到达与 VTEP-2 毗连的路由器 Router-2。
    4)Router-2将数据包发送给 VTEP-2。VTEP-2 负责解封数据包,依次去掉外层 MAC 头,外层 IP 头,UDP 头 和 VXLAN 头。
    5)VTEP-2 依据目标 MAC 地址将数据包发送给 Host-B。
    上面的流程我们看到 VTEP 是 VXLAN 的最焦点组件,负责数据的封装和解封。隧道也是建立在 VTEP 之间的,VTEP 负责数据的传送。
  • 在 ML2 中设置 VXLAN:
    1)在 /etc/neutron/plugins/ml2/ml2_conf.ini 设置 vxlan network 相干参数:

    2)然后指定 vxlan 的范围:

    上面的设置定义了 vxlan vni 的范围是 1001 – 2000。这个范围是针对平凡用户在自己的租户里创建 vxlan network 的范围。因为平凡用户创建 network 时并不能指定 vni,Neutron 会按顺序自动从这个范围中取值。对于 admin 则没有 vni 范围的限定,admin 可以创建 vni 范围为 1-16777216 的 vxlan network。
    3)接着必要在 [VXLAN] 中设置 VTEP:
    控制节点 devstack_controller 的 ml2_conf.ini 设置如下:

    计算节点 devstack_compute01 的 ml2_conf.ini 设置如下:

    local_ip 指定节点上用作 VTEP 的 IP 地址。devstack_controller 的 VTEP IP 是 166.66.16.10,网卡为 eth1。devstack_compute01 的 VTEP IP 是 166.66.16.11,网卡为 eth1。注意:作为准备工作,这两个 VTEP IP 必要提前设置到节点的 eht1 上,Neutron 并不会帮我们分配这个 IP。
  • 创建 VXLAN:
    1)打开菜单 Admin -> Networks,点击 “Create Network” 按钮

    2)显示创建页面,Provider Network Type 选择 “VXLAN” Segmentation ID 即 VNI,设置为 100。点击 “Create Network”,vxlan100 创建成功:

    3)点击 vxlan100 链接,进入 network 设置页面:

    4)目前还没有 subnet,点击 “Create Subnet” 按钮:

    5)创建 subnet_172_16_100_0,IP 地址为 172.16.100.0/24:


    6)底层网络发生了什么变化 。在控制节点上执行 brctl show,查看当前的网络布局:

    Neutron 创建了:
    a. vxlan100 对应的网桥 brq1762d312-d4
    b. vxlan interface vxlan-100
    c. dhcp 的 tap 装备 tap4df76d0e-59
    d. vxlan-100 和 tap4df76d0e-59 已经毗连到 brq1762d312-d4,vxlan100 的二层网络停当。
    7)执行 ip -d link show dev vxlan-100 查看 vxlan interface 的详细设置

    可见,vxlan-100 的 VNI 是 100,对应的 VTEP 网络接口为 eth1。
    8)此时 vxlan100 布局如图所示:

  • 部署 Instance 到 VXLAN:
    1)launch 新的 instance “cirros-vm1”,网络选择vxlan100:

    2)cirros-vm1 分配到的 IP 为 172.16.100.3:

    3)cirros-vm1 被 schedule 到控制节点,对应的 tap 装备为 tap099caa87-cd,而且毗连到 bridge brq1762d312-d4:

    4)当前 vxlan100 的布局如下:

    5)继续用同样的方式 launch instance cirros-vm2,分配到的 IP 为 172.16.100.4:

    6)cirros-vm2 被 schedule 到计算节点,对应的 tap 装备为 tap457cc048-aa,而且毗连到 bridge brq1762d312-d4:

    7)因为计算节点上没有 dhcp 服务,以是没有相应的 tap 装备。另外,bridge 的名称与控制节点上同等,都是 brq1762d312-d4,表明是同一个 network。
    8)当前vxlan100的布局如下:

    9)cirros-vm1(172.16.100.3) 与 cirros-vm2(172.16.100.4) 位于不同节点,通过 vxlan100 相连,下面执行 PING 验证连通性。 在 cirros-vm1 控制台中执行 ping 172.16.100.4:

    如我们预料,ping 成功。对于多 vxlan 之间的 routing 以及 floating ip,实现方式与 vlan 非常类似。
  • L2 Population 原理:
    1)作用:L2 Population 是用来提高 VXLAN 网络 Scalability 的。通常我们说某个体系的 Scalability 好,其意思是:当体系的规模变大时,仍然能够高效地工作。
    2)L2 Population 到底解决了怎样的 Scalability 题目,请看下图:

    3)这是一个包罗 5 个节点的 VXLAN 网络,每个节点上运行了若干 VM。如今假设 Host 1 上的 VM A 想与 Host 4 上的 VM G 通讯。VM A 要做的第一步是获知 VM G 的 MAC 地址。于是 VM A 必要在整个 VXLAN 网络中广播 APR 报文:“VM G 的 MAC 地址是多少?”

    4)如果 VXLAN 网络的节点许多,广播的成本会很大,如许 Scalability 就成题目了,幸好 L2 Population 出现了:L2 Population 的作用是在 VTEP 上提供 Porxy ARP 功能,使得 VTEP 能够预先获知 VXLAN 网络中如下信息:VM IP — MAC 对应关系、VM — VTEP 的对应关系:

    5)当 VM A 必要与 VM G 通讯时:a)Host 1 上的 VTEP 直接响应 VM A 的 APR 请求,告之 VM G 的 MAC 地址。b)因为 Host 1 上的 VTEP 知道 VM G 位于 Host 4,会将封装好的 VXLAN 数据包直接发送给 Host 4 的 VTEP。如许就解决了 MAC 地址学习和 APR 广播的题目,从而保证了 VXLAN 的 Scalability。
    6)那么下一个关键题目是:VTEP 是怎样提前获知 IP — MAC — VTEP 相干信息的呢?
    答案是:a)Neutron 知道每一个 port 的状态和信息; port 生存了 IP,MAC 相干数据。b)instance 启动时,其 port 状态变化过程为:down -> build -> active。c)每当 port 状态发生变化时,Neutron 都会通过 RPC 消息通知各节点上的 Neutron agent,使得 VTEP 能够更新 VM 和 port 的相干信息。VTEP 可以根据这些信息判定出其他 Host 上都有哪些 VM,以及它们的 MAC 地址,如许就能直接与之通讯,从而避免了不须要的隧道毗连和广播。
  • 设置 L2 Population:
    1)目前 L2 Population 支持 VXLAN with Linux bridge 和 VXLAN/GRE with OVS;
    2)在 /etc/neutron/plugins/ml2/ml2_conf.ini 设置 l2population mechanism driver:

    3)同时在 [VXLAN] 中设置 enable L2 Population:

    4)L2 Population 生效后,输入ip -d link show dev vxlan-100下令,发现创建的 vxlan-100 会多一个 Proxy ARP 功能:

    5)输入bridge fdb show dev vxlan-100下令查看控制节点上的 forwarding database,可以看到 VTEP 生存了 cirros-vm2 的 port 信息:

    6)cirros-vm2 的 MAC 为 fa:16:3e:1d:23:a3。 VTEP IP 为 166.66.16.11。当必要与 cirros-vm2 通讯时,控制节点 VTEP 166.66.16.10 会将封装好的 VXLAN 数据包直接发送给计算节点的 VTEP 166.66.16.11。
    7)输入bridge fdb show dev vxlan-100下令查看计算节点上的 forwarding database:

    8)fdb 中生存了 cirros-vm1 和 dhcp 的 port 信息。当必要与它们通讯时,计算节点 VTEP 知道应该将数据包直接发送给控制节点的 VTEP。
2.5.5.9 Security Group



  • Neutron 为 instance 提供了两种管理网络安全的方法:安全组(Security Group)和虚拟防火墙。安全组的原理是通过 iptables 对 instance 地点计算节点的网络流量举行过滤。虚拟防火墙则由 Neutron Firewall as a Service(FWaaS)高级服务提供。其底层也是使用 iptables,在 Neutron Router 上对网络包举行过滤。
  • 默认安全组:每个 Project(租户)都有一个定名为 “default” 的默认安全组。
    1)点击菜单 Project -> Compute -> Access & Security,查看 Security Group 列表:

    2)点击Manage Rules按钮,查看 “default” 安全组的规则:

    3)“default” 安全组有四条规则,其作用是:允许所有外出(Egress)的流量,但禁止所有进入(Ingress)的流量。
    4)当我们创建 instance 时,可以在 “Access & Security” 标签页中选择安全组。如果当前只有 “default” 这一个安全组,则会逼迫使用 “default” :

    5)当前在 devstack-controller 上有 instance “cirros-vm1”:

    6)在 devstack-controller 上执行 iptables-save 下令查看相干规则。iptables 的规则较多,这里我们节选了 cirros-vm1 相干的规则。这些规则是 Neutron 根据安全组自动天生的。cirros-vm1 的 TAP interface 为 tap8bca5b86-23,可以看到:

    7)iptables 的规则是应用在 Neutron port 上的,port 在这里是 cirros-vm1 的虚拟网卡 tap8bca5b86-23。ingress 规则集中定义在定名为 “neutron-linuxbri-i8bca5b86-2” 的 chain 中。egress 规则集中定义在定名为 “neutron-linuxbri-o8bca5b86-2” 的 chain 中。
    8)我们通过 dhcp namespace 对 cirros-vm1 举行 ping 和 ssh 测试:

    9)无法 ping 和 ssh cirros-vm1,可见当前的规则实现了 “default” 安全组,所有 ingress 流量都被禁止。
  • 应用新的安全组:Neutron 默认的安全组规则会禁止掉所有从外面访问 instance 的流量。本节我们会修改安全组的设置,允许 ping 和 ssh instance。有两种方法可以达到这个目的:a)修改 “default” 安全组。b)为 cirros-vm1 添加新的安全组。
    1)添加新的安全组,在安全组列表页面点击按钮:

    2)为安全组定名并点击 “Create Security Group”:

    3)新的安全组 “allow ping & ssh” 创建成功:

    4)点击Manage Group按钮,查看 “allow ping & ssh” 的规则:

    5)体系默认定义了两条规则,运行所有的外出流量。点击Add Rule按钮,添加允许 ping 的规则,“Rule” 选择 “All ICMP”,“Direction” 选择 “Ingress”,然后点击 “Add” 按钮:

6)同样的方式添加 ssh 规则:

7)在列表中查看添加成功的规则:

8)接下来设置 cirros-vm1,使用新的安全组 。进入 instance 列表页面,点击 cirros-vm1 下拉操作列表中的 “Edit Security Groups”:

9)可以看到 cirros-vm1 当前使用的安全组为 “default”,可选安全组为 “allow ping & ssh”。点击安全组 “allow ping & ssh” 后面的 “+” 按钮:

10)点击 “Save” 生存:

11)iptables 会立刻更新,下面通过 vimdiff 查看 iptables 前后的变化:

12)“allow ping & ssh” 安全组引入了下面两条 iptables 规则。作用是运行 ingress 的 ssh 和 ping 流量:

13)测试一下,如今能够 ping 和 ssh cirros-vm1 了:



  • 小结-安全组有以下特性:
    1)通过宿主机上 iptables 规则控制进出 instance 的流量;
    2)安全组作用在 instance 的 port 上;
    3)安全组的规则都是 allow,不能定义 deny 的规则;
    4)instance 可应用多个安全组叠加使用这些安全组中的规则。
2.5.5.10 Firewall as a Service



  • 理解概念:Firewall as a Service(FWaaS)是 Neutron 的一个高级服务。用户可以用它来创建和管理防火墙,在 subnet 的界限上对 layer 3 和 layer 4 的流量举行过滤。传统网络中的防火墙一般放在网关上,用来控制子网之间的访问。FWaaS 的原理也一样,是在 Neutron 虚拟 router 上应用防火墙规则,控制进出租户网络的数据。
  • FWaaS 有三个紧张概念: Firewall、Policy 和 Rule:
    1)Firewall:租户能够创建和管理的逻辑防火墙资源。 Firewall 必须关联某个 Policy,因此必须先创建 Policy。
    2)Firewall Policy:Policy 是 Rule 的聚集,Firewall 会按顺序应用 Policy 中的每一条 Rule。
    3)Firewall Rule:Rule 是访问控制的规则,由源与目的子网 IP、源与目的端口、协议、allow 或 deny 动作组成。比方,我们可以创建一条 Rule,允许外部网络通过 ssh 访问租户网络中的 instance,端口为 22。
  • 与 FWaaS 容易混淆的概念是安全组(Security Group):
    1)安全组的应用对象是虚拟网卡,由 L2 Agent 实现,好比 neutron_openvswitch_agent 和neutron_linuxbridge_agent;
    2)安全组会在计算节点上通过 iptables 规则来控制进出 instance 虚拟网卡的流量。也就是说:安全组保护的是 instance;
    3)FWaaS 的应用对象是 router,可以在安全组之前控制外部过来的流量,但是对于同一个 subnet 内的流量不作限定。也就是说:FWaaS 保护的是 subnet。以是,可以同时部署 FWaaS 和安全组实现双重防护。
  • 启用 FWaaS:
    1)因为 FWaaS 是在 router 中实现的,以是 FWaaS 没有单独的 agent。已有的 L3 agent 负责提供所有 FWaaS 功能。要启用 FWaaS,必须在 Neutron 的相干设置文件中做些设置。
    2)设置 firewall driver。Neutron 在 /etc/neutron/fwaas_driver.ini 文件中设置 FWaaS 使用的 driver:

    这里 driver 为 iptables。如果以后支持更多的 driver,可以在这里更换。
    3)设置 Neutron。在 Neutron 设置文件 /etc/neutron/neutron.conf 中启用 FWaaS plugin:

  • 举行实践,默认规则:
    1)环境:在我们的实验环境中,有两个 instance: cirros-vm1(172.16.100.3) 和 cirros-vm2(172.16.101.3)

    2)cirros-vm1 和 cirros-vm2 分别位于网络 vlan100 和 vlan101。vlan100 和 vlan101 之间由虚拟路由器 test_router 毗连。
    3)网络拓扑如下所示:

    4)在 test_router 没有应用任何 FWaaS 的环境下,cirros-vm1 可以通过 ping 和 ssh 跨网络访问 cirros-vm2:

    5)下面我们将举行如下实验:a)创建一个不包罗任何 rule 的 firewall “test_firewall” 并应用到 test_router。此时 FWaaS 生效,默认环境下会阻止任何跨子网的流量。b)创建 rule 允许 ssh,并将其添加到 test_firewall。此时 cirros-vm1 应该能够 ssh cirros-vm2。
    6)应用无 rule 的 firewall ,点击菜单 Project -> Network -> Firewalls,打开 Firewall Policies 标签页面,目前没有定义任何 Policy:

    7)点击Add Policy显示Policy创建页面,将 Policy 定名为 “test_policy”,直接点击 “Add” 按钮:

    8)如许我们创建的 test_policy 不包罗任何 Rule:

    9)进入 “Firewalls” 标签页,点击 “Create Firewall” 按钮:

    10)将新的 Firewall 定名为 “test_firewall”,并关联 “test_policy”:

    11)在 “Routers” 标签页中选择 “test_router”,点击 “Add” 创建 firewall:

    12)等待 test_firewall 的 Status 变为 “Active”,此时 test_router 已经成功应用 test_policy:

    13)通过 iptables-save 查看 router namespace 的 iptables 规则:

    14)为了让各人相识底层到底发生了什么变化,下面用 vimdiff 显示了应用 test_firewall 前后 iptables 规则的变化:

    15)分析一下规则:
    route 在转发数据包时会使用 chain:

    neutron-vpn-agen-FORWARD 的规则如下:

    我们以第一条为例,其寄义是:从 router namespace 任何一个 qr-* interface 发出的流量都会应用 chain neutron-vpn-agen-iv4e85f4601,该 chain 定义如下:

    其规则为:如果数据包的状态为 INVALID,则 DROP;如果数据包的状态为 RELATED 或 ESTABLISHED,则 ACCEPT。
    其他正常传输的数据怎么处理呢? 回到 neutron-vpn-agen-FORWARD chain 的下一条关于 router 外出数据的规则:

    neutron-vpn-agen-fwaas-defau 内容为:

    可见,数据会被丢弃。同样的道理,router 上所有进入 qr-* interface 的数据也会被丢弃。其结论是:在没有定义任何 firewall rule 的环境下,进出 router 的数据包都会被丢弃。
    16)ping 和 ssh 测试表明目前 cirros-vm1 确实已经无法与 cirros-vm2 通讯:

  • 举行实践,允许 SSH:
    1)添加一条 firewall rule,允许 ssh,在 Firewall Rules 标签页面点击 “Add Rule” 按钮:

    2)将新 rule 定名为 “allow ssh”, Protocal 选择 “TCP”, Action 为 “ALLOW”,Destination Port/Port Range 为 “22”:

    3)点击 “Add” ,rule 创建成功:

    4)接下来将 rule 添加到 policy 中 。点击 Firewall Policies 标签页面,然后点击 “test_policy” 后面的 “Insert Rule” 按钮:


    5)在下拉框中选择 Rule “allow ssh”,点击 “Save Changes”,可以看到,“allow ssh” 已经成功添加到 “test_policy” 中:

    6)通过 vimdiff 查看 router namespace 的 iptables-save 发生了什么变化:

    7)iptables 添加了两条规则:

    其寄义是进出 router 的 tcp 数据包,如果目的端口为 22(ssh)ssh,则同等 ACCEPT。
    8)测试一下,cirros-vm1 已经可以 ssh cirros-vm2,但 ping 还是不通,这与预期同等:

    “allow ssh” 已经起作用。同时我们也发现,firewall rule 对进出流量同时生效,不区分方向。
  • FWaaS 用于增强 Neutron 网络的安全性,与安全组可以配合使用,FWaaS 和安全组做个比较:
    1)相同点:底层都是通过 iptables 实现。
    2)不同点:a)FWaaS 的 iptables 规则应用在 router 上,保护整个租户网络。安全组则应用在虚拟网卡上,保护单个 instance; b)FWaaS 可以定义 allow 或者 deny 规则,安全组只能定义 allow 规则;c)目前 FWaaS 规则不能区分进出流量,对双向流量都起作用,安全组规则可以区分 ingress 和 egress。
2.5.5.11 Load Balancing as a Service

  2.5.6 Open vSwitch实现Neutron网络



  • 基础环境:
    实验环境两节点的网卡分配方式与 Linux Bridge 同等,如下所示:

    1)控制节点三个网卡(eth0, eth1, eth2),计算节点两网卡(eth0, eth1)。
    2)合并 Management 和 API 网络,使用 eth0,IP 段为 192.168.104.0/24。
    3)VM 网络使用 eht1。
    4)控制节点的 eth2 与 External 网络毗连,IP 段为 10.10.10.0/24。
  • 网络拓扑:

    这个图在 Linux Bridge 实现中也看到过,唯一的区别是:对于节点中的 “Virtual Network Switch” 我们将用 Open vSwitch 更换掉 Linux Bridge。
  • 设置 openvswitch mechanism driver:
    要将 Liunx Bridge 切换成 Open vSwitch,首先必要安装 Open vSwitch 的 agent,修改 devstack 的 local.conf:

    重新运行 ./stack,devstack 会自动下载并安装 Open vSwitch。接下来就可以修改 ML2 的设置文件 /etc/neutron/plugins/ml2/ml2_conf.ini,设置使用 openvswitch mechanism driver:

    控制节点和计算节点都必要按照上面的方法安装并设置 Open vSwitch。Neutron 服务重启后,可以通过 neutron agent-list 下令查看到 neutron-openvswitch-agent 已经在两个节点上运行:

  • 初始网络状态:
    1)控制节点:

    ifconfig 显示控制节点上有三个网桥 br-ex,br-int 和 br-tun。从定名上看我们大抵能猜出他们的用途:
    a)br-ex:毗连外部(external)网络的网桥
    b)br-int:集成(integration)网桥,所有 instance 的虚拟网卡和其他虚拟网络装备都将毗连到该网桥。
    c)br-tun:隧道(tunnel)网桥,基于隧道技术的 VxLAN 和 GRE 网络将使用该网桥举行通讯。
    这些网桥都是 Neutron 自动为我们创建的,但是通过 brctl show 下令却看不到它们。 这是因为我们使用的是 Open vSwitch 而非 Linux Bridge,必要用 Open vSwitch 的下令 ovs-vsctl show 查看,如下图所示:

    2)计算节点
    计算节点上也有 br-int 和 br-tun,但没有 br-ext。这是公道的,因为发送到外网的流量是通过网络节点上的虚拟路由器转发出去的,以是 br-ext 只会放在网络节点(devstack-controller)上。


  • 相识 Open vSwitch 环境中的各种网络装备。在 Open vSwitch 环境中,一个数据包从 instance 发送到物理网卡大抵会经过下面几个类型的装备:
    1)tap interface:定名为 tapXXXX;
    2)linux bridge:定名为 qbrXXXX;
    3)veth pair:定名为 qvbXXXX, qvoXXXX;
    4)OVS integration bridge:定名为 br-int;
    5)OVS patch ports:定名为 int-br-ethX 和 phy-br-ethX(X 为 interface 的序号);
    6)OVS provider bridge:定名为 br-ethX(X 为 interface 的序号);
    7)物理 interface:定名为 ethX(X 为 interface 的序号);
    8)OVS tunnel bridge:定名为 br-tun,OVS provider bridge:会在 flat 和 vlan 网络中使用;OVS tunnel bridge 则会在 vxlan 和 gre 网络中使用。
  • Open vSwitch 支持 local, flat, vlan, vxlan 和 gre 所有五种 network type。
2.5.6.1 local network



  • local network 的特点是不会与宿主机的任何物理网卡相连,也不关联任何的 VLAN ID。对于每个 local netwrok,ML2 linux-bridge 会创建一个 bridge,instance 的 tap 装备会毗连到 bridge。位于同一个 local network 的 instance 会毗连到相同的 bridge,如许 instance 之间就可以通讯了。因为 bridge 没有与物理网卡毗连,以是 instance 无法与宿主机之外的网络通讯。同时因为每个 local network 有自己的 bridge,bridge 之间是没有连通的,以是两个 local network 之间也不能通讯。
  • 创建第一个local network:
    1)进入菜单 Admin -> Networks,点击 “Create Network” 按钮:

    2)显示创建页面:

    “Provider Network Type” 选择 “Local”,点击 “Create Network”,first_local_net 创建成功;

    3)点击 first_local_net 链接,进入 network 设置页面,目前还没有 subnet,点击 “Create Subnet” 按钮:

    4)设置 IP 地址为 “172.16.1.0/24”:

    5)点击 “Next”,勾选 “Enable DHCP”,IP 池设置为 “172.16.1.2,172.16.1.99”:

    6)点击 “Create”,subnet 创建成功:

    7)同时 devstack-controler 针对此 subnet 的 DHCP 服务也已经 Active:

    8)底层网络发生了什么变化,打开控制节点的 shell 终端,用 ovs-vsctl show 查看当前 Open vSwitch 的状态:

    9)可以看到 Neutron 自动在 br-int 网桥上创建了 port “tap7970bdcd-f2”。从定名可知,该 port 对应 local_net 的 dhcp 接口。与 linux bridge driver 一样,dhcp 装备也是放在定名空间里的:

    10)目前网络布局如下图所示:

  • 将 Instance 部署到 OVS Local Network:
    1)launch 一个 instance,选择 first_local_net 网络:

    2)instance 部署成功,分配的 IP 地址为 172.16.1.3:

    3)如上图所示,port 列表中增加了一个 port “(fc1c6ebb-719d)”,IP 为 172.16.1.3,点击 port 名称查看 MAC 信息:

    4)Open vSwitch driver 会怎样将 cirros-vm1 毗连到 first_local_net? 如果接纳类似的实现方法,neutron-openvswitch-agent 会根据 port 信息创建 tap 装备 tapfc1c6ebb-71,并将其毗连到 br-int 网桥,tapfc1c6ebb-71 就是 cirros-vm1 的虚拟网卡。cirros-vm1 部署到了控制节点,通过 ovs-vsctl show 查看 bridge 的设置:

    非常遗憾,在 br-int 上并没有看到 tapfc1c6ebb-71,而是多了一个 qvofc1c6ebb-71。目前我们并不知道 qvofc1c6ebb-71 是什么,我们再用 brctl show 查看一下 linux bridge 的设置:

    这里我们看到有一个新建的网桥 qbrfc1c6ebb-71,上面毗连了两个装备 qvbfc1c6ebb-71 和 tapfc1c6ebb-71。从定名上看,他们都应该与 cirros-vm1 的虚拟网卡有关。
    5)通过 virsh edit 查看 cirros-vm1 的设置:

    确实 tapfc1c6ebb-71 是 cirros-vm1 的虚拟网卡。那么 linux bridge qbrfc1c6ebb-71 上的 qvbfc1c6ebb-71 装备与 Open vSwitch br-int 上的 qvofc1c6ebb-71 是什么关系呢?
    6)我们用 ethtool -S 分别查看 qvbfc1c6ebb-71 和 qvofc1c6ebb-71 的 statistics:

    原来 qvbfc1c6ebb-71 和 qvofc1c6ebb-71 都是 veth 装备,它们对应的另一端 veth 装备 的 index 分别是 12 和 13。
    7)通过 ip a 下令找到 index 12 和 13 的装备:

    实在qvbfc1c6ebb-71 和 qvofc1c6ebb-71 组成了一个 veth pair。veth pair 是一种成对出现的特殊网络装备,它们像一根虚拟的网线毗连两个网络装备。这里 qvbfc1c6ebb-71 和 qvofc1c6ebb-71 的作用就是毗连网桥 qbrfc1c6ebb-71 和 br-int。
    8)拓扑布局如下所示:

    由图所示,tapfc1c6ebb-71 通过 qbrfc1c6ebb-71 间接毗连到 br-int。
    9)为什么 tapfc1c6ebb-71 不能像左边的 DHCP 装备 tap7970bdcd-f2 那样直接毗连到 br-int 呢?
    其原因是: Open vSwitch 目前还不支持将 iptables 规则放在与它直接相连的 tap 装备上。如果做不到这一点,就无法实现 Security Group 功能。为了支持 Security Group,不得不多引入一个 Linux Bridge 支持 iptables。如许的后果就是网络布局更复杂了,路径上多了一个 linux bridge 和 一对 veth pair 装备。
  • 再部署一个 Instance 和 Local Network:
    1)再部署一个 Instance 到first_local_network,以同样的方式 launch instance “cirros-vm2”,分配的 IP 为 172.16.1.4:

    2)cirros-vm2 也被 schedule 到控制节点,ovs-vsctl show 的输出如下:

    3)cirros-vm2 对于的 tap 装备为 tapddbbb728-93:

    4)从 cirros-vm2 能够 Ping 通 cirros-vm1 的 IP 地址 172.16.1.3:

    5)当前宿主机的网络布局如下 :

    两个 instance 都挂在 br-int 上,可以相互通讯。
    6)创建第二个 local network:
    为了分析 local network 的连通性,我们再创建一个 “second_local_net”,second_local_net 的绝大部分属性与 first_local_net 相同,除了 IP 池范围为 172.16.1.101-172.16.1.200:

    second_local_net 的 DHCP 装备也已经停当:

    DHCP 对应的 tap 装备为 tap2c1b3c58-4e,已经毗连到 br-int:

  • 部署instance到second_local_network
    1)launch 新的 instance “cirros-vm3”,网络选择 second_local_net:

    2)cirros-vm3 分配到的 IP 为 172.16.1.102:

    3)cirros-vm3 被 schedule 到控制节点,其虚拟网卡也毗连到 br-int:


    4)当前的控制节点上的网络布局如下 :

    5)下面我们讨论一个有趣的题目:cirros-vm3 能否 Ping 到 cirros-vm1 呢?根据我们在 linux bridge 中学到的知识,既然 cirros-vm3 和 cirros-vm1 都毗连到同一个网桥 br-int,那么它们之间应该是可以 Ping 通的。但另一方面,根据 Neutron 的计划,不同 local 网络之间是无法通讯的。那么究竟到底是怎样呢?

    实验证实 cirros-vm3 无法 Ping 到 cirros-vm1。
    6)下面我们必要表明同一个网桥上的 port 为什么不能通讯,让我们重新审阅一下 br-int 上各个 port 的设置。

    这次我们注意到,虚拟网卡和 DHCP 对应的 port 都有一个特殊的 tag 属性。first_local_net 相干 port 其 tag 为 1;second_local_net 相干 port 其 tag 为 2。玄机就在这里了: Open vSwitch 的每个网桥都可以看作一个真正的交换机,可以支持 VLAN,这里的 tag 就是 VLAN ID。br-int 中标志 tag 1 的 port 和 标志 tag 2 的 port 分别属于不同的 VLAN,它们之间是隔离的。必要特别说明的是: Open vSwitch 中的 tag 是内部 VLAN,用于隔离网桥中的 port,与物理网络中的 VLAN 没有关系。
    7)我们将 tag 信息添加到网络布局图中,如下所示:

2.5.6.2 flat network



  • flat network 是不带 tag 的网络,要求宿主机的物理网卡直接与 linux bridge 毗连,这意味着:每个 flat network 都会独占一个物理网卡。
  • 在ML2中设置 enable flat network
    1)在控制节点 /etc/neutron/plugins/ml2/ml2_conf.ini 中设置 flat network 相干参数:

    指定平凡用户创建的网络类型为 flat。必要注意的是:因为 flat 网络与物理网卡一一对应,一般环境下租户网络不会接纳 flat,这里只是示例。接着必要指明 flat 网络与物理网络的对应关系:


    如上所示:在 [ml2_type_flat] 中通过 flat_networks 定义了一个 flat 网络,label 为 “default”。在 [ovs] 中通过 bridge_mappings 指明 default 对应的 Open vSwitch 网桥为 br-eth1。
    label 是 flat 网络的标识,在创建 flat 时会用到,label 的名字可以是恣意字符串,只要确保各个节点 ml2_conf.ini 中的 label 定名同等就可以了。各个节点中 label 与物理网卡的对于关系可能不一样。这是因为每个节点可以使用不同的物理网卡将 instance 毗连到 flat network。与 linux bridge 实现的 flat 网络不同,ml2 中并不会直接指定 label 与物理网卡的对应关系,而是指定 label 与 ovs bridge 的对应关系。
    2)这里的 ovs bridge 是 br-eth1,我们必要提前通过 ovs-vsctl add-br br-eth1和ovs-vsctl add-port br-eth1 eth1 下令创建 br-eth1。将物理网卡 eth1 桥接在 br-eth1 上。

    3)如果要创建多个 flat 网络,必要定义多个 label,用逗号隔开,当然也必要用到多个 ovs bridge,如下所示:

    4)计算节点也必要做相同的设置,然后重启所有节点的 Neutron 服务,通过ovs-vsctl show检视一下当前的网络布局:

    对于 ovs bridge “br-eth1” 和其上桥接的 port “eth1” 我们应该不会感到不测,这是前面设置的结果。然而除此之外,br-int 和 br-eth1 分别多了一个 port “int-br-eth1” 和 “phy-br-eth1”,而且这两个 port 都是 “patch” 类型,同时通过 “peer” 指向对方。上面的设置形貌了如许一个究竟:br-int 与 br-eht1 这两个网桥通过 int-br-eth1 和 phy-br-eth1 毗连在一起了。
    5)目前控制节点网络布局如下:

    6)veth pair VS patch port:
    在前面 local network 我们看到,br-int 与 linux bridge 之间可以通过 veth pair 毗连。

    而这里两个 ovs bridge 之间是用 patch port 毗连的。看来 veth pair 和 patch port 都可以毗连网桥,使用的时候怎样选择呢?patch port 是 ovs bridge 自己特有的 port 类型,只能在 ovs 中使用。如果是毗连两个 ovs bridge,优先使用 patch port,因为性能更好。以是:a)毗连两个 ovs bridge,优先使用 patch port。技术上veth pair 也能实现,但性能不如 patch port。b)毗连 ovs bridge 和 linux bridge,只能使用 veth pair。c)毗连两个 linux bridge,只能使用 veth pair。
  • 创建 OVS Flat Network:
    1)Admin -> Networks,点击 “Create Network” 按钮:

    显示创建页面:

    Provider Network Type 选择 “Flat”。
    Physical Network 填写 “default”,与 ml2_conf.ini 中 flat_networks 参数值保持同等。
    2)点击 “Create Network”,flat_net 创建成功:

    3)点击 flat_net 链接,进入 network 设置页面,目前还没有 subnet。点击 “Create Subnet” 按钮:

    4)设置 IP 地址为 “172.16.1.0/24”:

    5)点击 “Next”,勾选 “Enable DHCP”:

    6)点击 “Create”,subnet 创建成功:

    7)查看控制节点的网络布局,执行 ovs-vsctl show:

    Neutron 自动在 br-int 网桥上创建了 flat-net dhcp 的接口 “tap83421c44-93”。
    8)此时 flat_net 布局如图所示:

  • 部署 Instance 到ovs flat network:
    1)launch 新的 instance “cirros-vm1”,网络选择 falt_net:

    2)cirros-vm1 分配到的 IP 为 172.16.1.3:

    3)cirros-vm1 被 schedule 到控制节点,其虚拟网卡也毗连到 br-int:


    虚拟网卡与 br-int 的毗连方式与 local 网络是一样的,不再赘述。
    4)当前 flat_net 的布局如下:

    5)继续用同样的方式 launch instance cirros-vm2,分配到的 IP 为 172.16.1.4:

    6)cirros-vm2 被 schedule 到计算节点,虚拟网卡已经毗连到 br-int:


    因为计算节点上没有 hdcp 服务,以是没有相应的 tap 装备。
    7)当前 flat_net 的布局如下:

    cirros-vm1(172.16.1.3) 与 cirros-vm2(172.16.1.4) 位于不同节点,通过 flat_net 相连,下面验证连通性。
    8)在 cirros-vm2 控制台中 ping 172.16.1.3:

    如我们预料两台虚拟机位于同一个flat network中,以是可以ping 成功。
2.5.6.3 vlan network



  • vlan network 是带 tag 的网络。在 Open vSwitch 实现方式下,不同 vlan instance 的虚拟网卡都接到 br-int 上。这一点与 linux bridge 非常不同,linux bridge 是不同 vlan 接到不同的网桥上。
  • 在我们的实验环境中,收发 vlan 数据的物理网卡为 eth1,上面可以走多个 vlan,以是物理交换机上与 eth1 相连的的 port 要设置成 trunk 模式,而不是 access 模式。
  • 在 ML2 设置中 enable vlan network:
    1)在 /etc/neutron/plugins/ml2/ml2_conf.ini 设置 vlan network 相干参数,指定平凡用户创建的网络类型为 vlan:

    2)指定 vlan 的范围:

    上面设置定义了 label 为 “default” 的 vlan network,vlan id 的范围是 3001 – 4000。
    这个范围是针对平凡用户在自己的租户里创建 network 的范围。因为平凡用户创建 network 时并不能指定 vlan id,Neutron 会按顺序自动从这个范围中取值。对于 admin 则没有 vlan id 的限定,admin 可以创建 id 范围为 1-4094 的 vlan network。
    3)接着必要指明 vlan 网络与物理网络的对应关系:

    如上所示:在 [ml2_type_vlan] 中定义了 lable “default”,[ovs] 中则通过 bridge_mappings 指明 default 对应的 Open vSwitch 网桥为 br-eth1。这里 label 的作用与前面 flat network 中的 label 一样,只是一个标示,可以是任何字符串
    4)我们必要提前通过 ovs-ovctl 下令创建 br-eth1,并将物理网卡 eth1 桥接在 br-eth1 上。

  • 创建 OVS Vlan100 Netwrok:
    1)打开菜单 Admin -> Networks,点击 “Create Network” 按钮:

    显示创建页面:

    Provider Network Type 选择 “VLAN”。
    Physical Network 填写 “default”,与 ml2_conf.ini 中 network_vlan_ranges 参数值保持同等。
    Segmentation ID 即 VLAN ID,设置为 100。
    2)点击 “Create Network”,vlan100 创建成功:

    3)点击 vlan100 链接,进入 network 设置页面,目前还没有 subnet,点击 “Create Subnet” 按钮:

    4)创建 subnet_172_16_100_0,IP 地址为 172.16.100.0/24:


    5)在控制节点上执行 ovs-vsctl show,查看网络布局:

    Neutron 自动在 br-int 网桥上创建了 vlan100 dhcp 的接口 “tap43567363-50”。
    6)此时 vlan100 布局如图所示:

  • 部署 Instance 到vlan100:
    1)launch 新的 instance “cirros-vm1”,网络选择 vlan100:

    2)cirros-vm1 分配到的 IP 为 172.16.100.3:

    3)cirros-vm1 被 schedule 到控制节点,其虚拟网卡也毗连到 br-int:


    虚拟网卡与 br-int 的毗连方式与 local 和 flat 网络一样。
    4)当前 vlan100 的布局如下:

    5)继续用同样的方式 launch instance cirros-vm2,分配到的 IP 为 172.16.100.104:

    6)cirros-vm2 被 schedule 到计算节点,虚拟网卡已经毗连到 br-int:


    因为计算节点上没有 hdcp 服务,以是没有相应的 tap 装备。
    7)当前 vlan100 的布局如下:

    8)cirros-vm1(172.16.100.3) 与 cirros-vm2(172.16.100.4) 位于不同节点,通过 vlan100 相连,下面执行 PING 验证连通性。在 cirros-vm1 控制台中执行 ping 172.16.100.4:

  • 创建vlan 101并部署instance:
    1)创建vlan 101:

    2)subnet IP 地址为 172.16.101.0/24:

    3)Neutron 自动在 br-int 网桥上创建了 vlan100 dhcp 的接口 “tap1820558c-0a”:

    4)如今,网络布局如下:

    5)将 instance 毗连到 vlan101,unch 新的 instance “cirros-vm3”,网络选择 vlan101:

    6)cirros-vm3 分配到的 IP 为 172.16.101.103 :

    7)cirros-vm3 被 schedule 到计算节点,虚拟网卡已经毗连到 br-int:


    8)当前网络布局如下:

    cirros-vm1 位于控制节点,属于 vlan100。 cirros-vm2 位于计算节点,属于 vlan100。cirros-vm3 位于计算节点,属于 vlan101。cirros-vm1 与 cirros-vm2 都在 vlan100,它们之间能通讯。cirros-vm3 在 vlan101,不能与 cirros-vm1 和 cirros-vm2 通讯。
  • 分析 OVS 怎样实现 vlan 隔离:
    1)之前完成的OVS vlan 环境的搭建,当前拓扑布局如下所示:
    a)cirros-vm1 位于控制节点,属于 vlan100;
    b)cirros-vm2 位于计算节点,属于 vlan100;
    c)cirros-vm3 位于计算节点,属于 vlan101。

    2)详细分析 OVS 怎样实现 vlan100 和 vlan101 的隔离:
    与 Linux Bridge driver 不同,Open vSwitch driver 并不通过 eth1.100, eth1.101 等 VLAN interface 来隔离不同的 VLAN。
    所有的 instance 都毗连到同一个网桥 br-int,Open vSwitch 通过 flow rule(流规则)来指定怎样对进出 br-int 的数据举行转发,进而实现 vlan 之间的隔离。详细来说:当数据进出 br-int 时,flow rule 可以修改、添加或者剥掉数据包的 VLAN tag,Neutron 负责创建这些 flow rule 并将它们设置到 br-int,br-eth1 等 Open vSwitch 上。
    3)下面我们就来研究一下当前的 flow rule,查看 flow rule 的下令是 ovs-ofctl dump-flow <bridge>:

    br-eth1 上设置了四条 rule,每条 rule 有不少属性,其中比较紧张的属性有:
    a)priority:rule 的优先级,值越大优先级越高。Open vSwitch 会按照优先级从高到低应用规则。
    b)in_port:inbound 端口编号,每个 port 在 Open vSwitch 中会有一个内部的编号。可以通过下令 ovs-ofctl show <bridge> 查看 port 编号。
    好比 br-eth1:

    eth1 编号为 1;phy-br-eth1 编号为 2。
    c)dl_vlan:数据包原始的 VLAN ID。
    d)actions:对数据包举行的操作。
    br-eth1 跟 VLAN 相干的 flow rule 是前面两条,下面我们来详细分析。清晰起见,我们只保留紧张的信息,如下:

    第一条的寄义是:从 br-eth1 的端口 phy-br-eth1(in_port=2)接收进来的包,如果 VLAN ID 是 1(dl_vlan=1),那么必要将 VLAN ID 改为 100(actions=mod_vlan_vid:100)

    从上面的网络布局我们可知,phy-br-eth1 毗连的是 br-int,phy-br-eth1 的 inbound 包实际上就是 instance 通过 br-int 发送给物理网卡的数据。
    4)那么怎么理解将 VLAN ID 1 改为 VLAN ID 100 呢?
    请看下面计算节点 ovs-vsctl show 的输出:

    br-int 通过 tag 隔离不同的 port,这个 tag 可以当作内部的 VLAN ID。从 qvo4139d09b-30(对应 cirros-vm2,vlan100)进入的数据包会被打上 1 的 VLAN tag。从 qvo98582dc9-db(对应 cirros-vm3,vlan101)进入的数据包会被打上 5 的 VLAN tag。因为 br-int 中的 VLAN ID 跟物理网络中的 VLAN ID 并不相同,以是当 br-eth1 接收到 br-int 发来的数据包时,必要对 VLAN 举行转换。Neutron 负责维护 VLAN ID 的对应关系,并将转换规则设置在 flow rule 中。
    5)理解了 br-eth1 的 flow rule,我们再来分析 br-int 的 flow rule:

    最关键的是下面两条:


    port 1 为 int-br-eth1,那么这两条规则的寄义就应该是:
    a)从物理网卡接收进来的数据包,如果 VLAN 为 100,则改为内部 VLAN 1。
    b)从物理网卡接收进来的数据包,如果 VLAN 为 101,则将为内部 VLAN 5。
    简单的说,数据包在物理网络中通过 VLAN 100 和 VLAN 101 隔离,在计算节点 OVS br-int 中则是通过内部 VLAN 1 和 VLAN 5 隔离。
2.5.6.4 Routing



  • Neutron Routing 服务提供跨 subnet 互联互通的本事。
    比方前面我们搭建了实验环境:
    cirros-vm1 172.16.100.3 vlan100
    cirros-vm3 172.16.101.3 vlan101
    这两个 instance 要通讯必须借助 router。可以是物理 router 或者虚拟 router。
  • 详细讨论 Neutron 的虚拟 router 实现:
    1)设置 l3 agent,Neutron 的路由服务是由 l3 agent 提供的。
    l3 agent 必要正确设置才气工作,设置文件为 /etc/neutron/l3_agent.ini,位于控制节点或网络节点:

    external_network_bridge 指定毗连外网的网桥,默认是 br-ex。
    interface_driver 是最紧张的选项,如果 mechanism driver 是 open vswitch,则:

    如果选用 linux bridge,则:

    2)l3 agent 运行在控制或网络节点,接纳neutron agent-list下令查询:

    3)创建虚拟 router “router_100_101”,买通 vlan100 和 vlan101:
    进入操作菜单 Project -> Network -> Routers:

    4)点击 “Create Router” 按钮:

    5)outer 定名为 “router_100_101”,点击 “Create Router” 按钮确认:

    6)router_100_101 创建成功:

    7)接下来必要将 vlan100 和 vlan101 毗连到 router_100_101。点击 “router_100_101” 链接进入 router 的设置页面,在 “Interfaces” 标签中点击 “Add Interface” 按钮:

    8)选择 vlan100 的 subnet_172_16_100_0,点击 “Add Interface” 确认:

    9)用同样的方法添加 vlan101 的 subnet_172_16_101_0:

    完成后,可以看到 router_100_101 有了两个 interface,其 IP 恰恰是 subnet 的 Gateway IP 172.16.100.1 和 172.16.101.1。
    10)到这里,router_100_101 已经毗连了subnet_172_16_100_0 和subnet_172_16_101_0。router_100_101 上已经设置好了两个 subnet 的 Gateway IP。cirros-vm1 和 cirros-vm3 应该可以通讯了。

    不出所料,cirros-vm1 和 cirros-vm3 能通讯了。
  • Neutron Router 工作原理:
    1)先查看控制节点的网络布局发生了什么变化:

    br-int 上多了两个 port:
    a)qr-d295b258-45,从定名上可以推断该 interface 对应 router_100_101 的 interface (d295b258-4586),是subnet_172_16_100_0 的网关。
    b)qr-2ffdb861-73,从定名上可以推断该 interface 对应 router_100_101 的 interface (2ffdb861-731c),是subnet_172_16_101_0 的网关。
    2)与 linux bridge 实现方式一样, router_100_101 运行在自己的 namespace 中:

    如上所示,qrouter-a81cc110-16f4-4d6c-89d2-8af91cec9714 为 router 的 namespace,两个 Gateway IP 分别设置在 qr-2ffdb861-73 和 qr-d295b258-45 上。
    3)当前网络布局如图所示:

route_101_101 上设置了 vlan100 和 vlan101 的网关,两个网络在三层上就通了。



  • 访问外网,这里的外部网络是指的租户网络以外的网络。租户网络是由 Neutron 创建和维护的网络。 外部网络不由 Neutron 创建。如果是私有云,外部网络通常指的是公司 intranet;如果是公有云,外部网络通常指的是 internet
    1)详细到我们的实验网络环境,计算节点和控制节点 eth1 提供的是租户网络,IP 段租户可以自由设置。控制节点 eth2 毗连的就是外部网络,IP 网段为 10.10.10.2/24。如下图所示:

    2)设置准备:
    为了毗连外部网络,必要预先在设置文件中告诉 Neutron 外部网络的类型以及对应的 Open vSwitch 网桥。外部网络是已经存在的物理网络,一般都是 flat 或者 vlan 类型。这里我们将外部网络的 label 定名为 “external”,网桥为 br-ex。
    a)如果类型为 flat,控制节点/etc/neutron/plugins/ml2/ml2_conf.ini 设置如下:

    b)如果类型为 vlan,设置如下:

    在我们的网络环境中,外部网络是 flat 类型。 修改设置后,必要重启 neutron 的相干服务。另外,我们必要提前准备好 br-ex,将 eth2 添加到 br-ex:

    br-ex 已经存在,我们只必要添加 eth2。
    3)创建ext_net:
    a)进入 Admin -> Networks 菜单,点击 “Create Network” 按钮:

    显示创建页面:

    Provider Network Type 选择 “Flat”。
    Network 填写 “external”,与 ml2_conf.ini 中 flat_networks 的参数值保持同等。
    勾选 External Network 选择框。
    b)点击 “Create Network”,ext_net 创建成功:

    c)点击 ext_net 链接,进入 network 设置页面,目前还没有 subnet。点击 “Create Subnet” 按钮:

    d)创建 subnet_10_10_10_0,IP 地址为 10.10.10.0/24:

    这里 Gateway 我们使用默认地址 10.10.10.1。
    通常我们必要询问网络管理员外网 subnet 的 Gateway IP,然后填在这里。
    e)点击 “Next”:

    因为我们不会直接为 instance 分配外网 IP,以是不必要 enable DHCP。
    f)点击 “Create”:

    subnet 创建成功,网关为 10.10.10.1。
    g)下面查看控制节点网络布局的变化,执行 ovs-vsctl show下令:

    上图所示,br-ex 与 br-int 通过 patch port “phy-br-ex” 和 “int-br-ex” 毗连。
    3)接下来必要将ext_net毗连到 Neutron 的router,如许 instance 才气访问外网:
    a)点击菜单 Project -> Network -> Routers 进入 router 列表:

    b)点击 router_100_101 的 “Set Gateway” 按钮 :

    c)在 “External Network” 下拉列表中选择 ext_net,点击 “Set Gateway”:

    d)外网设置成功。点击 “router_100_101” 链接,打开 “Interfaces” 标签页:

    router 多了一个新 interface,IP 为 10.10.10.2。
    该 interface 用于毗连外网 ext_net,对应的 br-ex 的 port “qg-cf54d3ea-6a”。

    e)在 router 的 namespace 中查看到 qg-cf54d3ea-6a 已经设置了 IP 10.10.10.2:

    router interface 的定名规则如下:
    i)如果 interface 用于毗连租户网络,定名格式为 qr-xxx。
    ii)如果 interface 用于毗连外部网络,定名格式为 qg-xxx。
    f)查看 router 的路由表信息:

    可以看到默认网关为 10.10.10.1。
    意味着对于访问 vlan100 和 vlan101 租户网络以外的所有流量,router_100_101 都将转发给 ext_net 的网关 10.10.10.1。
    g)如今 router_100_101 已经同时毗连了 vlan100, vlan101 和 ext_net 三个网络,如下图所示:

    h)我们在 cirros-vm3 上测试一下:

    cirros-vm3 位于计算节点,如今已经可以 Ping 到 ext_net 网关 10.10.10.1 了。
    i)通过 traceroute <IP Address>下令 查看一下 cirros-vm3 到 10.10.10.1 的路径:

    数据包经过两跳到达 10.10.10.1 网关。
    i)数据包首先发送到 router_100_101 毗连 vlan101 的 interface(172.16.101.1)。
    ii)然后通过毗连 ext_net 的 interface(10.10.10.2) 转发出去,末了到达 10.10.10.1。
    当数据包从 router 毗连外网的接口 qg-cf54d3ea-6a 发出的时候,会做一次 Source NAT,将包的源地址修改为 router的接口地址 10.10.10.2,如许就能够保证目的端能够将应答的包发回给 router,然后再转发回源端 instance。
  • floating IP
    1)通过 SNAT 使得 instance 能够直接访问外网,但外网还不能直接访问 instance。
    2)直接访问 instance 指的是通讯毗连由外网发起,比方从外网 SSH instance。
    如果必要从外网直接访问 instance,可以利用 floating IP。
    3)Open vSwitch driver 环境中 floating IP 的实现与 Linux Bridge driver 完全一样:都是通过在 router 提供网关的外网 interface 上设置 iptables NAT 规则实现。
    4)有关 floating IP 的详细分析可以参考 Linux Bridge 中 floating IP 的相干章节。
2.5.6.5 vxlan network



  • Open vSwitch 支持 VXLAN 和 GRE 这两种 overlay network。因为 OpenStack 对于 VXLAN 与 GRE 设置和实现差别不大,这里只讨论怎样实施 VXLAN。
  • ML2设置ovs vxlan:
    1)在 ML2 设置中 enable vxlan network,在 /etc/neutron/plugins/ml2/ml2_conf.ini 设置 vxlan network 相干参数:

    2)指定平凡用户创建的网络类型为 vxlan,同时 enable l2 population mechanism driver,然后指定 vxlan 的范围(L2 Population 是用来提高 VXLAN 网络 Scalability 的。通常我们说某个体系的 Scalability 好,其意思是:当体系的规模变大时,仍然能够高效地工作。):

    上面设置定义了 vxlan vni 的范围是 1001 – 2000,这个范围是针对平凡用户在自己的租户里创建 vxlan network 的范围。 因为平凡用户创建 network 时不能指定 vni,Neutron 会按顺序自动从这个范围中取值。对于 admin 则没有 vni 范围的限定,admin 可以创建 vni 范围为 1-16777216 的 vxlan network。
    3)在 [agent] 中设置启用 vxlan 和 l2population:

    4)末了在 [ovs] 中设置 VTEP:

    vxlan tunnel 对应的网桥为 br-tun。
    local_ip 指定 VTEP 的 IP 地址。
    devstack-controller 使用 166.66.16.10,此 IP 设置在网卡 eth1 上。
    devstack-compute01 则使用 166.66.16.11,此 IP 设置在网卡 eth1 上。

  • 初始网络布局:
    Neutron 服务重启后,通过 ovs-vsctl show 查看网络设置:

    br-int 与 br-tun 通过 patch port “patch-tun” 和 “br-tun” 毗连。
  • 目前网络布局如下所示:

  • 创建vxlan 100_net,并将instance毗连到此网络上:
    1)创建 vxlan100_net:
    打开菜单 Admin -> Networks,点击 “Create Network” 按钮:

    2)显示创建页面:

    Provider Network Type 选择 “VXLAN”。
    Segmentation ID 即 VNI,设置为 100。
    3)点击 “Create Network”,vxlan100 创建成功:

    4)点击 vxlan100 链接,进入 network 设置页面,目前还没有 subnet。点击 “Create Subnet” 按钮:

    5)创建 subnet_172_16_100_0,IP 地址为 172.16.100.0/24:


    6)将 instance 毗连到 vxlan100_net。launch 新的 instance “cirros-vm1”,“cirros-vm2” 网络选择 vxlan100:

    7)cirros-vm1,cirros-vm2 分别部署到控制节点和计算节点,IP 如下:

    8)测试 cirros-vm1 和 cirros-vm2 的连通性:

  • 底层网络布局分析:
    1)在控制节点,执行 ovs-vsctl show:

    a)br-int:
    br-int 毗连了如下 port:
    i)tap0d4cb13a-7a 是 vxlan100_net 的 DHCP 服务对应的 interface。
    ii)qvoa2ac3b9a-24 将 cirros-vm1 虚拟网卡毗连到 vxlan100_net。
    b)br-tun:
    br-tun 上创建了一个特殊的 port “vxlan-a642100b”,它是 VXLAN 的隧道端点,指定了本地(devstack-controller)节点和远端(devstack-compute1)节点 VTEP 的 IP
    2)在计算节点,执行 ovs-vsctl show:

    a)br-int:
    br-int 上 qvoab219616-01 将 cirros-vm2 虚拟网卡毗连到 vxlan100_net。
    b)br-tun:
    br-tun 上也创建了 port “vxlan-a642100b”,设置内容与控制节点相对,指定了本地(devstack-compute1)节点和远端(devstack-controller)节点 VTEP 的 IP。
    3)当前网络布局如下:

    必要特别注意的是:无论存在多少个 VXLAN,devstack-controller 与 devstack-compute1 之间所有的数据都只通过 “vxlan-a642100b” 这对 port 上建立的隧道传输。
  • flow rule分析:
    1)br-int 的 flow rule:

    br-int 的 rule 看上去固然多,实在逻辑很简单,br-int 被当作一个二层交换机,其紧张的 rule 是下面这条:

    此规则的寄义是:根据 vlan 和 mac 举行转发。
  • br-tun 的 flow rule:

    这些才是真正处理 VXLAN 数据包的 rule,流程如下:

    上图各方块中的数字对应 rule 中 table 的序号,好比编号为0的方块对应下面三条 rule。
    1)table 0:

    结合如下 port 编号:

    table 0 flow rule 的寄义为:
    a)从 port 1(patch-int)进来的包,扔给 table 2 处理:actions=resubmit(,2)
    b)从 port 2(vxlan-a642100b)进来的包,扔给 table 4 处理:actions=resubmit(,4)
    即第一条 rule 处理来自内部 br-int(这上面挂载着所有的网络服务,包括路由、DHCP 等)的数据;
    第二条 rule 处理来自外部 VXLAN 隧道的数据。
    2)table 4:

    table 4 flow rule 的寄义为: 如果数据包的 VXLAN tunnel ID 为 100(tun_id=0x64),action 是添加内部 VLAN ID 1(tag=1),然后扔给 table 10 去学习。
    3)table 10:

    table 10 flow rule 的寄义为: 学习外部(从 tunnel)进来的包,往 table 20 中添加对返程包的正常转发规则,然后从 port 1(patch-int)扔给 br-int。
    4)table2:

    table 2 flow rule 的寄义为:
    a)br-int 发过来数据如果是单播包,扔给 table 20 处理:resubmit(,20)
    b)br-int 发过来数据如果是多播或广播包,扔 table 22 处理:resubmit(,22)
    5)table20:

    table 20 flow rule 的寄义为:
    a)第一条规则就是 table 10 学习来的结果。内部 VLAN 号为 1(tag=1),目标 MAC 是
    fa:16:3e:fd:8a:ed(virros-vm2)的数据包,即发送给 virros-vm2 的包,action 是去掉 VLAN
    号,添加 VXLAN tunnel ID 100(十六进制 0x64),并从 port 2 (tunnel 端口 vxlan-a642100b)
    发出。
    b)对于没学习到规则的数据包,则扔给 table 22 处理。
    6)table22:

    table 22 flow rule 的寄义为: 如果数据包的内部 VLAN 号为 1(tag=1),action 是去掉 VLAN
    号,添加 VXLAN tunnel ID 100(十六进制 0x64),并从 port 2 (tunnel 端口 vxlan-a642100b)
    发出。
  • VXLAN 的路由和 floating IP 支持
    对于多 VXLAN 之间的 routing 以及 floating IP,实现方式与 vlan 非常类似,这里不再赘述,请参看前面 vlan 相干章节。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

去皮卡多

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表