怎么用CloudStack配置和管理云环境

70次阅读
没有评论

共计 12165 个字符,预计需要花费 31 分钟才能阅读完成。

这篇文章主要为大家展示了“怎么用 CloudStack 配置和管理云环境”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让丸趣 TV 小编带领大家一起研究并学习一下“怎么用 CloudStack 配置和管理云环境”这篇文章吧。

CloudStack 前身为 cloud.com 的商业化产品,它在 2011 年被 Ctrix 以超过二亿美金价格收购,随后又在今年被捐献给 Apache 基金会。这项产品开源的举措,引起了市场对 IaaS 发展路线的一些争议,例如它与另外一个开源产品 OpenStack 的竞争与合作关系?

OpenStack 是由 Rackspace 和 NASA 主导开发的一个 IaaS,它拥有更大的用户群,包括 HP,IBM,Dell 和 Redhat 等大公司。表 1 列出了 CloudStack 与 OpenStack 的一些对比。

表 1.CloudStack 与 OpenStack 的对比

怎么用 CloudStack 配置和管理云环境

附:比较数据截止至 2012 年中,对应的软件版本为 CloudStack 3 和 OpenStack Essex。

可以认为,在市场上 CloudStack 和 OpenStack 这两个 IaaS 平台存在不同的功能、客户和发展路线,前者作为曾经的商业软件,已经被证明为可以可靠的用于生产系统;而后者,虽则目前缺少广泛的真实用户,却拥有更多的大公司支持。这是它们显著的不同。

尽管如此,但从技术而言,它们背后的源代码贡献者并不是一定不同的,经常有来自同一家公司的开发人员为这两个开源项目提交代码。从这个角度说,两个平台在某一天的合并也不会令人惊奇。

还存在其它众多的 IaaS 产品(例如 Eucalyptus,Nebula 等),可以在文末的 参考资源中找到一些介绍。总体而言,这些产品当中 CloudStack 和 OpenStack 是特性最为相近、也是最引起争论的,参考资源中的一篇文章提及到了最近发生的一个有趣争论。

CloudStack 架构图

CloudStack 采用了典型的分层结构:客户端、核心引擎、以及资源层。它面向各类型的客户提供了不同的访问方式:Web Console、Command Shell 和 Web Service API。通过它们,用户可以管理使用在其底层的计算资源(又分为主机、网络和存储),完成诸如在主机上分配虚拟机,配给虚拟磁盘等功能。见图 1。

怎么用 CloudStack 配置和管理云环境

图 1. 系统架构图

虚拟机如果使用 Xen 和 KVM,需要安装 CloudStack Agent 来支持其与管理服务器的交互。而管理服务器和 Xen Server 交互则是靠 XAPI,和 vCenter、ESX 交互靠 HTTP。

当部署 CloudStack 时,需要了解它的层次结构和存储管理,见图 2。

怎么用 CloudStack 配置和管理云环境

图 2. 部署图

Zone:Zone 对应于现实中的一个数据中心,它是 CloudStack 中最大的一个单元。

Pod:Pod 对应着一个机架。同一个 pod 中的机器在同一个子网(网段)中。

Cluster:Cluster 是多个主机组成的一个集群。同一个 cluster 中的主机有相同的硬件,相同的 Hypervisor,和共用同样的存储。同一个 cluster 中的虚拟机,可以实现无中断服务地从一个主机迁移到另外一个上。

Host:Host 就是运行虚拟机(VM)的主机。

即从包含关系上来说,一个 zone 包含多个 pod,一个 pod 包含多个 cluster,一个 cluster 包含多个 host。

CloudStack 中存在两种存储:

Primary storage:一级存储与 cluster 关联,它为该 cluster 中的主机的全部虚拟机提供磁盘卷。一个 cluster 至少有一个一级存储,且在部署时位置要临近主机以提供高性能。

Secondary storage:二级存储与 zone 关联,它存储模板文件,ISO 镜像和磁盘卷快照。

模板:可以启动虚拟机的操作系统镜像,也包括了诸如已安装应用的其余配置信息。

ISO 镜像:包含操作系统数据或启动媒质的磁盘镜像。

磁盘卷快照:虚拟机数据的已储存副本,能用于数据恢复或者创建新模板。

安装 CloudStack

环境准备

一个完整的 CloudStack 环境包括两部分:

管理服务器(Management Server)

虚拟机管理器 (Hypervisor)

附:通常对 CloudStack 的 hypervisor 也有另外的称呼,例如主机(host),代理(agent)等。本文统一为 hypervisor。

在本文的安装步骤中,所要配置的为一个简单网络,即所有被管理的虚拟机都位于一个网段。相应的硬件如下:

怎么用 CloudStack 配置和管理云环境

表 2. 软硬件环境

本次安装中 CloudStack 的版本为:Red Hat Enterprise Linux/CentOS 6.2

Hypervisor 为 KVM。

管理服务器需要更多的存储空间是因为 NFS 也建在该机上。更多的详细安装需求可以参阅 CloudStack 官网的指南。这里需要着重列出的问题为:

Q1:官网的安装要求中哪些软硬件因素容易导致 CloudStack 的安装失败?

Hypervisor 所在的主机,要求 CPU 和主板支持硬件虚拟化(本人的机器是 DELL 台式机,需要在主板的 BIOS 中设置 Intel-VT 为 enable)。

操作系统必须是 64 位的,推荐 centos 6.2(当前最新的 CloudStack 3 支持 6.2)。如果使用 5.5 或者 6.0 版本,一定要选择匹配的 CloudStack 安装包。Ubuntu 目前只有运行在 10.04 平台上的发行版,且该 release 不是最新的 CloudStack。此处强烈建议新用户给 Managment Server 和 Hypervisor 所在的两台主机选择一样的操作系统(推荐 centos/redhat)和一样版本的 CloudStack 软件,同时注意 OS 一定是要被官方 release 宣称支持,这样能避免走不少弯路。例如确实也存在有人能成功在 Ubuntu 12.04 或 centos 6.3(官方 2012 年 9 月尚未宣称支持)上部署 CloudStack,但付出精力较大。

Hypervisor 的主机不能有任何正在运行的虚拟机,否则在后续的 add host 操作中会遇到失败。最佳的建议是 hypervisor 主机上的操作系统为全新安装,且没有部署任何其余虚拟机。

无论是管理服务器还是 hypervisor 所在主机,都需要以 root 登录进行 CloudStack 安装。

Management Server 和 Hypervisor 主机必须是有独立静态 IP 的主机。否则后续安装因为 IP 地址变化会导致 service 状态异常。

CentOS 安装后的默认网络配置为 DHCP,需修改为手工分配 IP,这步操作要在 cloud-server 和 cloud-agent 两台机器都进行:

点击桌面右上角的网络图标,编辑网络:

怎么用 CloudStack 配置和管理云环境

图 3

Method 原来为“DHCP”,改成设置为“Manual”,然后输入静态 IP 地址、掩码、网关、DNS 服务器信息。

怎么用 CloudStack 配置和管理云环境

图 4

安装 Management Server

以 root 身份登录 cloud-server.squirrel.org。

运行“hostname ndash; fqdn”,检查其返回的格式必须是包括域名的全称(例如 cloud-server.squirrel.org)。Hostname 最好是在安装 centos 时即设置好,否则需要在 /etc/hosts 和 /etc/sysconfig/network 两处文件中同时修改才可以永久生效。

设置 SELinux。在 /etc/selinux/config 中修改“SELINUX=enforcing”为“SELINUX=permissive”,并在 shell 中运行“setenforce permissive”令其立即生效。

进入下载并解压好的 CloudStack 安装目录 (我这里是 /home/squirrel/mybox/cloud/CloudStack-oss-3.0.2-1-rhel6.2),运行命令“./install.sh”,选择“M”安装 Management Server 软件。

运行下面命令启动 NFS 和 rpcbind 服务,并设置为开机运行:

# service rpcbind start # service nfs start # chkconfig nfs on # chkconfig rpcbind on

再次运行命令“./install.sh”,选择“D”安装数据库 mysql。

编辑 /etc/my.cnf,在 [mysqld] 下面加入内容:

innodb_rollback_on_timeout=1 innodb_lock_wait_timeout=600 max_connections=350 log-bin=mysql-bin binlog-format =  ROW

重启数据库后,设置 root 用户密码。

# service mysqld restart # mysql -u root mysql  SET PASSWORDPASSWORD = PASSWORD(password  mysql  exit

运行 CloudStack 脚本让其自动配置数据库:

#cloud-setup-databases cloud: dbpassword @localhost \ --deploy-as=root: password

即表示以 root 用户身份来生成数据库,该数据库属于新建的 cloud 用户(密码 dbpassword 可以留空)。

最后,下面的命令将完成对操作系统 iptables、sudoers 的设置(CloudStack 本身有安全性方面的要求,不是无限暴露给网络,同时又需要一些管理权限来运行自身服务,因此要做这两项的设置),并启动管理服务器:

#cloud-setup-management

使用“service cloud-management status”查看运行状态。

Q2:第 2 步中运行“hostname ndash; fqdn”命令时,要保证机器是联网状态,才能返回正确的主机名称。

Q3:如果后续打算把 hypervisor 也安装在 management server 的同一台主机上,需要在 /etc/sysconfig/network-scripts/ifcfg- yourPhysicalDeviceName 中配置出对应的信息。

同时,如果该 hypervisor 为 KVM,需要修改 /etc/sudoers,加入如下行:

Defaults:cloud !requiretty

配置 NFS

前面讲过,CloudStack 需要两类存储(primary storage 和 secondary storage)来支持它的 cluster 和 host,本节中由 NFS 来提供这两个存储,因此前述步骤中要启动 NFS 服务。同时为了方便起见,NFS Server 也由 cloud-server.squirrel.org 充当。

以 root 身份登录 cloud-server.squirrel.org。

创建两个目录,分别作为一级和二级存储:

# mkdir -p /export/primary # mkdir -p /export/secondary

编辑文件 /etc/exports,加入:

/export *(rw,async,no_root_squash)

然后导出 /export 目录:

# exportfs -a

编辑 /etc/sysconfig/nfs 文件,取消如下行的注释符号(或者在文件末尾直接添加下列行):

LOCKD_TCPPORT=32803 LOCKD_UDPPORT=32769 MOUNTD_PORT=892 RQUOTAD_PORT=875 STATD_PORT=662 STATD_OUTGOING_PORT=2020

编辑防火墙设置文件 /etc/sysconfig/iptables,在 input 部分最上面加入如下的规则:

-A INPUT -m state --state NEW -p udp --dport 111 -j ACCEPT -A INPUT -m state --state NEW -p tcp --dport 111 -j ACCEPT -A INPUT -m state --state NEW -p tcp --dport 2049 -j ACCEPT -A INPUT -m state --state NEW -p tcp --dport 32803 -j ACCEPT -A INPUT -m state --state NEW -p udp --dport 32769 -j ACCEPT -A INPUT -m state --state NEW -p tcp --dport 892 -j ACCEPT -A INPUT -m state --state NEW -p udp --dport 892 -j ACCEPT -A INPUT -m state --state NEW -p tcp --dport 875 -j ACCEPT -A INPUT -m state --state NEW -p udp --dport 875 -j ACCEPT -A INPUT -m state --state NEW -p tcp --dport 662 -j ACCEPT -A INPUT -m state --state NEW -p udp --dport 662 -j ACCEPT

重启防火墙,并保存修改:

# service iptables restart # service iptables save

在管理服务器(cloud-server.squirrel.org)和 hypervisor 主机(cloud-agent.squirrel.org)上,修改文件 /etc/idmapd.conf,加入如下内容:

Domain = squirrel.org

重启管理服务器的主机,然后测试并挂载 NFS。在 cloud-agent.squirrel.org 机器建立目录 /primarymount,运行如下命令并确认其是否成功:

mount -t nfs 192.168.1.4:/export/primary /primarymount

Q4:在 KVM hypervisor 机器运行 showmount 命令时,如果采用的是 hostname,例如“showmount -e cloud-server.squirrel.org”,并且失败,报错“clnt_create: RPC: Program not registered”,那么可以尝试用 IP 代替:“showmount -e 192.168.1.4”。或者编辑本机的 /etc/hosts,加入对方 server 的 IP- 主机名映射(但这样失去了灵活性):

192.168.1.4 cloud-server.squirrel.org

Q5:第 5 步中新加入规则在防火墙配置文件中的次序对 NFS share 成功很重要,一定要加入 INPUT 区的最开始部分,即系统中原有的 input 项必须在新加入行的后面,否则可能在运行 showmount -e 192.168.1.4 时会出现

clnt_create: RPC: Port mapper failure – Unable to receive: errno 113 (No route to host) 的错误。

Q6:出现错误 mount.nfs: access denied by server while mounting 192.168.1.4:/export/primary 的处理?

有时当运行“showmount -e cloud-server.squirrel.org”有“clnt_create: RPC: Port mapper failure – Unable to receive: errno 111 (Connection refused)”错误提示,然后 mount nfs 失败,会出现标题上的错误信息,这可能跟 NFS 的建立方式有关,有时也跟防火墙有关。需要检查 log:

tail -200 /var/log/messages refused mount request from 192.168.1.5 for /export/primary (/export): illegal port 1024

那么考虑尝试如下方法:

vi /etc/exports

在原来的那一行上修改如下:

/export *(rw,async,insecure,no_root_squash)

然后:

exportfs -rv service nfs restart

在 cloud-agent.squirrel.org 上重新运行命令:

mount -t nfs 192.168.1.4:/export/primary /primarymount

没有提示,应该成功了,可以确认:

mount |grep primary OK !

准备系统虚拟机模板

系统虚拟机模板(System VM Template)保存在二级存储上,是用于创建云平台上的系统虚拟机的。

以 root 身份登录 cloud-server.squirrel.org。

这里下载的是 KVM 模板,运行如下命令安装:

# /usr/lib64/cloud/agent/scripts/storage/secondary/cloud-install-sys-tmplt -m /export/secondary -u http://download.cloud.com/templates/acton/acton-systemvm-02062012.qcow2.bz2 -h kvm -F

依赖于网络速度,这个过程所需时间在几分钟到数小时(笔者的下载速度显示在 2M~3M/s,三分钟左右完成全部下载和安装)。

Q7:这里有两点需要注意:

磁盘分区必须够大。

虚拟机模板的下载安装这步不可省略,否则后面在控制台添加二级存储时会失败。

系统虚拟机不同于普通的 hypervisor host 上的虚拟机,它是 CloudStack 自带的用于完成自身系统相关的一些任务的 vm。它有两种:

二级存储虚拟机(Secondary Storage VM):下载上传模板、下载镜像,第一次创建虚拟机时从二级存储拷贝模板到一级存储并且自动创建快照等。

控制台代理虚拟机(Console Proxy VM):用于在 web 界面上展示控制台。

需要注意的是,系统虚机为 Debian 32 位操作系统,CloudStack 管理员可以用 SSH 登录。同时,能在主机的 /var/lib/libvirt/images 查看到它们,如图 5:

怎么用 CloudStack 配置和管理云环境

图 5. 查看已经安装的 VMs

安装 KVM Hypervisor

以 root 身份登录 hypervisor 主机 cloud-agent.squirrel.org。

确保 hostname 是完整带域名的,修改方法同管理服务器步骤 1。

运行“yum erase qemu-kvm”删除 OS 自带的 qemu-kvm。

进入下载并解压好的 CloudStack 安装目录,运行命令“./install.sh”,选择“A”安装 agent。

安装完毕后,运行下面命令启动 nfs 和 rpcbind 服务,并设置为开机运行:

# service rpcbind start # service nfs start # chkconfig nfs on # chkconfig rpcbind on

Q8:如何处理因为没有 enable VT 而导致 CloudStack Agent 启动不成功?

注意检查 log:/var/log/cloud/agent/。如果是因为 BIOS 的 VT 没有打开而引起的启动失败,则需要在打开 VT 支持后重新安装 agent。运行命令:

# service cloud-agent status

若显示:

cloud-agent (pid 4188) is running...

则说明已经成功运行了。

安装 NTP,时间同步

运行“yum install ntp”安装 NTP 服务。

编辑配置文件 /etc/ntp.conf,加入如下服务器:

server 0.xenserver.pool.ntp.org server 1.xenserver.pool.ntp.org server 2.xenserver.pool.ntp.org server 3.xenserver.pool.ntp.org

重启 NTP 并设置为开机自动运行:

# service ntpd restart # chkconfig ntpd on

在 Management Console 中配置虚拟化资源

当上面的管理服务器与 hypervisor 安装好后,可以登录进 CloudStack 的 UI console 进行资源的配置与部署。

和几个竞争对手 mdash; mdash; 例如 Eucalyptus 从一开始就对 AWS 的兼容,OpenStack 对松耦合组件的系统结构设计 mdash; mdash; 相比,CloudStack 的特点之一就是有最友好的用户界面,即控制管理台。

首先打开浏览器,登录 URL:

http://192.168.1.4:8080/client  用户名  /  密码:admin/password

选择“Continue with basic installation”,接着修改 CloudStack 管理员密码。

怎么用 CloudStack 配置和管理云环境

图 6. 添加 zone

怎么用 CloudStack 配置和管理云环境

图 7. 添加 pod

怎么用 CloudStack 配置和管理云环境

图 8. 添加客户机网络

怎么用 CloudStack 配置和管理云环境

图 9. 添加 cluster

怎么用 CloudStack 配置和管理云环境

图 10. 添加 host

怎么用 CloudStack 配置和管理云环境

图 11. 添加一级存储

怎么用 CloudStack 配置和管理云环境

图 12. 添加二级存储

最后点击“Launch”启动 CloudStack 云平台,开始初始化。

怎么用 CloudStack 配置和管理云环境

图 13. 初始化中

直到出现成功信息。这样一个简单的云环境就搭建完毕,我们随后可以在这个控制台执行计算资源的管理任务了。下面两图为控制台显示界面。

怎么用 CloudStack 配置和管理云环境

图 14.Overview

怎么用 CloudStack 配置和管理云环境

图 15.Infrastructure

Q9:有时因为各种原因,例如在控制台错误的配置了一些数据,需要重新初始化时,可以删除 CloudStack 的数据库,步骤如下:

在命令行下:

mysql  ndash;u root  password  mysql  drop database cloud; drop database cloud_usage; #cloud-setup-databases cloud: dbpassword @localhost --deploy-as=root: password  #cloud-setup-management

然后重复本节的操作。

附:CloudStack 的 Web Console 界面是可以定制化的。

使用 CloudStack API

如同 AWS API 一样,CloudStack API 也是基于 Web Service,可以使用任何一种支持 HTTP 调用的语言(例如 Java,PHP)编写代码。

调用代码(caller)首先需要在管理服务器进行认证。目前 CloudStack 采用两种认证方式:

Session 认证:通过 login API,获得一个 JSESSIONID cookie 和一个 SESSIONKEY token。

API Key 认证。

本文代码示例采用 API Key 进行认证。其过程如下:

管理员给调用者分配 API Key 和 Security Key(由 Admin 通过 web console 或者用 registerUserKeys 在程序中生成)。

调用者用 Security Key 以 HMAC SHA-1 哈希算法对 API Key + Command String 生成签名。

最后的 API Request=Base URL+API Path+Command String+Signature。

下面具体为 admin 用户生成两个 key:

首先登陆管理台:http://192.168.1.4:8080/client。

点击 accounts,选择 admin,点击 users tab,找到 admin。

可以看到 API Key 和 Security Key,如果两个框没有值,点击工具栏的钥匙小图标,“Generate Keys”,如图 16。

怎么用 CloudStack 配置和管理云环境

图 16. 生成 API Key 和 Security Key

两个 Key 的生成结果如下:

怎么用 CloudStack 配置和管理云环境

表 3.Admin 用户的 API Key 和 Security Key

接下来用 CloudStack 的 Restful API 生成一个虚拟机。其调用 URL 如下:

http://192.168.1.4:8080/client/api?command=deployVirtualMachine \ serviceofferingid=1 templateid=4 zoneid=1

command 参数中的内容可以参阅 API Reference: CloudStack,此处不赘述。需要注意的是,URL 当中每个参数是按照字母顺序排列的,这是生成签名必要的。

下面演示如何生成签名并组装一个完整的 URL。

首先在此处下载一段 perl 脚本,我们要利用它来帮助生成签名。将它放入合适的目录,然后在命令行下键入:

$ ./generate-url.pl  ndash;f 1 -u  command=deployvirtualmachine serviceofferingid=1 templateid=4\  zoneid=1  -a TEBBqfXkV-9blsxpkjFLAxNUmnvMsFEq7WKwPOMT_nuce69bmcElXz1\ izsN1qJFK58ye5U5hWWN2ckscsysodg  ndash; s 7VJx0QfxvJQZBYZbLdct2QFck8lV6hwLMvo9\ YCJ97pVou8f_aDSHdhEqBaY2CtFI6_MULP0eYqr_Z7D2Jon8nQ

-f 后面数字 1 是生成 url 的意思,-a 后面是 API Key,-s 后面是 Security Key。-u 后面的 command 参数都已经修改为小写字母(此步不可省略)。命令运行完毕生成一段字符串:

http://*.*.*.*/client/api?command=deployvirtualmachine serviceofferingid=1\ zoneid=1 templateid=4 apikey=Kn7rrPjdXDWTrcjCTLs7hZM22o0X6aKSZ4Cy4\ GDUHD1TmoVw3e-oNxjRTCBXchffju5OFTqW4zPIik-HKxH7-w signature=%2BQMXTBOoicZJG\ 6EosCcRGvO7OWU%3D

然后把 IP 替换入上面 url,并把 command 中的小写字母还原成原来正确的 API 名字,结果如下:

http://192.168.1.4:8080/client/api?command=listVirtualMachines account=\admin amp;domainId=1 apikey=Kn7rrPjdXDWTrcjCTLs7hZM22o0X6aKSZ4Cy4GDUHD1TmoVw3e-o\ NxjRTCBXchffju5OFTqW4zPIik-HKxH7-w signature=i5%2FQxBf7FIGc6GvAfNcpFnVKpEw%3D

把该 URL 键入浏览器,可以执行成功,返回一段 XML response:

deployvirtualmachineresponse cloud-stack-version= 3.0.2.20120506223416   id d29a98f2-610c-4e4e-9331-18c133c5bdb3 /id   jobid a5c9f26d-98be-4a81-9883-da9dd8dfda47 /jobid   /deployvirtualmachineresponse

如果回到控制台界面的 instance tab,可以看到一个新的 vm instance 被创建。

用同样的方法,使用如下命令,列举出 Admin 用户下的全部虚拟机。

http://192.168.1.4:8080/client/api?command=listVirtualMachines account= admin amp;domainId=1 apikey=Kn7rrPjdXDWTrcjCTLs7hZM22o0X6aKSZ4Cy4GDUHD1TmoVw3e-\ oNxjRTCBXchffju5OFTqW4zPIik-HKxH7-w signature=%2BQMXTBOoicZJG6EosCcRGvO7OWU%3D

Q10:CentOS 需要安装 perl 开发环境才能运行上面的脚本。如果在命令执行过程中出现类似 cannot locate WWW/Mechanize 类的错误,需要先安装 cpan:

yum install cpan

然后用 cpan 安装缺少的 module:

cpan install WWW::Mechanize

后面缺少哪个 module,就用 cpan 安装该 module,直到所使用的包都被装入。

总体而言,CloudStack 的 API 提供了很灵活和强大的功能,而且通过 CloudBridge,更是实现了与亚马逊 EC2 API 的兼容。

现状与展望

CloudStack 目前在 Apache 站点的更新也很快,最新的 4.0 也已经发布,它提供了 VLAN 间路由(VPC)能力、给管理资源保存元数据、增加新类型存储、和支持 Ubuntu 12.04 和 REHL6.3 等新功能。

在国内,像中国电信这类大型企业,还有一些中小型企业,都在迅速的使用 CloudStack 来构建它们的公共云或私有云、混合云平台。在这些用户的实践中,CloudStack 对丰富种类的 Hypervisor、存储类型的支持、强大的伸缩能力和网络功能、良好的安全设计、灵活的 API 调用都令人留下深刻印象。

与 OpenStack 的竞争会是接下来几年 CloudStack 无法回避的问题,相对于对手的后发优势,CloudStack 更强调成熟的产品应用。但随着自身的开源,将来的 IaaS 市场也许会在求同方面走的更远。

以上是“怎么用 CloudStack 配置和管理云环境”这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注丸趣 TV 行业资讯频道!

正文完
 
丸趣
版权声明:本站原创文章,由 丸趣 2023-08-25发表,共计12165字。
转载说明:除特殊说明外本站除技术相关以外文章皆由网络搜集发布,转载请注明出处。
评论(没有评论)