本地源方式安装开源 OpenStack (V版本)

本地源方式安装开源 OpenStack (V版本)

文章目录

本地源方式安装开源 OpenStack (V版)

背景

由于网络条件限制,通过外网方式部署 OpenStack 无法完成,可以使用本地源方式部署。以下是详细部署步骤。


环境准备

主机名IP网关/DNSCPU/内存磁盘角色备注
controller192.168.100.130192.168.100.24C/8G100G控制/网络/计算节点必须开启虚拟化引擎
compute192.168.100.131192.168.100.24C/8G100G计算节点必须开启虚拟化引擎
💡 提示:确保两台主机的虚拟化引擎已启用。在BIOS中检查Intel VT-x或AMD-V是否启用。

通过外网方式安装openstack

配置网卡及主机名

控制节点

[root@localhost ~]# hostnamectl set-hostname controller[root@localhost ~]# bash[root@controller ~]# vi /etc/sysconfig/network-scripts/ifcfg-ens160[root@controller ~]# cat /etc/sysconfig/network-scripts/ifcfg-ens160TYPE=Ethernet BOOTPROTO=none DEFROUTE=yes NAME=ens160 DEVICE=ens160 ONBOOT=yes IPADDR=192.168.100.130 NETMASK=255.255.255.0 GATEWAY=192.168.100.2 DNS1=192.168.100.2 
💡 说明:确保ens160是你的实际网卡名称。可以使用ip a命令查看。

计算节点

[root@localhost ~]# hostnamectl set-hostname compute[root@localhost ~]# bash[root@compute ~]# vi /etc/sysconfig/network-scripts/ifcfg-ens160[root@compute ~]# cat /etc/sysconfig/network-scripts/ifcfg-ens160TYPE=Ethernet BOOTPROTO=none DEFROUTE=yes NAME=ens160 DEVICE=ens160 ONBOOT=yes IPADDR=192.168.100.131 NETMASK=255.255.255.0 GATEWAY=192.168.100.2 DNS1=192.168.100.2 
💡 提示:确保两台主机的IP地址在同一个子网内,且网关和DNS配置正确。

关闭防火墙及 SELinux

控制节点

[root@controller ~]# systemctl disable --now firewalld[root@controller ~]# systemctl status firewalld ● firewalld.service - firewalld - dynamic firewall daemon Loaded: loaded (/usr/lib/systemd/system/firewalld.service; disabled; vendor preset: enabled) Active: inactive (dead) Docs: man:firewalld(1)[root@controller ~]# sed -i 's/SELINUX=enforcing/SELINUX=disabled/g' /etc/selinux/config[root@controller ~]# setenforce 0

计算节点

[root@compute ~]# systemctl disable --now firewalld[root@compute ~]# systemctl status firewalld ● firewalld.service - firewalld - dynamic firewall daemon Loaded: loaded (/usr/lib/systemd/system/firewalld.service; disabled; vendor preset: enabled) Active: inactive (dead) Docs: man:firewalld(1)[root@compute ~]# sed -i 's/SELINUX=enforcing/SELINUX=disabled/g' /etc/selinux/config[root@compute ~]# setenforce 0
💡 重要提示:在生产环境中,建议配置防火墙规则而非完全禁用。但在部署阶段,禁用防火墙可以避免网络配置问题。

主机名映射及基础软件包

控制节点

[root@controller ~]# vi /etc/hosts[root@controller ~]# cat /etc/hosts127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4 ::1 localhost localhost.localdomain localhost6 localhost6.localdomain6 192.168.100.130 controller 192.168.100.131 compute 

计算节点

[root@compute ~]# vim /etc/hosts[root@compute ~]# cat /etc/hosts127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4 ::1 localhost localhost.localdomain localhost6 localhost6.localdomain6 192.168.100.130 controller 192.168.100.131 compute 
💡 提示:确保两台主机的/etc/hosts文件内容一致,这样它们可以互相解析主机名。

本地源配置

💡 重要提示:本地源配置只需在计算节点上完成,控制节点会通过HTTP从计算节点获取本地源。

计算节点配置

[root@compute ~]# lsblk NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT sr0 11:0 110.9G 0 rom # 本地ISO已经存在,这里就不上传了 nvme0n1 259:0 0 100G 0 disk ├─nvme0n1p1 259:1 0 1G 0 part /boot └─nvme0n1p2 259:2 0 99G 0 part └─cs-root 253:0 0 99G 0 lvm / [root@compute ~]# mkdir /mnt/centos-stream8[root@compute ~]# mount /dev/cdrom /mnt/centos-stream8 mount: /mnt/centos-stream8: WARNING: device write-protected, mounted read-only. [root@compute ~]# ls -l /mnt/centos-stream8/ total 30 dr-xr-xr-x. 4 root root 2048 Dec 232022 AppStream dr-xr-xr-x. 4 root root 2048 Dec 232022 BaseOS dr-xr-xr-x. 3 root root 2048 Dec 232022 EFI dr-xr-xr-x. 3 root root 2048 Dec 232022 images dr-xr-xr-x. 2 root root 2048 Dec 232022 isolinux -r--r--r--. 1 root root 18092 Sep 142021 LICENSE -r--r--r--. 1 root root 88 Dec 232022 media.repo -r--r--r--. 1 root root 883 Dec 232022 TRANS.TBL 

配置本地YUM仓库

[root@compute yum.repos.d]# mkdir bak[root@compute yum.repos.d]# mv *.repo bak/[root@compute yum.repos.d]# vi CentOS-Stream8.repo
[BaseOS] name = BaseOS baseurl = file:////mnt/centos-stream8/BaseOS gpgcheck=0 enabled = 1 [AppStream] name = AppStream baseurl = file:///mnt/centos-stream8/AppStream gpgcheck=0 enabled = 1 
💡 重要说明gpgcheck=0:在离线环境中,不需要检查GPG签名,设置为0避免错误。enabled=1:启用此仓库,系统会使用它。默认值就是1,但显式写上更清晰baseurl中的file:///表示这是本地文件系统路径。

验证本地源配置

[root@compute yum.repos.d]# dnf clean all0 files removed [root@compute yum.repos.d]# dnf repolist repo id repo name AppStream AppStream BaseOS BaseOS 
💡 提示:如果看不到仓库,确保ISO已正确挂载,且路径正确。

配置 httpd 服务

[root@compute ~]# dnf install httpd -y... [root@compute ~]# ls /var/www/html/[root@compute ~]# mkdir /var/www/html/openstack[root@compute ~]# mkdir /var/www/html/centos-stream8[root@compute ~]# ls /var/www/html/centos-stream8 openstack[root@compute ~]# ll /var/www/html/centos-stream8 total 22162580 -rw-r--r--. 1 root root 11729371136 Nov 2016:04 20-CentOS-Stream-8-x86_64-20221222-dvd1.iso -rw-r--r--. 1 root root 10965106688 Nov 2015:22 21-CentOS-Stream-8-OPS-Victoria.iso -rw-------. 1 root root 1330 Nov 1714:42 anaconda-ks.cfg [root@compute ~]# mount 20-CentOS-Stream-8-x86_64-20221222-dvd1.iso /var/www/html/centos-stream8 mount: /var/www/html/centos-stream8: WARNING: device write-protected, mounted read-only. [root@compute ~]# mount 21-CentOS-Stream-8-OPS-Victoria.iso /var/www/html/openstack mount: /var/www/html/openstack: WARNING: device write-protected, mounted read-only. [root@compute ~]# ls /var/www/html/openstack/ centos-ceph-pacific centos-nfv-openvswitch centos-openstack-victoria centos-rabbitmq-38 extras extras-common highavailability nfv powertools resilientstorage rt [root@compute ~]# ls /var/www/html/centos-stream8/AppStream BaseOS EFI images isolinux LICENSE media.repo TRANS.TBL[root@compute ~]# systemctl status httpd ● httpd.service - The Apache HTTP Server Loaded: loaded (/usr/lib/systemd/system/httpd.service; enabled; vendor preset: disabled) Active: active (running) since Thu 2025-11-20 16:09:18 CST; 7s ago Docs: man:httpd.service(8) Main PID: 11096(httpd) Status: "Started, listening on: port 80" Tasks: 213(limit: 49261) Memory: 39.9M 
💡 验证方式:使用浏览器访问http://192.168.100.131/centos-stream8http://192.168.100.131/openstack,确认可以访问。

配置 YUM 源(控制节点)

[root@controller yum.repos.d]# pwd /etc/yum.repos.d [root@controller yum.repos.d]# cat centos-stream8_openstack.repo[highavailability] name = highavailability baseurl = http://192.168.100.131/openstack/highavailability gpgcheck =0 enabled =1[resilientstorage] name = resilientstorage baseurl = http://192.168.100.131/openstack/resilientstorage gpgcheck =0 enabled =1[extras-common] name = extras-common baseurl = http://192.168.100.131/openstack/extras-common gpgcheck =0 enabled =1[extras] name = extras baseurl = http://192.168.100.131/openstack/extras gpgcheck =0 enabled =1[centos-ceph-pacific] name = centos-ceph-pacific baseurl = http://192.168.100.131/openstack/centos-ceph-pacific gpgcheck =0 enabled =1[centos-rabbitmq-38] name = centos-rabbitmq-38 baseurl = http://192.168.100.131/openstack/centos-rabbitmq-38 gpgcheck =0 enabled =1[centos-nfv-openvswitch] name = centos-nfv-openvswitch baseurl = http://192.168.100.131/openstack/centos-nfv-openvswitch gpgcheck =0 enabled =1[BaseOS] name = BaseOS baseurl = http://192.168.100.131/centos-stream8/BaseOS gpgcheck =0 enabled =1[AppStream] name = AppStream baseurl = http://192.168.100.131/centos-stream8/AppStream gpgcheck =0 enabled =1[centos-openstack-victoria] name = centos-openstack-victoria baseurl = http://192.168.100.131/openstack/centos-openstack-victoria gpgcheck =0 enabled =1[powertools] name = powertools baseurl = http://192.168.100.131/openstack/powertools gpgcheck =0 enabled =1[nfv] name = nfv baseurl = http://192.168.100.131/openstack/nfv gpgcheck =0 enabled =1[rt] name = rt baseurl = http://192.168.100.131/openstack/rt gpgcheck =0 enabled =1
💡 重要提示:确保控制节点能访问计算节点的HTTP服务(http://192.168.100.131)。

安装基础软件包

[root@controller yum.repos.d]# dnf clean all0 files removed [root@controller yum.repos.d]# dnf repolist repo id repo name AppStream AppStream BaseOS BaseOS centos-ceph-pacific centos-ceph-pacific centos-nfv-openvswitch centos-nfv-openvswitch centos-openstack-victoria centos-openstack-victoria centos-rabbitmq-38 centos-rabbitmq-38 extras extras extras-common extras-common highavailability highavailability nfv nfv powertools powertools resilientstorage resilientstorage rt rt [root@controller ~]# dnf install vim net-tools bash-completion
💡 提示bash-completion提供命令补全功能,让操作更高效。

配置 NTP 时钟同步

控制节点

[root@controller ~]# dnf install -y chrony[root@controller ~]# vim /etc/chrony.conf# 修改内容: pool ntp.aliyun.com iburst allow 192.168.100.0/24 [root@controller ~]# systemctl start chronyd[root@controller ~]# systemctl enable chronyd[root@controller ~]# systemctl status chronyd ● chronyd.service - NTP client/server Loaded: loaded (/usr/lib/systemd/system/chronyd.service; enabled; vendor preset: enabled) Active: active (running) since Thu 2025-11-20 16:44:19 CST; 9s ago Docs: man:chronyd(8) man:chrony.conf(5) Main PID: 11236(chronyd) Tasks: 1(limit: 49261) Memory: 924.0K 

计算节点

[root@compute ~]# dnf install -y chrony[root@compute ~]# vim /etc/chrony.conf# 修改内容: server controller iburst [root@compute ~]# systemctl start chronyd[root@compute ~]# systemctl enable chronyd[root@compute ~]# systemctl status chronyd ● chronyd.service - NTP client/server Loaded: loaded (/usr/lib/systemd/system/chronyd.service; enabled; vendor preset: enabled) Active: active (running) since Thu 2025-11-20 16:48:13 CST; 10s ago Docs: man:chronyd(8) man:chrony.conf(5) Main PID: 11886(chronyd) Tasks: 1(limit: 49261) Memory: 828.0K 
💡 重要提示:时间同步对OpenStack非常重要,确保所有节点时间一致。

关闭 NetworkManager

💡 为什么需要关闭 NetworkManager?
NetworkManager 与 OpenStack 的网络配置有冲突,特别是 Neutron 组件。在服务器环境中,建议使用传统的 network 服务。

控制节点

[root@controller ~]# systemctl stop NetworkManager[root@controller ~]# systemctl disable NetworkManager Removed /etc/systemd/system/multi-user.target.wants/NetworkManager.service. Removed /etc/systemd/system/dbus-org.freedesktop.nm-dispatcher.service. Removed /etc/systemd/system/network-online.target.wants/NetworkManager-wait-online.service. 

计算节点

[root@compute ~]# systemctl stop NetworkManager[root@compute ~]# systemctl disable NetworkManager Removed /etc/systemd/system/multi-user.target.wants/NetworkManager.service. Removed /etc/systemd/system/dbus-org.freedesktop.nm-dispatcher.service. Removed /etc/systemd/system/network-online.target.wants/NetworkManager-wait-online.service. 
💡 重要提示:确保关闭 NetworkManager 后,network 服务已启用。

安装 packstack 工具

[root@controller ~]# dnf install -y openstack-packstack
💡 提示openstack-packstack 是 OpenStack 的自动化部署工具,用于简化安装过程。

生成应答文件

[root@controller ~]# packstack --gen-answer-file=/tmp/openstack-response.txt Packstack changed given value to required value /root/.ssh/id_rsa.pub Additional information: * Parameter CONFIG_NEUTRON_L2_AGENT: You have chosen OVN Neutron backend. Note that this backend does not support the VPNaaS plugin. Geneve will be used as the encapsulation method for tenant networks [root@controller ~]# ls /tmp/openstack-response.txt -ld -rw-------. 1 root root 51366 Nov 2016:56 /tmp/openstack-response.txt 
💡 重要说明--gen-answer-file 会生成一个模板文件,用于后续安装时指定配置。

修改应答文件

[root@controller ~]# vim /tmp/openstack-response.txt

需要修改的关键参数

CONFIG_COMPUTE_HOSTS=192.168.100.131 CONFIG_KEYSTONE_ADMIN_PW=redhat # 登录OpenStack网页后密码,用户是admin CONFIG_PROVISION_DEMO=n CONFIG_HEAT_INSTALL=y CONFIG_NEUTRON_OVN_BRIDGE_IFACES=br-ex:ens160 
💡 重要提示CONFIG_COMPUTE_HOSTS:指定计算节点的IP地址CONFIG_KEYSTONE_ADMIN_PW:设置管理员密码,建议改为更安全的密码CONFIG_NEUTRON_OVN_BRIDGE_IFACES:指定Neutron OVN后端的网桥接口

开始安装 OpenStack

[root@controller ~]# packstack --answer-file=/tmp/openstack-response.txt Welcome to the Packstack setup utility The installation log file is available at: /var/tmp/packstack/20251121-093753-6xa_aasc/openstack-setup.log Installing: Clean Up [ DONE ] Discovering ip protocol version [ DONE ] [email protected]'s password: # 输入root密码 [email protected]'s password: # 输入root密码 Setting up ssh keys [ DONE ] Preparing servers [ DONE ] Pre installing Puppet and discovering hosts' details [ DONE ] Preparing pre-install entries [ DONE ] Setting up CACERT [ DONE ] Preparing AMQP entries [ DONE ] Preparing MariaDB entries [ DONE ] Fixing Keystone L DAP config parameters to be undef if empty [ DONE ] Preparing Keystone entries [ DONE ] Preparing Glance entries [ DONE ] Checking if the Cinder server has a cinder-volumes vg [ DONE ] Preparing Cinder entries [ DONE ] Preparing Nova API entries [ DONE ] Creating ssh keys for Nova migration [ DONE ] Gathering sshhost keys for Nova migration [ DONE ] Preparing Nova Compute entries [ DONE ] Preparing Nova Scheduler entries [ DONE ] Preparing Nova VNC Proxy entries [ DONE ] Preparing OpenStack Network-related Nova entries [ DONE ] Preparing Nova Common entries [ DONE ] Preparing Neutron API entries [ DONE ] Preparing Neutron L3 entries [ DONE ] Preparing Neutron L2 Agent entries [ DONE ] Preparing Neutron DHCP Agent entries [ DONE ] Preparing Neutron Metering Agent entries [ DONE ] Checking if NetworkManager is enabled and running [ DONE ] Preparing OpenStack Client entries [ DONE ] Preparing Horizon entries [ DONE ] Preparing Swift builder entries [ DONE ] Preparing Swift proxy entries [ DONE ] Preparing Swift storage entries [ DONE ] Preparing Heat entries [ DONE ] Preparing Heat CloudFormation API entries [ DONE ] Preparing Gnocchi entries [ DONE ] Preparing Redis entries [ DONE ] Preparing Ceilometer entries [ DONE ] Preparing Aodh entries [ DONE ] Preparing Puppet manifests [ DONE ] Copying Puppet modules and manifests [ DONE ] Applying 192.168.100.130_controller.pp [ DONE ] Applying 192.168.100.130_network.pp [ DONE ] Applying 192.168.100.131_compute.pp [ DONE ] Applying 192.168.100.130_compute.pp [ DONE ] Applying Puppet manifests [ DONE ] Finalizing [ DONE ] **** Installation completed successfully **** Additional information: * Parameter CONFIG_NEUTRON_L2_AGENT: You have chosen OVN Neutron backend. Note that this backend does not support the VPNaaS plugin. Geneve will be used as the encapsulation method for tenant networks * Time synchronization installation was skipped. Please note that unsynchronized time on server instances might be problem for some OpenStack components. * File /root/keystonerc_admin has been created on OpenStack client host192.168.100.130. To use the command line tools you need to source the file. * To access the OpenStack Dashboard browse to http://192.168.100.130/dashboard. Please, find your login credentials stored in the keystonerc_admin in your home directory. * The installation log file is available at: /var/tmp/packstack/20251121-094156-e15lwv6y/openstack-setup.log * The generated manifests are available at: /var/tmp/packstack/20251121-094156-e15lwv6y/manifests 

安装验证与后续配置

启用 network 服务

💡 重要说明:在RHEL 8/CentOS Stream 8中,网络管理已转向NetworkManager。但为了与OpenStack兼容,我们使用传统的network服务。
[root@controller ~]# systemctl start network[root@controller ~]# systemctl enable network network.service is not a native service, redirecting to systemd-sysv-install. Executing: /usr/lib/systemd/systemd-sysv-install enable network [root@controller ~]# systemctl status network ● network.service - LSB: Bring up/down networking Loaded: loaded (/etc/rc.d/init.d/network; generated) Active: active (exited) since Fri 2025-11-21 10:07:46 CST; 11s ago Docs: man:systemd-sysv-generator(8) Tasks: 0(limit: 49261) Memory: 0B CGroup: /system.slice/network.service 

计算节点启用 network

[root@compute ~]# dnf install -y network-scripts[root@compute ~]# systemctl start network[root@compute ~]# systemctl enable network network.service is not a native service, redirecting to systemd-sysv-install. Executing: /usr/lib/systemd/systemd-sysv-install enable network [root@compute ~]# systemctl status network ● network.service - LSB: Bring up/down networking Loaded: loaded (/etc/rc.d/init.d/network; generated) Active: active (exited) since Fri 2025-11-21 10:08:20 CST; 12s ago Docs: man:systemd-sysv-generator(8) Tasks: 0(limit: 49261) Memory: 0B CGroup: /system.slice/network.service 
💡 重要提示:在CentOS Stream 8中,network-scripts包提供了network服务,需要单独安装。

常见问题解决

问题1:安装过程中SSH密码提示

现象

[email protected]'s password: 

解决方法

  1. 确保/root/.ssh/id_rsa.pub存在
  2. 输入密码后,再次运行packstack

在控制节点上执行:

ssh-copy-id [email protected] 

问题2:NTP同步问题

现象:时间不同步导致OpenStack服务启动失败

解决方法

  1. 确保所有节点都配置了正确的NTP服务器
  2. 确保所有节点的时间源都显示为^*(表示同步成功)

在计算节点上执行:

chronyc sources 

在控制节点上执行:

chronyc sources 

问题3:网络配置错误

现象:安装后无法访问OpenStack Dashboard

解决方法

  1. 检查/etc/hosts文件是否正确配置
  2. 确保防火墙已禁用或配置了正确的规则
  3. 确保/etc/sysconfig/network-scripts/ifcfg-ens160配置正确

检查网络接口配置:

ip addr show 

访问 OpenStack Dashboard

  1. 打开浏览器,访问:http://192.168.100.130/dashboard
  2. 使用用户名:admin
  3. 使用密码:redhat(或你设置的密码)

Read more

旧电脑秒变 AI 员工:OpenClaw 本地部署教程(含环境配置 + 插件开发 + 常见坑)

旧电脑秒变 AI 员工:OpenClaw 本地部署教程(含环境配置 + 插件开发 + 常见坑)

前言 本文基于最新OpenClaw版本编写,适配电脑低配置场景(最低2vCPU+2GiB内存+40GiB SSD),兼容Windows 10/11(优先WSL2)、Ubuntu 20.04+系统,全程纯操作指令,覆盖环境配置、本地部署、插件开发、高频坑排查。核心解决部署卡顿、国内网络适配、插件开发无思路、报错无法排查四大痛点,全程适配国内网络(国内镜像源)、国内大模型(通义千问、阿里云百炼等),无需海外代理,可稳定运行实现自动化办公(文件处理、IM对接、任务调度等)。 一、前置准备(适配优化) 1.1 硬件要求(最低适配) * CPU:Intel i3 4代+/AMD Ryzen 3 2000+(支持虚拟化,

By Ne0inhk
Flutter 组件 zxcvbnm 的适配 鸿蒙Harmony 实战 - 驾驭极致密码强度评估、实现鸿蒙端金融级账户准入安全与人性化安全感知的深度方案

Flutter 组件 zxcvbnm 的适配 鸿蒙Harmony 实战 - 驾驭极致密码强度评估、实现鸿蒙端金融级账户准入安全与人性化安全感知的深度方案

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.ZEEKLOG.net Flutter 组件 zxcvbnm 的适配 鸿蒙Harmony 实战 - 驾驭极致密码强度评估、实现鸿蒙端金融级账户准入安全与人性化安全感知的深度方案 前言 在鸿蒙(OpenHarmony)构建的全场景安全体系中,“账号安全”是所有隐私防护的起点。我们绝大多数开发者在处理用户注册时,依然采用 length > 6 这种极其原始的校验逻辑。殊不知,像 password123 这种符合长度规则的密码,在现代暴力破解算法面前几乎是瞬间沦陷。 如何让你的鸿蒙 App 具备一眼识破“弱密码”的火眼金睛?如何在高频率交互的注册界面实现秒级的安全评级? zxcvbnm 是一款基于波斯纳算法(zxcvbn)的高性能 Dart 实现。它不是简单的正则匹配,而是扫描字典、日期、序列乃至常用键盘模式,给出一个 0 到

By Ne0inhk
Flutter 组件 dascade 的适配 鸿蒙Harmony 实战 - 驾驭级联式异步数据流、实现鸿蒙端响应式 UI 状态泵与复杂业务逻辑解耦方案

Flutter 组件 dascade 的适配 鸿蒙Harmony 实战 - 驾驭级联式异步数据流、实现鸿蒙端响应式 UI 状态泵与复杂业务逻辑解耦方案

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.ZEEKLOG.net Flutter 组件 dascade 的适配 鸿蒙Harmony 实战 - 驾驭级联式异步数据流、实现鸿蒙端响应式 UI 状态泵与复杂业务逻辑解耦方案 前言 在鸿蒙(OpenHarmony)的大型复杂应用开发中,我们最头疼的问题往往不是单一接口的调用,而是“由于一个操作引发的连锁数据反应”。例如:当用户在鸿蒙平板上切换了一个项目的 ID,系统需要同时刷新任务列表、参与人员、最近讨论以及对应的缓存指纹,且这些操作往往互有依赖、顺序敏感。 如果你依然在 Activity 或 Widget 中写满了一层层的 then() 或是各种脏乱的 setState(),那么业务逻辑的“级联爆炸”将不可避免。 dascade 是一款专为级联式数据流(Cascading Streams)设计的轻量化状态管理工具。它能将复杂的异步逻辑链条抽象为一组可插拔、可观测的“级联节点”

By Ne0inhk