Z21-X头像
云原生运维学习笔记:OpenStack核心组件实战——从Keystone到Heat的全链路体验封面图

云原生运维学习笔记:OpenStack核心组件实战——从Keystone到Heat的全链路体验

云原生运维学习笔记:OpenStack核心组件实战——从Keystone到Heat的全链路体验

前面我们花了不少时间在KVM、华为云、存储仿真器上折腾,算是把虚拟化和公有云的基础摸了一遍。今天终于进入了OpenStack的世界,说实话,刚看到这一大堆组件名字的时候,脑子是嗡嗡的——Keystone、Glance、Nova、Cinder、Swift、Neutron、Heat,七个组件,每个都能单独讲一天。但静下心来跟着实验手册一步步做,发现其实它们之间的协作逻辑非常清晰:Keystone管认证,Glance管镜像,Nova管计算,Cinder和Swift管存储,Neutron管网络,Heat管编排。就像一个公司的各个部门,各司其职又互相配合。

这篇博客就当作我今天的实验记录,按照实际学习的顺序,把每个组件的核心概念、操作命令和实验现象都记下来。内容比较多,我尽量把每一步的命令和输出都完整呈现,方便日后复习。


一、OpenStack界面管理与命令行登录

1.1 登录Dashboard

在浏览器输入 http://192.168.108.10,输入admin账号和密码,点击登入。登录成功后默认进入admin项目的概况界面,能看到实例、VCPU、内存、卷等资源的使用情况。

左侧导航栏有“项目”、“管理员”、“身份管理”三大块。在“管理员”->“概览”里,可以按时间段查看整个系统的使用情况摘要,下面有个使用情况表格,按项目列出VCPUs、Disk、RAM等指标。在“身份管理”->“项目”里,能看到当前有两个项目:services和admin。

1.2 修改admin密码

点击右上角“admin”,选择“设置”,在左侧选择“修改密码”。输入原密码、新密码、确认密码,点击“修改”。

# 返回登录界面会提示"密码已更改,请重新登录。"
# 用新密码登录成功后,再把密码改回原密码

1.3 创建普通用户user1

在“身份管理”->“用户”页面,点击右上角“创建用户”:

  • 用户名:user1
  • 密码:自定义,我设的是huawei
  • 主项目:admin
  • 角色:_member_
# 右上角提示成功:用户"user1"成功创建。

退出admin,用user1登录,发现左侧导航栏少了“管理员”这一整块,身份管理里也少了“域”、“组”和“角色”的内容。这就是角色权限的区别——_member_角色的用户只能管自己项目内的资源,而admin角色可以看到全局管理视图。

1.4 命令行登录

用MobaXterm远程登录controller节点(192.168.108.10),root密码登录。

[root@controller ~]# source keystonerc_admin
[root@controller ~(keystone_admin)]# openstack project list
+----------------------------------+----------+
| ID                               | Name     |
+----------------------------------+----------+
| 849ccdf6e95c41f7857bee41d6252cb1 | services |
| 9dfc7c9839ea4ff387fc223cd4d61823 | admin    |
+----------------------------------+----------+

如果提示401认证失败,说明环境变量文件有问题。如果想切换到user1用户,可以复制一份环境变量文件再修改:

[root@controller ~(keystone_admin)]# cp keystonerc_admin keystonerc_user1
[root@controller ~(keystone_admin)]# vim keystonerc_user1

把内容改成:

unset OS_SERVICE_TOKEN
export OS_USERNAME=user1
export OS_PASSWORD='huawei'
export OS_REGION_NAME=RegionOne
export OS_AUTH_URL=http://192.168.108.10:5000/v3
export PS1='[\u@\h \W(keystone_user1)]\$ '

export OS_PROJECT_NAME=admin
export OS_USER_DOMAIN_NAME=Default
export OS_PROJECT_DOMAIN_NAME=Default
export OS_IDENTITY_API_VERSION=3
[root@controller ~(keystone_admin)]# source keystonerc_user1
[root@controller ~(keystone_user1)]# openstack project list
+----------------------------------+-------+
| ID                               | Name  |
+----------------------------------+-------+
| 9dfc7c9839ea4ff387fc223cd4d61823 | admin |
+----------------------------------+-------+

普通用户只能看到自己所属的项目,看不到services项目。这就是Keystone权限隔离的直观体现。


二、OpenStack认证管理-Keystone

2.1 Keystone核心概念

Keystone是OpenStack的认证服务,它做三件事:管理用户及其权限、维护Service的Endpoint、认证和鉴权。

几个核心概念必须搞清楚:

  • Domain(域) :一个虚拟概念,是一组User、Group或Project的容器。一个域可以对应一个大的机构、一个数据中心,必须全局唯一。
  • User(用户) :可以通过Keystone访问OpenStack服务的个人、系统或服务。用户不是全局唯一的,只需要在域内唯一。
  • Group(用户组) :一组User的容器,可以直接给Group分配角色,组内所有用户就拥有了该角色的权限。
  • Project(项目) :各服务中可访问的资源集合。创建虚拟机、创建卷时都需要指定Project。在OpenStack界面中,Tenant/Project/Account这几个术语通用,但长期看会倾向于使用Project(公有云叫租户)。
  • Role(角色) :一组定义的用户权限和特权。用户可以被赋予域或项目内的角色,角色可以继承,必须全局唯一。
  • Service(服务) :OpenStack服务,对外暴露一个或多个Endpoint。
  • Endpoint(端点) :访问某个具体服务的网络地址。
  • Token(令牌) :允许访问特定资源的凭证,默认有效期24小时。
  • Credential(凭证) :确认用户身份的数据,如用户名和密码。

2.2 通过命令行管理Keystone

创建和删除Domain:

# 创建新的domain叫domain-test
[root@controller ~(keystone_admin)]# openstack domain create domain-test
+-------------+----------------------------------+
| Field       | Value                            |
+-------------+----------------------------------+
| description |                                  |
| enabled     | True                             |
| id          | c70009318d0141c7a84b26ff427ff9d6 |
| name        | domain-test                      |
| options     | {}                               |
| tags        | []                               |
+-------------+----------------------------------+

# 验证
[root@controller ~(keystone_admin)]# openstack domain list
+----------------------------------+-------------+---------+----------------+
| ID                               | Name        | Enabled | Description    |
+----------------------------------+-------------+---------+----------------+
| 2c99588e109d427abb530cbb9aada74a | heat        | True    |                |
| c70009318d0141c7a84b26ff427ff9d6 | domain-test | True    |                |
| default                          | Default     | True    | The default domain |
+----------------------------------+-------------+---------+----------------+

# 删除domain(要先禁用)
[root@controller ~(keystone_admin)]# openstack domain set --disable domain-test
[root@controller ~(keystone_admin)]# openstack domain delete domain-test
[root@controller ~(keystone_admin)]# openstack domain list
+----------------------------------+---------+---------+--------------------+
| ID                               | Name    | Enabled | Description        |
+----------------------------------+---------+---------+--------------------+
| 2c99588e109d427abb530cbb9aada74a | heat    | True    |                    |
| default                          | Default | True    | The default domain |
+----------------------------------+---------+---------+--------------------+

删除前必须先禁用,这是Keystone的安全设计,防止误删。

创建用户:

# 创建用户user1,密码HUAWEI
[root@controller ~(keystone_admin)]# openstack user create --password HUAWEI user1
+---------------------+----------------------------------+
| Field               | Value                            |
+---------------------+----------------------------------+
| domain_id           | default                          |
| enabled             | True                             |
| id                  | 77ae3f5b216749ef8663c3bdb5679d36 |
| name                | user1                            |
| options             | {}                               |
| password_expires_at | None                             |
+---------------------+----------------------------------+

# 查看用户详细信息
[root@controller ~(keystone_admin)]# openstack user show user1

创建组并添加用户:

# 创建组group1
[root@controller ~(keystone_admin)]# openstack group create group1
+-------------+----------------------------------+
| Field       | Value                            |
+-------------+----------------------------------+
| description |                                  |
| domain_id   | default                          |
| id          | f259902c4c0242d3b392d951494e747f |
| name        | group1                           |
+-------------+----------------------------------+

# 将user1加入group1
[root@controller ~(keystone_admin)]# openstack group add user group1 user1

# 查看user1是否属于group1
[root@controller ~(keystone_admin)]# openstack group contains user group1 user1
user1 in group group1

给组赋予角色:

# 给group1赋予admin角色(在admin项目下)
[root@controller ~(keystone_admin)]# openstack role add --project admin --group group1 admin

# 验证group1角色
[root@controller ~(keystone_admin)]# openstack role assignment list --names --group group1
+-------+-------------------+-------------------+----------------+--------+--------+-----------+
| Role  | User              | Group             | Project        | Domain | System | Inherited |
+-------+-------------------+-------------------+----------------+--------+--------+-----------+
| admin |                   | group1@Default    | admin@Default  |        |        | False     |
+-------+-------------------+-------------------+----------------+--------+--------+-----------+

在Dashboard里查看user1的角色分配,能看到“admin(通过组group1)”的字样。

创建项目并分配用户:

# 创建项目ProjectA
[root@controller ~(keystone_admin)]# openstack project create ProjectA
+-------------+----------------------------------+
| Field       | Value                            |
+-------------+----------------------------------+
| description |                                  |
| domain_id   | default                          |
| enabled     | True                             |
| id          | a6aa11ee311a46889ac34e49b8da47d1 |
| is_domain   | False                            |
| name        | ProjectA                         |
| options     | {}                               |
| parent_id   | default                          |
| tags        | []                               |
+-------------+----------------------------------+

# 将ProjectA分配给用户user1
[root@controller ~(keystone_admin)]# openstack user set --project ProjectA user1

# 给项目ProjectA里的user1赋予admin角色
[root@controller ~(keystone_admin)]# openstack role add --user user1 --project ProjectA admin

修改项目配额:

# 将ProjectA配额设置为实例3,vCPU 5,内存5000MB
[root@controller ~(keystone_admin)]# openstack quota set --instances 3 --cores 5 --ram 5000 ProjectA

用user1登录Dashboard,切换到ProjectA,能看到实例、VCPU、内存的上限变成了3、5、5000MB。

查看服务列表和Endpoint:

[root@controller ~(keystone_admin)]# openstack service list
+----------------------------------+------------+----------------+
| ID                               | Name       | Type           |
+----------------------------------+------------+----------------+
| 006d8f9e6a054e238a1093fe5af715bf | swift      | object-store   |
| 1abf3641147f40368f8d1c7e8b5677e1 | heat       | orchestration  |
| 2e6919aa53eb48c99bc992b506a0e3e  | glance     | image          |
| 5dfb29073cf140199cc78b2d84fac299 | keystone   | identity       |
| 5ed901220a18430f8d423f9a95d43477 | ceilometer | metering       |
| 8ec4ba00f67448ad8acedc744dce2d87 | heat-cfn   | cloudformation |
| 9a6c3edee4ba431bd7d1cac840b910dc | neutron    | network        |
| a747c0c45e544fa9b20538474ac579d1 | nova       | compute        |
| c4e445f741a943ff897eb494cca6dfe | cinderv2   | volumev2       |
| d06744c3ad6343988bb0ab60b291ffeb | placement  | placement      |
| db9e425f65ac4808ab62dc1659f58916 | cinderv3   | volumev3       |
| e11ec9b570254141bdac2ff3ec75179d | aodh       | alarming       |
| e3a0ba8fe0f84249bfa3a90ec6a6fea  | gnocchi    | metric         |
+----------------------------------+------------+----------------+

[root@controller ~(keystone_admin)]# openstack endpoint list

Endpoint有三个入口:admin、public、internal。admin用于管理操作,public供外部访问,internal供内部服务间通信。用openstack catalog list也能看到每个服务的Endpoint。


三、OpenStack镜像管理-Glance

3.1 Glance概述

Glance是OpenStack的镜像服务,主要职责是查询、获取镜像元数据和镜像本身。它维护镜像信息、注册上传VM镜像、对VM创建快照和备份、支持多种存储后端(Swift、S3、Ceph、File System等)。

镜像、实例、规格三者的关系:镜像是包含虚拟磁盘和可引导操作系统的模板;实例是OpenStack上运行的虚拟机;规格定义了实例有多少个vCPU、多大RAM、多大临时磁盘。同一个镜像可以启动任意数量的实例,每个实例都是基于镜像的副本,实例上的修改不会影响镜像。

Glance支持的磁盘格式很多,常见的有:vhd(Xen/VirtualBox)、vhdx(vhd增强版)、vmdk(VMware)、vdi(VirtualBox/QEMU)、iso(光盘)、qcow2(QEMU,支持动态扩展和写时复制)、raw(非结构化磁盘镜像)。

3.2 上传镜像实验

先把两个镜像文件拖到controller节点的/root目录:cirros-0.5.2-x86_64-disk.img 和 TinyCore-12.0.iso。

[root@controller ~]# ls
anaconda-ks.cfg  answers.txt  cirros-0.5.2-x86_64-disk.img  keystonerc_admin  TinyCore-12.0.iso

# 观察两个文件的磁盘格式
[root@controller ~]# qemu-img info cirros-0.5.2-x86_64-disk.img
image: cirros-0.5.2-x86_64-disk.img
file format: qcow2
virtual size: 112 MiB (117440512 bytes)
disk size: 15.5 MiB
cluster_size: 65536
Format specific information:
    compat: 1.1
    compression type: zlib
    lazy refcounts: false
    refcount bits: 16
    corrupt: false
    extended l2: false

[root@controller ~]# qemu-img info TinyCore-12.0.iso
image: TinyCore-12.0.iso
file format: raw
virtual size: 20 MiB (20971520 bytes)
disk size: 20 MiB

在Dashboard里创建镜像:项目 -> 计算 -> 镜像 -> 创建镜像。

  • cirros-0.5.2:格式选QCOW2 - QEMU模拟器,可见性选“公有”。
  • TinyCore-12.0:格式选ISO - 光盘镜像,可见性选“公有”。

上传成功后,可以看到镜像列表。点击cirros-0.5.2进去,能看到它的ID是 e846b42b-5024-479b-9f79-1ae181bfa14e。

镜像上传到哪里去了?

[root@controller ~]# find / -name e846b42b-5024-479b-9f79-1ae181bfa14e
/var/lib/glance/images/e846b42b-5024-479b-9f79-1ae181bfa14e

去数据库里看看:

[root@controller ~]# mysql
MariaDB [(none)]> use glance;
MariaDB [glance]> show tables;
+----------------------------------+
| Tables_in_glance                 |
+----------------------------------+
| alembic_version                  |
| image_locations                  |
| image_members                    |
| image_properties                 |
| image_tags                       |
| images                           |
| metadef_namespace_resource_types |
| metadef_namespaces               |
| metadef_objects                  |
| metadef_properties               |
| metadef_resource_types           |
| metadef_tags                     |
| migrate_version                  |
| task_info                        |
| tasks                            |
+----------------------------------+

MariaDB [glance]> select id,value from image_locations;
+----+-----------------------------------------------------------------------------------------+
| id | value                                                                                   |
+----+-----------------------------------------------------------------------------------------+
|  1 | file:///var/lib/glance/images/e846b42b-5024-479b-9f79-1ae181bfa14e                    |
|  2 | file:///var/lib/glance/images/bb8a4940-3bde-428c-83b4-9c98eb430721                    |
+----+-----------------------------------------------------------------------------------------+

镜像文件本身存在/var/lib/glance/images/,数据库的image_locations表记录了文件路径。

3.3 镜像状态机

Glance有两种状态机:镜像状态和任务状态。镜像状态包括:

  • queued:保留了镜像标识符,但镜像数据未上传,大小未初始化。
  • saving:镜像数据正在上传。
  • uploading:调用了import data-put请求。
  • importing:导入中,镜像尚未就绪。
  • active:镜像创建完成,可以使用。
  • deactivated:禁止非管理员用户访问镜像。
  • killed:上传出错,镜像不可用。
  • deleted:保留了信息但不能用,一段时间后自动清理。
  • pending_delete:类似deleted,但数据尚未删除,可恢复。

任务状态有pending、processing、success、failure。

3.4 命令行上传大文件

Web界面上传大文件没有进度条,只会转圈,而且容易失败。建议用命令行:

[root@controller ~(keystone_admin)]# glance image-create --name image_centos --file CentOS-7-x86_64-Minimal-1810.iso --disk-format raw --container bare --progress

--progress会显示上传进度条,大文件上传更可靠。

3.5 最简单的Glance镜像制作方法

最简单的办法是直接下载系统供应商官方发布的OpenStack镜像文件。大多数官方镜像都预装了cloud-init包,支持SSH密钥对登录和用户数据注入功能。具体下载链接可以参考OpenStack社区网站:https://docs.openstack.org/image-guide/obtain-images.html。

如果直接下载的镜像不符合要求,那就需要手动制作了——用virt-manager创建虚拟机安装系统,装cloud-init,停止虚拟机,用virt-sysprep预清理,virsh undefine释放定义,qemu-img转换格式,最后openstack image create上传。不过这部分今天没有深入展开。


四、OpenStack计算管理-Nova

4.1 Nova的职责

Nova负责虚拟机生命周期管理和其他计算资源生命周期管理,但不负责承载虚拟机的物理主机自身的管理,也不做全面的系统状态监控。

Nova包含多个进程:nova-api(接收HTTP请求)、nova-scheduler(选择物理主机)、nova-conductor(数据库代理和复杂流程控制)、nova-compute(虚拟机生命周期执行)、placement(跟踪资源库存和使用情况)。组件之间通过RPC消息传递通信。

4.2 Nova调度器

nova-scheduler负责确定虚拟机分配到哪台物理机。调度过程分两步:过滤(Filters)和权重(Weighting)。

过滤器:

  • RetryFilter:刷掉之前调度过的节点,通常作为第一个filter。
  • AvailabilityZoneFilter:根据可用区过滤。
  • RamFilter:将不能满足flavor内存需求的节点过滤掉。允许overcommit,由ram_allocation_ratio控制,默认1.5。如果计算节点内存10GB,OpenStack会认为它有15GB。
  • DiskFilter:将不能满足flavor磁盘需求的节点过滤掉。disk_allocation_ratio默认1。
  • CoreFilter:将不能满足vCPU需求的节点过滤掉。cpu_allocation_ratio默认16。8vCPU的节点,调度器认为它有128个vCPU。不过默认配置里没有包含CoreFilter。
  • ComputeFilter:保证只有nova-compute服务正常工作的节点才能被调度,必选。
  • ComputeCapabilitiesFilter:根据计算节点的特性筛选,比如指定x86_64架构。
  • ImagePropertiesFilter:根据镜像属性筛选,比如指定hypervisor类型为kvm。
  • ServerGroupAntiAffinityFilter:尽量将实例分散到不同节点。
  • ServerGroupAffinityFilter:尽量将实例部署到同一节点。

权重: 通过所有filter的节点会计算权重,默认实现是根据空闲内存量计算——空闲内存越多,权重越大,实例被部署到空闲内存最多的节点上。

实验:配置可用区

在“管理员”->“计算”->“主机聚合”里创建两个聚合:gpu_az 和 nogpu_az。gpu_az包含controller节点,nogpu_az包含compute节点。

创建实例时,如果选择gpu_az,实例会被调度到controller;选择nogpu_az,会被调度到compute。在/var/log/nova/nova-scheduler.log里能看到AvailabilityZoneFilter returned 1 host(s)这样的日志,说明过滤器生效了。

打开debug后可以看到完整的过滤日志:

[root@controller ~]# vim /etc/nova/nova.conf
# 第694行 debug=True
[root@controller ~]# systemctl restart openstack-nova*

[root@controller ~(keystone_admin)]# cat /var/log/nova/nova-scheduler.log | grep Filter
# 依次经过6个过滤器,两个计算节点都通过了
# 然后比较权重,compute节点的硬盘比controller多(58368 > 54272),权重值更大(3.0 > 2.928),最终选择compute

生产环境没故障时不要开debug,浪费性能。

4.3 创建实例

在Dashboard里创建实例:

  1. 详情:实例名称vm1,可用域选nogpu_az,数量2。
  2. 源:选择镜像Img_web。
  3. 实例类型:选择Flavor_web(1vCPU、128MB内存、1GB根磁盘)。
  4. 网络:选择内网neiwang-1。
  5. 其他保持默认,点击创建。

创建完成后,实例列表里能看到两台虚拟机分别获得了192.168.11.4和192.168.11.169的IP地址。

实例操作:

  • 软重启(Soft Reboot):重启操作系统,实例依然处于运行状态,相当于在Linux里执行reboot。
  • 硬重启(Hard Reboot):重启实例,相当于关机再开机。
  • 暂停(Pause):将实例状态保存到宿主机内存中,恢复(Resume/Unpause)快。
  • 挂起(Suspend):将实例状态保存到宿主机磁盘上,恢复(Resume)慢,状态变为Shut Down。
  • Shelve:将实例作为镜像保存到Glance,然后在宿主机上删除该实例,释放预留资源。
  • 锁定实例:防止意外删除,管理员锁定的实例普通用户不能直接删除,也不能解锁。

在/etc/openstack-dashboard/nova_policy.json里可以看到锁定和解锁的策略规则。默认os_compute_api:os-lock-server:unlock是rule:admin_or_owner,意味着普通用户可以解锁。如果改成rule:admin_api,普通用户就不能解锁了。


五、OpenStack存储管理-Cinder和Swift

5.1 存储类型

从数据保存时间角度分两类:临时存储(Ephemeral)和持久存储(Persistent)。

  • 临时存储:数据被虚拟机实例使用,实例关机、重启或删除后数据丢失。默认情况下临时存储以文件形式放在计算节点的本地磁盘上。
  • 持久存储:数据持续可用,生命周期独立于虚拟机。OpenStack的持久存储包括块存储(Cinder)、对象存储(Swift)和文件存储(Manila)。

5.2 Cinder块存储

Cinder在虚拟机和具体存储设备之间引入了一层“逻辑存储卷”的抽象。它本身不是一种存储技术,只是提供了一个中间的抽象层,为后端不同的存储技术提供统一接口。不同的块设备服务厂商在Cinder中以驱动的形式实现接口。

Cinder架构包括:cinder-api(对外提供REST API)、cinder-scheduler(调度选择后端)、cinder-volume(与设备交互完成卷操作)、cinder-backup(备份到其他存储介质)、SQL DB(存储卷、快照、备份等数据)。

创建卷:

在Dashboard里,“项目”->“卷”->“卷”->“创建卷”。卷名称volume1,类型iscsi,大小1GB,可用域az1。

# 命令行创建卷
[root@controller ~(keystone_admin)]# openstack volume create --size 1 --availability-zone az1 volume1
+---------------------+--------------------------------------+
| Field               | Value                                |
+---------------------+--------------------------------------+
| attachments         | []                                   |
| availability_zone   | az1                                  |
| bootable            | false                                |
| consistencygroup_id | None                                 |
| created_at          | 2024-09-27T06:02:35.368543           |
| description         | None                                 |
| encrypted           | False                                |
| id                  | 43746d03-a0c5-4232-8f1b-6023ffe83545 |
| migration_status    | None                                 |
| multiattach         | False                                |
| name                | volume1                              |
| properties          |                                      |
| replication_status  | None                                 |
| size                | 1                                    |
| snapshot_id         | None                                 |
| source_volid        | None                                 |
| status              | creating                             |
| type                | iscsi                                |
| updated_at          | None                                 |
| user_id             | 7ef9147a8abe485889ece90dce340ab1     |
+---------------------+--------------------------------------+

可用区过滤实验:

在/etc/cinder/cinder.conf里,storage_availability_zone=az1表示该节点属于az1,default_availability_zone=nova表示创建卷不指定AZ时默认使用nova。

# 创建卷时不指定AZ,使用nova,但节点属于az1,创建失败
[root@controller ~(keystone_admin)]# openstack volume create --size 1 volume1
Availability zone 'nova' is invalid. (HTTP 400) (Request-ID: req-c4e2d4d1-d299-4267-b2a1-22fcd676a6ea)

# 创建az2的卷,被AvailabilityZoneFilter过滤
[root@controller ~(keystone_admin)]# openstack volume create --size 1 --availability-zone az2 volume1
Availability zone 'az2' is invalid. (HTTP 400) (Request-ID: req-749dad9d-d5fb-4122-95aa-ab03d0c5a955)

# 创建az1的卷,创建成功
[root@controller ~(keystone_admin)]# openstack volume create --size 1 --availability-zone az1 volume1
# 创建成功,status为creating

Cinder配置文件里的LVM后端:

[root@controller ~(keystone_admin)]# vim /etc/cinder/cinder.conf
# 第5261-5267行
[lvm]
volume_backend_name=lvm
volume_driver=cinder.volume.drivers.lvm.LVMVolumeDriver
target_ip_address=192.168.108.10
target_helper=lioadm
volume_group=cinder-volumes
volumes_dir=/var/lib/cinder/volumes

实验环境的后端存储就是LVM,CONFIG_CINDER_BACKEND=lvm,卷组是cinder-volumes,大小20G。

5.3 Swift对象存储

Swift是对象存储,用于永久类型的静态数据的长期存储。最适合存储虚拟机镜像、图片、邮件、存档备份。Swift没有中心单元或主控节点,扩展性、冗余和持久性更强。

Swift为账户、容器和对象分别定义了Ring,Ring记录存储对象与物理位置的映射关系,通过Zone、Device、Partition和Replica来维护映射。

Swift实验:

先给controller节点新增一块20GB磁盘,分成两个10GB分区,格式化为xfs,分别挂载到/srv/node/obs1和/srv/node/obs2。

# fdisk分区
[root@controller ~]# fdisk /dev/sdb
Command (m for help): n
# ... 创建两个10G分区 sdb1 和 sdb2
Command (m for help): w

# 格式化
[root@controller ~]# mkfs.xfs /dev/sdb1
[root@controller ~]# mkfs.xfs /dev/sdb2

# 挂载
[root@controller node]# vim /etc/fstab
# 注释掉原来的swiftloopback
#/srv/loopback-device/swiftloopback /srv/node/swiftloopback ext4 noatime,nodiratime,nofail,loop,user_xattr 0 0
/dev/sdb1 /srv/node/obs1 xfs defaults 0 0
/dev/sdb2 /srv/node/obs2 xfs defaults 0 0

[root@controller node]# mount -a
[root@controller node]# df
Filesystem     1K-blocks    Used Available Use% Mounted on
/dev/sdb1       10475520  106088  10369432   2% /srv/node/obs1
/dev/sdb2       10474496  106088  10368408   2% /srv/node/obs2

# 修改权限
[root@controller node]# chown swift:swift obs1 obs2
[root@controller node]# ll
drwxr-xr-x 2 swift swift 6 Sep 29 14:04 obs1
drwxr-xr-x 2 swift swift 6 Sep 29 14:04 obs2

创建swift ring:

[root@controller swift]# swift-ring-builder container.builder create 12 2 1
[root@controller swift]# swift-ring-builder account.builder create 12 2 1
[root@controller swift]# swift-ring-builder object.builder create 12 2 1
# 12表示ring分区数量为2^12
# 2表示2个副本
# 1表示最少1个小时后才能更改ring配置

# 查看各服务的bind_port
[root@controller swift]# cat account-server.conf | grep bind_port
bind_port = 6002
[root@controller swift]# cat container-server.conf | grep bind_port
bind_port = 6001
[root@controller swift]# cat object-server.conf | grep bind_port
bind_port = 6000

# 添加ring映射
[root@controller swift]# swift-ring-builder account.builder add z1-192.168.108.10:6002/obs1 100
[root@controller swift]# swift-ring-builder account.builder add z2-192.168.108.10:6002/obs2 100
[root@controller swift]# swift-ring-builder container.builder add z1-192.168.108.10:6001/obs1 100
[root@controller swift]# swift-ring-builder container.builder add z2-192.168.108.10:6001/obs2 100
[root@controller swift]# swift-ring-builder object.builder add z1-192.168.108.10:6000/obs1 100
[root@controller swift]# swift-ring-builder object.builder add z2-192.168.108.10:6000/obs2 100

# 再平衡
[root@controller swift]# swift-ring-builder account.builder rebalance
Reassigned 8192 (200.00%) partitions. Balance is now 0.00. Dispersion is now 0.00
[root@controller swift]# swift-ring-builder object.builder rebalance
Reassigned 8192 (200.00%) partitions. Balance is now 0.00. Dispersion is now 0.00
[root@controller swift]# swift-ring-builder container.builder rebalance
Reassigned 8192 (200.00%) partitions. Balance is now 0.00. Dispersion is now 0.00

在Dashboard里“项目”->“对象存储”->“容器”->“容器”->创建容器,名称test,存储策略Policy-0。进入容器后上传cirros-0.5.2-x86_64-disk.img文件。

上传成功后,去两个目录检查:

[root@controller obs1]# find /srv/node -name data
/srv/node/obs1/objects/317/0fe/13d34c83bb5eed122321759e90f6e0fe/1727591964.07735.data
/srv/node/obs2/objects/317/0fe/13d34c83bb5eed122321759e90f6e0fe/1727591964.07735.data

2个副本分别在obs1和obs2目录各存了一份,符合ring里配置的2副本。


六、OpenStack网络管理-Neutron

6.1 Neutron功能

Neutron为整个OpenStack环境提供网络支持,包括二层交换、三层路由、负载均衡、防火墙和VPN。它提供了一个灵活框架,开源和商业软件都可以通过配置实现这些功能。

  • 二层交换:Nova的实例通过虚拟交换机连接到虚拟二层网络。Neutron支持Linux Bridge和Open vSwitch,除了传统VLAN网络,还支持VXLAN和GRE Overlay网络。
  • 三层路由:通过虚拟路由器实现实例跨网段通信,用IP forwarding和iptables实现路由和NAT。
  • 负载均衡:LBaaS,默认Plugin是HAProxy。
  • 防火墙:Security Group(限制进出实例的包)和FWaaS(限制进出虚拟路由器的包),都通过iptables实现。

6.2 Neutron核心概念

  • Network:隔离的二层广播域,类型有local、flat、VLAN、VXLAN、GRE。不同network之间二层隔离。
  • Subnet:IPv4或IPv6地址段,实例IP从subnet分配。一个network可以有多个subnet,但不能重叠。
  • Port:虚拟交换机上的一个端口,定义了MAC地址和IP地址。当实例的虚拟网卡VIF绑定到port时,port会将MAC和IP分配给VIF。

关系总结:Project 1:m Network 1:m Subnet 1:m Port 1:1 VIF m:1 Instance。

6.3 Neutron架构

Neutron采用分布式架构,由Neutron Server(对外提供API)、Plugin(维护逻辑网络状态)、Agent(在network provider上实现网络功能)、network provider(Linux Bridge/OVS等)、Queue(消息队列)、Database(存放网络状态)组成。

6.4 创建网络和路由实验

创建外网:

在“管理员”->“网络”->“网络”->“创建网络”:

  • 名称:waiwang
  • 项目:admin
  • 供应商网络类型:Flat
  • 物理网络:extnet
  • 勾选“外部网络”
  • 子网名称:waiwang_subnet
  • 网络地址:192.168.108.0/24
  • 网关IP:192.168.108.2
  • 激活DHCP,分配地址池:192.168.108.100,192.168.108.200
# 查看OVN现象
[root@controller ~]# ovn-nbctl show
switch e69d7e37-9a0d-4abe-81c8-9d10c2246178 (neutron-e79063ae-1291-42b2-8519-ec0ce0a421e1) (aka waiwang)
    port 43b284b0-ebc8-4bd3-8c59-77dce8d33dd
        type: localport
        addresses: ["fa:16:3e:be:d3:41 192.168.108.100"]
    port provnet-50a84802-b570-4cad-be3e-cb934c259c48
        type: localnet
        addresses: ["unknown"]

创建内网:

项目 -> 网络 -> 网络 -> 创建网络:

  • 名称:neiwang-1
  • 子网名称:neiwang-1-subnet
  • 网络地址:192.168.11.0/24
  • 网关IP:192.168.11.1
  • 激活DHCP,DNS服务器填8.8.8.8
# 查看OVN现象
[root@controller ~]# ovn-nbctl show
switch 9e269a0c-5049-4c20-b602-ce42d722017c (neutron-c5a25fa7-559f-4e62-8bf0-7ebcd8c8a1f1) (aka neiwang-1)
    port 3b975511-7c63-495e-969c-1424e69770dc
        type: localport
        addresses: ["fa:16:3e:dd:ea:9d 192.168.11.2"]
switch e69d7e37-9a0d-4abe-81c8-9d10c2246178 (neutron-e79063ae-1291-42b2-8519-ec0ce0a421e1) (aka waiwang)
    port 43b284b0-ebc8-4bd3-8c59-77dce8d33dd
        type: localport
        addresses: ["fa:16:3e:be:d3:41 192.168.108.100"]
    port provnet-50a84802-b570-4cad-be3e-cb934c259c48
        type: localnet
        addresses: ["unknown"]

创建路由:

项目 -> 网络 -> 路由 -> 新建路由:

  • 路由名称:router1
  • 外部网络:waiwang
  • 启用SNAT

进入router1,点击“增加接口”,选择子网neiwang-1: 192.168.11.0/24,IP地址留空(默认使用子网网关)。

# 查看OVN现象
[root@controller ~]# ovn-nbctl show
# ...
router 9374d9e7-b8b0-4d6e-924d-c9fdef6662e5 (neutron-a75adc8f-9668-4fe1-b6eb-b4573d574ae0) (aka router1)
    port 1rp-9da6f7af-22e3-44fc-8465-90334f8abeea
        mac: "fa:16:3e:78:18:6c"
        networks: ["192.168.11.1/24"]
    port 1rp-c0354999-1e15-436f-b15f-be2d3b17c5b4
        mac: "fa:16:3e:82:b8:23"
        networks: ["192.168.108.185/24"]
    gateway chassis: [46cd64c9-2f35-4dfb-9351-e0b1693daf8b]
    nat d6fae190-e948-475c-b5b1-a9258a8b7c65
        external ip: "192.168.108.185"
        logical ip: "192.168.11.0/24"
        type: "snat"

在“网络拓扑”里可以看到waiwang和neiwang-1通过网络节点(router1)连在了一起。

验证实例互访:

创建两台实例vm-1和vm-2,网络都选neiwang-1。创建完成后,一台获得192.168.11.4,另一台获得192.168.11.169。

打开vm-1的控制台,ping另一台:

$ ping -c 2 192.168.11.4
PING 192.168.11.4 (192.168.11.4): 56 data bytes
64 bytes from 192.168.11.4: seq=0 ttl=64 time=10.387 ms
64 bytes from 192.168.11.4: seq=1 ttl=64 time=1.947 ms

--- 192.168.11.4 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 1.947/6.167/10.387 ms

同一子网内互通正常。


七、OpenStack编排管理-Heat

7.1 Heat的作用

Heat是一种通过OpenStack原生REST API使用声明性模板格式编排复合云应用程序的服务,提供与其他OpenStack核心项目的紧密集成。

Heat模板以文本文件的形式描述云应用程序的基础架构,支持版本控制。模板指定资源之间的关系,Heat能调用OpenStack API以正确的顺序创建用户所需的基础架构。

Heat位于Nova、Neutron等服务之上,充当OpenStack对外接口的角色。用户不需要直接接触其他服务,只需把需求写在Heat模板里,Heat会自动调用相关服务接口配置资源。

Heat架构:用户通过Horizon或CLI提交模板和参数,转化为REST API调用,Heat-api验证模板正确性后通过消息队列传递给Heat Engine处理。Heat-api提供REST API,Heat-api-cfn提供兼容AWS CloudFormation的API,Heat-engine是核心,负责任务调度和资源生命周期管理。

Heat模板默认使用YAML语法,包含heat_template_version、description、parameters、resources、outputs等字段。

7.2 Heat实验

先创建好实例类型Flavor_web(1vCPU、128MB内存、1GB根磁盘)、镜像Img_web、外网public_net。

编写heat.txt模板:

heat_template_version: 2018-08-31

description: Simple template to deploy a stack with one virtual machine instances

parameters:
  image_name_1:
    type: string
    label: Image ID
    description: SCOIMAGE Specify an image name for instance1
    default: 732c9cee-2652-4a4e-8c09-19745d6e15b5  # 替换自己的image id

  public_net:
    type: string
    label: Network ID
    description: SCONETWORK Network to be used for the compute instance
    default: a6e27f03-e762-4c46-a997-a7a6848d5849  # 替换自己的外网id

resources:
  mykey:
    type: OS::Nova::KeyPair
    properties:
      save_private_key: true
      name: mykey

  web_secgroup:
    type: OS::Neutron::SecurityGroup
    properties:
      rules:
        - protocol: tcp
          remote_ip_prefix: 0.0.0.0/0
          port_range_min: 22
          port_range_max: 22
        - protocol: icmp

  private_net:
    type: OS::Neutron::Net
    properties:
      name: private_net

  private_subnet:
    type: OS::Neutron::Subnet
    properties:
      network_id: { get_resource: private_net }
      cidr: "192.168.99.0/24"
      ip_version: 4

  vrouter:
    type: OS::Neutron::Router
    properties:
      external_gateway_info:
        network: { get_param: public_net }

  vrouter_interface:
    type: OS::Neutron::RouterInterface
    properties:
      router_id: { get_resource: vrouter }
      subnet_id: { get_resource: private_subnet }

  instance_port:
    type: OS::Neutron::Port
    properties:
      network: { get_resource: private_net }
      security_groups:
        - default
        - { get_resource: web_secgroup }
      fixed_ips:
        - subnet_id: { get_resource: private_subnet }

  floating_ip:
    type: OS::Neutron::FloatingIP
    properties:
      floating_network_id: { get_param: public_net }

  association:
    type: OS::Neutron::FloatingIPAssociation
    properties:
      floatingip_id: { get_resource: floating_ip }
      port_id: { get_resource: instance_port }

  instance1:
    type: OS::Nova::Server
    properties:
      image: { get_param: image_name_1 }
      key_name: { get_resource: mykey }
      flavor: Flavor_web  # 替换自己创建的flavor名字
      networks:
        - port: { get_resource: instance_port }

outputs:
  private_key:
    description: Private key
    value: { get_attr: [ mykey, private_key ] }

在Dashboard里“项目”->“编排”->“堆栈”->“创建堆栈”,模板源选“文件”,选择heat.txt,堆栈名称stack1,创建超时60分钟,输入admin密码,点击“启动”。

创建完成后,在堆栈详情页能看到完整的资源拓扑图,包括路由器、网络、子网、端口、安全组、密钥对、实例、浮动IP等。Heat把这一大堆资源的创建顺序和依赖关系都自动处理好了,这才是编排的真正价值。


八、踩坑总结与学习心得

这一天下来的实验量真的很大,踩的坑也不少,挑几个印象深刻的记一下:

1. Keystone删除domain前必须先禁用。 直接openstack domain delete会报错,必须先openstack domain set --disable。这是安全设计,防止误删。

2. 普通用户创建环境变量文件时,OS_PROJECT_NAME要改成自己有权限的项目。 我一开始没改,source之后openstack project list还是只显示admin,因为user1只在admin项目里有角色。

3. Glance镜像上传到/var/lib/glance/images/,文件名是镜像ID。 数据库image_locations表里存的是file://路径。这个设计让镜像文件和元数据分离,方便扩展存储后端。

4. Cinder的可用区过滤和Nova类似,但配置项不同。 storage_availability_zone和default_availability_zone要配合好,否则创建卷时会报Availability zone 'nova' is invalid。

5. Swift的ring创建后必须rebalance才能生效。 一开始我忘了rebalance,上传文件后两个obs目录都是空的,后来执行swift-ring-builder object.builder rebalance才正常。

6. Heat模板里的默认值要替换成自己的ID。 复制模板后如果没改image_name_1和public_net的default值,堆栈创建会失败。用openstack image list和openstack network list查一下ID就行。

7. 生产环境不要开debug。 实验时为了看调度器日志开了debug=True,日志刷得飞快,磁盘很快就满了。生产环境只在排障时临时开一下。

从Keystone的认证体系,到Glance的镜像管理,再到Nova的调度算法、Cinder的卷抽象、Swift的对象存储、Neutron的OVN网络、Heat的编排模板,OpenStack的七大组件算是过了一遍。虽然每个组件都只是入门级别,但至少对它们之间的协作关系有了直观认识:用户通过Keystone拿到Token,请求打到Nova,Nova向Glance要镜像、向Neutron要网络、向Cinder要卷,最后在计算节点上把虚拟机跑起来。Heat则是在最上层,把这一整套流程用模板描述出来,一键部署。

这套架构虽然复杂,但设计思路很清晰——每个组件只做一件事,通过消息队列和REST API解耦,可以独立扩展和替换。理解了这套逻辑,再去对比华为云的FusionCompute、Kubernetes的容器编排,会发现很多设计思想是相通的。

下一阶段应该要进入容器和Kubernetes了,从虚拟机到容器,从OpenStack到K8s,又是一次架构的跃迁。继续加油!

转载自 CSDN-专业IT技术社区

原文链接:https://blog.csdn.net/2604_96593683/article/details/169165910

文章来源转载

评论

评论列表

微信小程序
QQ小程序

关于作者

点赞数:0
关注数:0
粉丝:0
文章:0
关注标签:0
加入于:--