Contents
1.计算服务概览
使用OpenStack计算服务来托管和管理云计算系统。OpenStack计算服务是基础设施即服务(IaaS)系统的主要部分,模块主要由Python实现。
OpenStack计算组件请求OpenStack Identity服务进行认证;请求OpenStack Image服务提供磁盘镜像;为OpenStack dashboard提供用户与管理员接口。磁盘镜像访问限制在项目与用户上;配额以每个项目进行设定(例如,每个项目下可以创建多少实例)。OpenStack组件可以在标准硬件上水平大规模扩展,并且下载磁盘镜像启动虚拟机实例。
OpenStack计算服务由下列组件所构成:
- nova-api 服务
接收和响应来自最终用户的计算API请求。此服务支持OpenStack计算服务API,Amazon EC2 API,以及特殊的管理API用于赋予用户做一些管理的操作。它会强制实施一些规则,发起多数的编排活动,例如运行一个实例。
nova-api-metadata 服务
接受来自虚拟机发送的元数据请求。“nova-api-metadata“服务一般在安装“nova-network“服务的多主机模式下使用。更详细的信息,请参考OpenStack管理员手册中的链接`Metadata service <http://docs.openstack.org/admin-guide/compute-networking-nova.html#metadata-service>`__ in the OpenStack Administrator Guide。
- nova-compute服务
一个持续工作的守护进程,通过Hypervior的API来创建和销毁虚拟机实例。例如:
-
XenServer/XCP 的 XenAPI
-
KVM 或 QEMU 的 libvirt
-
VMware 的 VMwareAPI
过程是蛮复杂的。最为基本的,守护进程同意了来自队列的动作请求,转换为一系列的系统命令如启动一个KVM实例,然后,到数据库中更新它的状态。
- nova-scheduler服务
拿到一个来自队列请求虚拟机实例,然后决定那台计算服务器主机来运行它。
- nova-conductor模块
媒介作用于“nova-compute“服务与数据库之间。它排除了由“nova-compute“服务对云数据库的直接访问。nova-conductor模块可以水平扩展。但是,不要将它部署在运行“nova-compute“服务的主机节点上。参考Configuration Reference Guide <http://docs.openstack.org/mitaka/config-reference/compute/conductor.html>`__。
- nova-cert模块
服务器守护进程向Nova Cert服务提供X509证书。用来为“euca-bundle-image“生成证书。仅仅是在EC2 API的请求中使用
- nova-network worker 守护进程
与“nova-compute“服务类似,从队列中接受网络任务,并且操作网络。执行任务例如创建桥接的接口或者改变IPtables的规则。
- nova-consoleauth 守护进程
授权控制台代理所提供的用户令牌。详情可查看“nova-novncproxy“和 nova-xvpvncproxy。该服务必须为控制台代理运行才可奏效。在集群配置中你可以运行二者中任一代理服务而非仅运行一个nova-consoleauth服务。更多关于nova-consoleauth的信息,请查看`About nova-consoleauth <http://docs.openstack.org/admin-guide/compute-remote-console-access.html#about-nova-consoleauth>`__。
- nova-novncproxy 守护进程
提供一个代理,用于访问正在运行的实例,通过VNC协议,支持基于浏览器的novnc客户端。
- nova-spicehtml5proxy 守护进程
提供一个代理,用于访问正在运行的实例,通过 SPICE 协议,支持基于浏览器的 HTML5 客户端。
- nova-xvpvncproxy 守护进程
提供一个代理,用于访问正在运行的实例,通过VNC协议,支持OpenStack特定的Java客户端。
- nova-cert 守护进程
X509 证书。
- nova客户端
用于用户作为租户管理员或最终用户来提交命令。
- 队列
一个在守护进程间传递消息的中央集线器。常见实现有`RabbitMQ <http://www.rabbitmq.com/>`__ , 以及如`Zero MQ <http://www.zeromq.org/>`__等AMQP消息队列。
- SQL数据库
存储构建时和运行时的状态,为云基础设施,包括有:
1.可用实例类型 2.使用中的实例 3.可用网络 4.项目
理论上,OpenStack计算可以支持任何和SQL-Alchemy所支持的后端数据库,通常使用SQLite3来做测试可开发工作,MySQL和PostgreSQL 作生产环境。
1.1Nova服务相关名词介绍:
API:负责接收和响应外部请求。支持OpenStackAPI
Cert:提供证书,负责身份认证。
Scheduler:用于云主机调度。
Conductor:计算节点访问数据的中间件。
Consoleauth:用于控制台的授权验证。
Novncproxy:VNC代理;提供一个代理,用于访问正在运行的实例,通过VNC协议,支持基于浏览器的novnc客户端
2.安装计算服务(nova)
这一部分讲述的是 nova
在控制节点(compute)上的部署
2.1安装及配置控制节点(controller)
2.1.1先决条件
在安装和配置 Compute 服务前,你必须创建数据库服务的凭据以及 API endpoints(创建一个数据库和管理令牌)。
1)创建Nove数据库并授予合适的权限,完成以下操作
- 用数据库连接客户端以 root 用户连接到数据库服务器:
[root@controller ~]# mysql -uroot -p123456 #创建 nova_api 和 nova 数据库: CREATE DATABASE nova_api; CREATE DATABASE nova; #对数据库进行正确的授权: GRANT ALL PRIVILEGES ON nova_api.* TO 'nova'@'localhost' \ IDENTIFIED BY 'NOVA_DBPASS'; GRANT ALL PRIVILEGES ON nova_api.* TO 'nova'@'%' \ IDENTIFIED BY 'NOVA_DBPASS'; GRANT ALL PRIVILEGES ON nova.* TO 'nova'@'localhost' \ IDENTIFIED BY 'NOVA_DBPASS'; GRANT ALL PRIVILEGES ON nova.* TO 'nova'@'%' \ IDENTIFIED BY 'NOVA_DBPASS'; #注释说明: 用合适的密码代替 NOVA_DBPASS。 退出数据库客户端。
2)获得 admin 凭证来获取只有管理员能执行的命令的访问权限
[root@controller ~]# source admin-openrc
3)创建服务证书,如下操作
- 创建 nova 用户:
[root@controller ~]# openstack user create --domain default --password NOVA_PASS nova
+-----------+----------------------------------+
| Field | Value |
+-----------+----------------------------------+
| domain_id | 30c495cbb6e145cd9e70ffb825c0c710 |
| enabled | True |
| id | a825d77d2bbf4a6c81d7df7a9299012d |
| name | nova |
+-----------+----------------------------------+
- 给 nova 用户添加 admin 角色:
[root@controller ~]# openstack role add --project service --user nova admin
- 创建 nova 服务实体和Compute 服务 API 端点:
#创建 nova 服务实体 [root@controller ~]# openstack service create --name nova \ --description "OpenStack Compute" compute +-------------+----------------------------------+ | Field | Value | +-------------+----------------------------------+ | description | OpenStack Compute | | enabled | True | | id | 782b58802a344d7394e236700199bd71 | | name | nova | | type | compute | +-------------+----------------------------------+ #创建endpoint端点 [root@controller ~]# openstack endpoint create --region RegionOne \ compute public http://controller:8774/v2.1/%\(tenant_id\)s +--------------+-------------------------------------------+ | Field | Value | +--------------+-------------------------------------------+ | enabled | True | | id | 0df8964a05334447bb20555f17ddca6c | | interface | public | | region | RegionOne | | region_id | RegionOne | | service_id | 782b58802a344d7394e236700199bd71 | | service_name | nova | | service_type | compute | | url | http://controller:8774/v2.1/%(tenant_id)s | +--------------+-------------------------------------------+ [root@controller ~]# openstack endpoint create --region RegionOne \ compute internal http://controller:8774/v2.1/%\(tenant_id\)s +--------------+-------------------------------------------+ | Field | Value | +--------------+-------------------------------------------+ | enabled | True | | id | e25efa022dd4476c9933ed7c52736e3f | | interface | internal | | region | RegionOne | | region_id | RegionOne | | service_id | 782b58802a344d7394e236700199bd71 | | service_name | nova | | service_type | compute | | url | http://controller:8774/v2.1/%(tenant_id)s | +--------------+-------------------------------------------+ [root@controller ~]# openstack endpoint create --region RegionOne \ compute admin http://controller:8774/v2.1/%\(tenant_id\)s +--------------+-------------------------------------------+ | Field | Value | +--------------+-------------------------------------------+ | enabled | True | | id | b987ba8b881740ebb1a31f47296525f3 | | interface | admin | | region | RegionOne | | region_id | RegionOne | | service_id | 782b58802a344d7394e236700199bd71 | | service_name | nova | | service_type | compute | | url | http://controller:8774/v2.1/%(tenant_id)s | +--------------+-------------------------------------------+
- 检查验证结果
[root@controller ~]# openstack endpoint list +----------------------------------+-----------+--------------+--------------+---------+-----------+-------------------------------------------+ | ID | Region | Service Name | Service Type | Enabled | Interface | URL | +----------------------------------+-----------+--------------+--------------+---------+-----------+-------------------------------------------+ | 0df8964a05334447bb20555f17ddca6c | RegionOne | nova | compute | True | public | http://controller:8774/v2.1/%(tenant_id)s | | 56499eb404fa4d7fbc26c5f4506289d7 | RegionOne | keystone | identity | True | public | http://controller:5000/v3 | | 5fc6280579e648bc80eda2ce9374f79b | RegionOne | glance | image | True | admin | http://controller:9292 | | b987ba8b881740ebb1a31f47296525f3 | RegionOne | nova | compute | True | admin | http://controller:8774/v2.1/%(tenant_id)s | | ccd726240ec3491d9955724aefade07b | RegionOne | glance | image | True | public | http://controller:9292 | | d0cb9d0f5b2f45e2a45978fb693ce233 | RegionOne | glance | image | True | internal | http://controller:9292 | | e25efa022dd4476c9933ed7c52736e3f | RegionOne | nova | compute | True | internal | http://controller:8774/v2.1/%(tenant_id)s | | e50e7a9aac1047e187720be3dc447bde | RegionOne | keystone | identity | True | internal | http://controller:5000/v3 | | fc7d265a36f6482d99ab917e82ec6ec2 | RegionOne | keystone | identity | True | admin | http://controller:35357/v3 | +----------------------------------+-----------+--------------+--------------+---------+-----------+-------------------------------------------+ [root@controller ~]# openstack service list +----------------------------------+----------+----------+ | ID | Name | Type | +----------------------------------+----------+----------+ | 3da8ad2eb4924f6690da54a54d20ed47 | glance | image | | 782b58802a344d7394e236700199bd71 | nova | compute | | bf3be01318d24c3aba709844bb7de4fb | keystone | identity | +----------------------------------+----------+----------+ [root@controller ~]# openstack user list +----------------------------------+--------+ | ID | Name | +----------------------------------+--------+ | 1273330670a44844b1726a0d49d16ebf | demo | | 80f3ce85301d43e3b653c0c3e05b4c61 | admin | | 82cbea912a644fd78977c89bcf76988a | glance | | a825d77d2bbf4a6c81d7df7a9299012d | nova | +----------------------------------+--------+ [root@controller ~]# openstack role list +----------------------------------+-------+ | ID | Name | +----------------------------------+-------+ | 6ad97cd5fbc3476a98f8ccc7835a7217 | admin | | b1c08a167bb44527b6db7b7a17102c8e | user | +----------------------------------+-------+ [root@controller ~]# openstack host list +------------+-------------+----------+ | Host Name | Service | Zone | +------------+-------------+----------+ | controller | scheduler | internal | | controller | consoleauth | internal | | controller | conductor | internal | +------------+-------------+----------+
2.2安装并配置组件
2.2.1安装软件包(Nove的服务组件)
[root@controller ~]# yum install openstack-nova-api openstack-nova-conductor \ openstack-nova-console openstack-nova-novncproxy \ openstack-nova-scheduler -y
2.2.2编辑“/etc/nova/nova.conf
“文件并完成下面的操作
cp /etc/nova/nova.conf{,.bak} grep '^\[' /etc/nova/nova.conf.bak >/etc/nova/nova.conf vim /etc/nova/nova.conf
- 在“
[DEFAULT]
“部分,只启用计算和元数据API:
[DEFAULT] ... enabled_apis = osapi_compute,metadata
- 在“
[api_database]
“和“[database]
“部分,配置数据库的连接:
[api_database] ... connection = mysql+pymysql://nova:NOVA_DBPASS@controller/nova_api [database] ... connection = mysql+pymysql://nova:NOVA_DBPASS@controller/nova
用你为 Compute 数据库选择的密码来代替 NOVA_DBPASS。
- 在 “
[DEFAULT]
” 和 “[oslo_messaging_rabbit]
”部分,配置 “RabbitMQ
” 消息队列访问:
[DEFAULT] ... rpc_backend = rabbit [oslo_messaging_rabbit] ... rabbit_host = controller rabbit_userid = openstack rabbit_password = RABBIT_PASS
用你在 “RabbitMQ” 中为 “openstack” 选择的密码替换 “RABBIT_PASS”。
- 在
“[DEFAULT]”
和“[keystone_authtoken]”
部分,配置认证服务访问:
[DEFAULT] ... auth_strategy = keystone [keystone_authtoken] ... auth_uri = http://controller:5000 auth_url = http://controller:35357 memcached_servers = controller:11211 auth_type = password project_domain_name = default user_domain_name = default project_name = service username = nova password = NOVA_PASS
使用你在身份认证服务中设置的“nova“ 用户的密码替换“NOVA_PASS“。
- 在
[DEFAULT]
部分,配置``my_ip`
` 来使用控制节点的管理接口的IP 地址。
[DEFAULT] ... my_ip = 118.190.201.11
- 在
[DEFAULT]
部分,配置Networking
服务:
[DEFAULT] ... use_neutron = True firewall_driver = nova.virt.firewall.NoopFirewallDriver
- 在“
[vnc]
“部分,配置VNC代理使用控制节点的管理接口IP地址 :
[vnc] ... vncserver_listen = $my_ip vncserver_proxyclient_address = $my_ip
- 在
[glance]
区域,配置镜像服务 API 的位置:
[glance] ... api_servers = http://controller:9292
- 在
[oslo_concurrency]
部分,配置锁路径:
[oslo_concurrency] ... lock_path = /var/lib/nova/tmp
- MD5值如下
[root@controller ~]# md5sum /etc/nova/nova.conf
b6118aadce11365fc626f508e0401660 /etc/nova/nova.conf
2.2.2.1文件“/etc/nova/nova.conf
“的内容如下
[root@controller ~]# cat /etc/nova/nova.conf [DEFAULT] enabled_apis = osapi_compute,metadata rpc_backend = rabbit auth_strategy = keystone my_ip = 118.190.201.11 use_neutron = True firewall_driver = nova.virt.firewall.NoopFirewallDriver [api_database] connection = mysql+pymysql://nova:NOVA_DBPASS@controller/nova_api [barbican] [cache] [cells] [cinder] [conductor] [cors] [cors.subdomain] [database] connection = mysql+pymysql://nova:NOVA_DBPASS@controller/nova [ephemeral_storage_encryption] [glance] api_servers = http://controller:9292 [guestfs] [hyperv] [image_file_url] [ironic] [keymgr] [keystone_authtoken] auth_uri = http://controller:5000 auth_url = http://controller:35357 memcached_servers = controller:11211 auth_type = password project_domain_name = default user_domain_name = default project_name = service username = nova password = NOVA_PASS [libvirt] [matchmaker_redis] [metrics] [neutron] [osapi_v21] [oslo_concurrency] lock_path = /var/lib/nova/tmp [oslo_messaging_amqp] [oslo_messaging_notifications] [oslo_messaging_rabbit] rabbit_host = controller rabbit_userid = openstack rabbit_password = RABBIT_PASS [oslo_middleware] [oslo_policy] [rdp] [serial_console] [spice] [ssl] [trusted_computing] [upgrade_levels] [vmware] [vnc] vncserver_listen = $my_ip vncserver_proxyclient_address = $my_ip [workarounds] [xenserver]
2.2.3同步Compute 数据库
[root@controller ~]# su -s /bin/sh -c "nova-manage api_db sync" nova
[root@controller ~]# su -s /bin/sh -c "nova-manage db sync" nova
#忽略上述命令其中输出的不推荐信息
[root@controller ~]# mysql -uroot -p123456 -e "use nova;show tables;"|wc -l
110
[root@controller ~]# mysql -uroot -p123456 -e "use nova_api;show tables;"|wc -l
10
2.2.4完成安装,设置为随系统启动
~]# systemctl enable openstack-nova-api.service \ openstack-nova-consoleauth.service openstack-nova-scheduler.service \ openstack-nova-conductor.service openstack-nova-novncproxy.service ~]# systemctl start openstack-nova-api.service \ openstack-nova-consoleauth.service openstack-nova-scheduler.service \ openstack-nova-conductor.service openstack-nova-novncproxy.service
验证Nova服务状态
[root@controller ~]# openstack host list
+------------+-------------+----------+
| Host Name | Service | Zone |
+------------+-------------+----------+
| controller | consoleauth | internal |
| controller | scheduler | internal |
| controller | conductor | internal |
+------------+-------------+----------+
3安装及配置计算节点(compute1)
这部分操作是 nova
在计算节点(compute)上的部署
注释说明: 计算节点需支持对虚拟化的硬件加速,每个额外的计算节点都需要一个唯一的IP地址。
3.1安装并配置组件
3.1.1安装软件包
[root@compute1 ~]# yum install openstack-nova-compute -y #出现错误提示需要依赖包 解决方法: YUM仓库进行安装yum install openstack-nova-compute -y,安装后执行如下命令 ~]# \mv $(find /var/cache/yum/x86_64/ -name "*rpm") /usr/share/nginx/html/repo/ ~]# createrepo --update /usr/share/nginx/html/repo/ #回到计算节点安装 [root@compute1 ~]# yum clean all [root@compute1 ~]# yum install openstack-nova-compute -y Error: Package: spice-server-0.14.0-2.el7_5.4.x86_64 (openstack) Requires: libjpeg.so.62(LIBJPEG_6.2)(64bit) 提示需要依赖包,但是检查YUM仓库已经有了,所有执行下面命令 [root@compute1 ~]# yum upgrade #重新执行安装命令即可 [root@compute1 ~]# yum install openstack-nova-compute -y #或者下面的方法更方便 rpm -ivh http://mirror.centos.org/centos/7/os/x86_64/Packages/libjpeg-turbo-1.2.90-5.el7.x86_64.rpm yum install openstack-nova-compute -y 我搭建的是本地仓库下载本地的 rpm -ivh http://118.190.201.38/repo/libjpeg-turbo-1.2.90-5.el7.x86_64.rpm
3.1.2编辑“/etc/nova/nova.conf
“文件并完成下面的操作
cp /etc/nova/nova.conf{,.bak} grep '^\[' /etc/nova/nova.conf.bak >/etc/nova/nova.conf vim /etc/nova/nova.conf
- 在“
[DEFAULT]
“ 和[oslo_messaging_rabbit]
部分,配置“RabbitMQ
“消息队列的连接:
[DEFAULT] ... rpc_backend = rabbit [oslo_messaging_rabbit] ... rabbit_host = controller rabbit_userid = openstack rabbit_password = RABBIT_PASS
用你在 “RabbitMQ” 中为 “openstack” 选择的密码替换 “RABBIT_PASS”。
- 在 “
[DEFAULT]
” 和 “[keystone_authtoken]
” 部分,配置认证服务访问:
[DEFAULT] ... auth_strategy = keystone [keystone_authtoken] ... auth_uri = http://controller:5000 auth_url = http://controller:35357 memcached_servers = controller:11211 auth_type = password project_domain_name = default user_domain_name = default project_name = service username = nova password = NOVA_PASS
使用你在身份认证服务中设置的“nova“ 用户的密码替换“NOVA_PASS“。
- 在
[DEFAULT]
部分,配置 my_ip(MANAGEMENT_INTERFACE_IP_ADDRESS-管理接口地址) 选项:
[DEFAULT] ... my_ip = MANAGEMENT_INTERFACE_IP_ADDRESS
将其中的 MANAGEMENT_INTERFACE_IP_ADDRESS 替换为计算节点上的管理网络接口的IP 地址,例如这里所示的第一个节点 118.190.201.31
- 在
[DEFAULT]
部分,使能Networking
服务:
[DEFAULT] ... use_neutron = True firewall_driver = nova.virt.firewall.NoopFirewallDriver
注释说明:
缺省情况下,Compute 使用内置的防火墙服务。由于 Networking 包含了防火墙服务,所以你必须通过使用 nova.virt.firewall.NoopFirewallDriver 来去除 Compute 内置的防火墙服务。
- 在“
[vnc]
“部分,启用并配置远程控制台访问:
[vnc] ... enabled = True vncserver_listen = 0.0.0.0 vncserver_proxyclient_address = $my_ip novncproxy_base_url = http://controller:6080/vnc_auto.html
服务器组件监听所有的 IP 地址,而代理组件仅仅监听计算节点管理网络接口的 IP 地址。基本的 URL 指示您可以使用 web 浏览器访问位于该计算节点上实例的远程控制台的位置。
- 在
[glance]
区域,配置镜像服务 API 的位置:
[glance] ... api_servers = http://controller:9292
- 在
[oslo_concurrency]
部分,配置锁路径:
[oslo_concurrency] ... lock_path = /var/lib/nova/tmp
- MD5值及内容如下
#MD5值 [root@compute1 ~]# md5sum /etc/nova/nova.conf 34c1b255c8796cc64eb94d69c0ae8504 /etc/nova/nova.conf #配置文件的内容 [root@compute1 ~]# cat /etc/nova/nova.conf [DEFAULT] rpc_backend = rabbit auth_strategy = keystone my_ip = 118.190.201.31 use_neutron = True firewall_driver = nova.virt.firewall.NoopFirewallDriver [api_database] [barbican] [cache] [cells] [cinder] [conductor] [cors] [cors.subdomain] [database] [ephemeral_storage_encryption] [glance] api_servers = http://controller:9292 [guestfs] [hyperv] [image_file_url] [ironic] [keymgr] [keystone_authtoken] auth_uri = http://controller:5000 auth_url = http://controller:35357 memcached_servers = controller:11211 auth_type = password project_domain_name = default user_domain_name = default project_name = service username = nova password = NOVA_PASS [libvirt] [matchmaker_redis] [metrics] [neutron] [osapi_v21] [oslo_concurrency] lock_path = /var/lib/nova/tmp [oslo_messaging_amqp] [oslo_messaging_notifications] [oslo_messaging_rabbit] rabbit_host = controller rabbit_userid = openstack rabbit_password = RABBIT_PASS [oslo_middleware] [oslo_policy] [rdp] [serial_console] [spice] [ssl] [trusted_computing] [upgrade_levels] [vmware] [vnc] enabled = True vncserver_listen = 0.0.0.0 vncserver_proxyclient_address = $my_ip novncproxy_base_url = http://controller:6080/vnc_auto.html [workarounds] [xenserver]
3.1.3完成安装
1.确定您的计算节点是否支持虚拟机的硬件加速
[root@compute1 ~]# egrep -c '(vmx|svm)' /proc/cpuinfo 2
如果这个命令返回了 one or greater 的值,那么你的计算节点支持硬件加速且不需要额外的配置。
如果这个命令返回了 zero 值,那么你的计算节点不支持硬件加速。你必须配置 libvirt 来使用 QEMU 去代替 KVM
-
在
/etc/nova/nova.conf
文件的[libvirt]
区域做出如下的编辑:
[libvirt] ... virt_type = qemu
其中(…)代表的是默认的配置文件内容
2.启动计算服务及其依赖,并将其配置为随系统自动启动
~]# systemctl enable libvirtd.service openstack-nova-compute.service ~]# systemctl start libvirtd.service openstack-nova-compute.service
4.验证操作
验证计算服务的操作,在控制节点上执行这些命令
4.1获得 admin 凭证来获取只有管理员能执行的命令的访问权限
[root@controller ~]# source admin-openrc
4.2列出服务组件,以验证是否成功启动并注册了每个进程
[root@controller ~]# openstack compute service list +----+------------------+------------+----------+---------+-------+----------------------------+ | Id | Binary | Host | Zone | Status | State | Updated At | +----+------------------+------------+----------+---------+-------+----------------------------+ | 1 | nova-consoleauth | controller | internal | enabled | up | 2018-07-17T08:15:34.000000 | | 2 | nova-scheduler | controller | internal | enabled | up | 2018-07-17T08:15:38.000000 | | 3 | nova-conductor | controller | internal | enabled | up | 2018-07-17T08:15:38.000000 | | 7 | nova-compute | compute1 | nova | enabled | up | 2018-07-17T08:15:33.000000 | +----+------------------+------------+----------+---------+-------+----------------------------+
Get busy living or get busy dying. 努力活出精彩的人生,否则便如行尸走肉
- 转载请注明来源:OpenStack系列四之计算服务Nova
- 本文永久链接地址:https://www.xionghaier.cn/archives/521.html