云原生运维学习笔记: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里创建实例:
- 详情:实例名称
vm1,可用域选nogpu_az,数量2。 - 源:选择镜像
Img_web。 - 实例类型:选择
Flavor_web(1vCPU、128MB内存、1GB根磁盘)。 - 网络:选择内网
neiwang-1。 - 其他保持默认,点击创建。
创建完成后,实例列表里能看到两台虚拟机分别获得了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




