艺宵网 软件工具 自动化部署工具:Ansible、Chef、Puppet、Saltstack对比

自动化部署工具:Ansible、Chef、Puppet、Saltstack对比

Ansible Ansible 提供一种最简单的方式用于发布、管理和编排计算机系统的工具,你可在数分钟内搞定。…

Ansible

Ansible 提供一种最简单的方式用于发布、管理和编排计算机系统的工具,你可在数分钟内搞定。Ansible 是一个模型驱动的配置管理器,支持多节点发布、远程任务执行。默认使用 SSH 进行远程连接。无需在被管理节点上安装附加软件,可使用各种编程语言进行扩展。

架构:

自动化部署工具:Ansible、Chef、Puppet、Saltstack对比

图为ansible的基本架构,从上图可以了解到其由以下部分组成:

  • 核心:ansible
  • 核心模块(Core Modules):这些都是ansible自带的模块
  • 扩展模块(Custom Modules):如果核心模块不足以完成某种功能,可以添加扩展模块
  • 插件(Plugins):完成模块功能的补充
  • 剧本(Playbooks):ansible的任务配置文件,将多个任务定义在剧本中,由ansible自动执行
  • 连接插件(Connectior Plugins):ansible基于连接插件连接到各个主机上,虽然ansible是使用ssh连接到各个主机的,但是它还支持其他的连接方法,所以需要有连接插件
  • 主机群(Host Inventory):定义ansible管理的主机

ansible工作原理

自动化部署工具:Ansible、Chef、Puppet、Saltstack对比

  • 管理端支持local 、ssh、zeromq 三种方式连接被管理端,默认使用基于ssh的连接---这部分对应基本架构图中的连接模块;
  • 可以按应用类型等方式进行Host Inventory(主机群)分类,管理节点通过各类模块实现相应的操作---单个模块,单条命令的批量执行,我们可以称之为ad-hoc;
  • 管理节点可以通过playbooks 实现多个task的集合实现一类功能,如web服务的安装部署、数据库服务器的批量备份等。playbooks我们可以简单的理解为,系统通过组合多条ad-hoc操作的配置文件 。

界面

自动化部署工具:Ansible、Chef、Puppet、Saltstack对比

Ansible有一个管理页面,可以用于管理ansible。

安装

只需要安装一个ansible就可以了

[root@web9 ~]# yum install -y epel-release
[root@web9 ~]# yum install -y ansible

在hosts增加需要管理的节点IP或者hostname就可以实现ansible对节点的管理。

语言:

Playbooks 是 Ansible的配置,部署,编排语言.他们可以被描述为一个需要希望远程主机执行命令的方案,或者一组IT程序运行的命令集合.

如果 Ansible 模块你是工作室中的工具,那么 playbooks 就是你设置的方案计划.

在基础层面, playbooks 可以被用来管理用于部署到远程主机的配置文件.在更高的层面上,playbooks 可以依次对多层式架构上的服务器执行上线包括滚动更新在内的操作并可以将操作委托给其他主机包括在此过程中发生的与监视服务器,负载均衡服务器的交互操作在内.

Playbooks 的格式是YAML(详见:YAML 语法),语法做到最小化,意在避免 playbooks 成为一种编程语言或是脚本,但它也并不是一个配置模型或过程的模型.

playbook 由一个或多个 ‘plays’ 组成.它的内容是一个以 ‘plays’ 为元素的列表.

在 play 之中,一组机器被映射为定义好的角色.在 ansible 中,play 的内容,被称为 tasks,即任务.在基本层次的应用中,一个任务是一个对 ansible 模块的调用,这在前面章节学习过.

‘plays’ 好似音符,playbook 好似由 ‘plays’ 构成的曲谱,通过 playbook,可以编排步骤进行多机器的部署,比如在 webservers 组的所有机器上运行一定的步骤, 然后在 database server 组运行一些步骤,最后回到 webservers 组,再运行一些步骤,诸如此类.

“plays” 算是一个体育方面的类比,你可以通过多个 plays 告诉你的系统做不同的事情,不仅是定义一种特定的状态或模型.你可以在不同时间运行不同的 plays.

简单例子:

自动化部署工具:Ansible、Chef、Puppet、Saltstack对比

这个playbook描述了使用ansible安装了一个httpd服务的详细内容。把这个yaml格式的playbook保存为playbook.yml,然后执行命令ansible-playbook playbook.yml -f 10就可以开始部署httpd服务。

跟docker关系:

在docker文档网站上详细描述了使用ansible安装docker的详细流程。详细可参考:

https://docs.docker.com/engine/admin/ansible

跟openstack关系:

Ansible也可以用于安装openstack。详细可参考:

https://docs.openstack.org/developer/openstack-ansible/

使用的大公司:

自动化部署工具:Ansible、Chef、Puppet、Saltstack对比

Puppet

puppet是一种Linux、Unix、windows平台的集中配置管理系统,使用自有的puppet描述语言,可管理配置文件、用户、cron任务、软件包、系统服务等。puppet把这些系统实体称之为资源,puppet的设计目标是简化对这些资源的管理以及妥善处理资源间的依赖关系。

puppet采用C/S星状的结构,所有的客户端和一个或几个服务器交互。每个客户端周期的(默认半个小时)向服务器发送请求,获得其最新的配置信息,保证和该配置信息同步。每个puppet客户端每半小时(可以设置)连接一次服务器端, 下载最新的配置文件,并且严格按照配置文件来配置客户端. 配置完成以后,puppet客户端可以反馈给服务器端一个消息. 如果出错,也会给服务器端反馈一个消息。

设计架构

puppet是基于c/s架构的。服务器端保存着所有对客户端服务器的配置代码,在puppet里面叫做manifest. 客户端下载manifest之后,可以根据manifest对服务器进行配置,例如软件包管理,用户管理和文件管理等等。

自动化部署工具:Ansible、Chef、Puppet、Saltstack对比

如图所示,puppet的工作流程如下:

  • 客户端puppetd调用facter,facter探测出被管理主机的一些变量,例如主机名,内存大小,ip地址等。pupppetd 把这些信息通过ssl连接发送到服务器端;
  • 服务器端的puppetmaster 检测客户端的主机名,然后找到manifest里面对应的node配置, 并对该部分内容进行解析,facter送过来的信息可以作为变量处理,node牵涉到的代码才解析,其他没牵涉的代码不解析。解析分为几个阶段,语法检查,如果语法错误就报错。如果语法没错,就继续解析,解析的结果生成一个中间的“伪代码”,然后把伪代码发给客户端;
  • 客户端接收到“伪代码”,并且执行,客户端把执行结果发送给服务器;(4)服务器端把客户端的执行结果写入日志。

Facter是puppet自有语言的数据类型,最重要的数据类型包括:

  • Facts: 从每台机器上收集到的系统数据,用于编译为配置。
  • Manifest: 包含 Puppet 代码的文件,通常被组织为一些称为“模块 (modules)”的集合中。
  • Catalog: 一张包含主机上可管理资源及其依赖关系的图。
  • Report: 对于一个 Catalog,在其应用过程中产生的所有事件的集合。

详细工作流程

自动化部署工具:Ansible、Chef、Puppet、Saltstack对比

  • 客户端Puppetd向Master发起认证请求,或使用带签名的证书。
  • Master告诉Client你是合法的。
  • 客户端Puppetd调用Facter,Facter探测出主机的一些变量,例如主机名、内存大小、IP地址等。Puppetd将这些信息通过SSL连接发送到服务器端。
  • 服务器端的Puppet Master检测客户端的主机名,然后找到manifest对应的node配置,并对该部分内容进行解析。Facter送过来的信息可以作为变量处 理,node牵涉到的代码才解析,其他没牵涉的代码不解析。解析分为几个阶段,首先是语法检查,如果语法错误就报错;如果语法没错,就继续解析,解析的结 果生成一个中间的“伪代码”(catelog),然后把伪代码发给客户端。
  • 客户端接收到“伪代码”,并且执行。
  • 客户端在执行时判断有没有File文件,如果有,则向fileserver发起请求。
  • 客户端判断有没有配置Report,如果已配置,则把执行结果发送给服务器。
  • 服务器端把客户端的执行结果写入日志,并发送给报告系统。

界面

Puppet dashboard有一个很漂亮的网页版操作界面,可以在操作界面上管理监控puppet管理的相关节点。

自动化部署工具:Ansible、Chef、Puppet、Saltstack对比

安装

  • 编辑/etc/host以修改主机名,因为puppet是基于证书的,证书中包含主机名;
  • 在master和slave上依次安装ruby、facter和puppet,安装facter和puppet时,要使用ruby install.rb。

语言

puppet把需要管理的内容抽 象成为资源,每种资源有不同的属性,因此puppet语言就是描述这些资源的属性以及资 源之间关系的语言。puppet 语言是结果式的,使用者将自己想要达到的目的通过puppet语法描述给puppet,puppet去完成它,使用者不需要关心过程,整个过程完全被抽象化了。譬如安装一个软件包,只需要ensure => present ,不需要关心操作系统是debian还是redhat 。当puppet对一个节点执行一个manifest,puppet会使用资源抽象层RAL(Resource Abstraction Layer)来翻译要执行的操作。例如:当我们想安装一个httpd安装包,puppet会根据不同的操作系统类型翻译成对应操作系统安装httpd安装包的相应的命令。例如:在使用yum作为安装命令的linux发布版上(例如:redhat),则puppet使用yum命令来安装httpd rpm安装包,而在使用APT命令安装httpd安装包的linux发布版(debian)上,则会使用apt 命令安装httpd deb类型的安装包。

(RAL:Resource Abstraction Layer)

When Puppet applies the manifest to a node, it uses a Resource Abstraction Layer (RAL) to translate the package type into the package management system of the target node. What this means is that we can use the same manifest to install the httpd package on any system for which Puppet has a Provider for the package type. Providers are the pieces of code that do the real work of applying a manifest. When the previous code is applied to a node running on a YUM-based distribution, the YUM provider will be used to install the httpd RPM packages. When the same code is applied to a node running on an APT-based distribution, the APT provider will be used to install the httpd DEB package (which may not exist, most debian-based systems call this package apache2; we’ll deal with this sort of naming problem later).

Create a site.pp file and place the following code in it:

node default {

package { ‘httpd’:

ensure => ‘installed’

}

}

Puppet资源类型可以通过命令puppet describe –list命令看到:

自动化部署工具:Ansible、Chef、Puppet、Saltstack对比

简单例子

我们使用puppet管理主机集群的方式就是使用puppet定义的各种资源类型描述我们需要的管理对象,然后写成脚本保存在puppet的manifest目录。Puppet根据我们的脚本执行我们规定的操作。

目标

通过puppet分发执行shell脚本,在客户端的opt目录下新建一目录shelldir。

步骤:

第一步:编辑服务端的site.pp
vi
/etc/puppet/manifests/site.pp

———————————————
exec { “exec-mkdir”:
cwd => “/opt”, //切换到命令行运行时目录
command => “sh /opt/lgh.sh”,
user => “root”,
path => ”
/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin”,
}
第二步:在客户端编辑上一步command路径中指定的shell脚本,例如
vi /opt/lgh.sh

———————————————
#!/bin/bash
mkdir /opt/shelldir
第三步:在客户端执行命令
# puppetd –test –server server.puppet
第四步:在/opt目录下查看shelldir目录有没有建立。

跟docker关系:

在docker文档网站详细描述了使用puppet安装docker的流程。Puppet已经实现了docker安装流程的抽象,可以直接使用puppet在多种主机上安装docker。

自动化部署工具:Ansible、Chef、Puppet、Saltstack对比

https://docs.docker.com/engine/admin/puppet/

跟openstack关系:

Puppet也已经抽象了openstack的安装流程,可以使用puppet自动安装openstack。详细见:
https://wiki.openstack.org/wiki/Puppet

使用的大公司:

自动化部署工具:Ansible、Chef、Puppet、Saltstack对比

网上支持:

Puppet Forge 记录了大量的可用的puppet脚本,可以找到大量的puppet脚本示例。

Chef

Chef是一个优秀的自动化配置管理的软件,chef可以将各个管理对象转化成脚本代码。无论你实在云平台上还是在主机上,还是在混合云环境上,无论管理的主机规模多大,chef都可以通过网络进行有效管理。

Chef 是一个 C/S 架构的分布式软件配置管理工具。

Chef架构:

自动化部署工具:Ansible、Chef、Puppet、Saltstack对比

  • Chef Server 存储配置各个节点所需的所有信息,以 REST API 接口提供服务, Chef Nodes 是指那些安装了 chef-client 的节点, chef-client 主要用于与 Chef Server 通信,获取各自的 runlist和 recipes ,进行相应的软件安装、配置和启动工作。
  • Chef 通过 Cookbook 的方式进行软件配置,每一个 Chef Cookbook 定义了如何去配置某一个特定 service 或 app ,整个配置过程可能被定义为多个 step ,每一个 step 称为一个 recipe , Cookbook 需要上传到 Chef Server 由其进行统一管理。
  • Chef 还需要为 Cookbook 定义相应的 role ,一个 role 有一个定义 recipe 执行顺序的 runlist 。每一个 Chef Client 可能需要安装若干个 role ,运行时由 chef-client 进程与 ChefServer 通信,获得每一个 role 对应的 runlist ,并根据 runlist 下载相应的 Cookbooks ,依次执行各个 recipe 以实现某个 service/app 的安装配置。
  • 在 recipe 中有一个关键部分叫做 resource ,每一种 resource 定义一种特定的软件配置,譬如 rpm 的安装,用户 / 组的创建管理,目录的创建管理, service 的启动 / 停止等等,每一个 resource 对应一个 provider 。开发 recipe 时可以按需求使用相应的 resource , chef-client 会由相应的 provider 来完成每一个 resource 的工作。

界面

Chef可以通过网页进行管理和监控:

自动化部署工具:Ansible、Chef、Puppet、Saltstack对比

安装:

  • 在客户端、被管理的节点以及服务端分别安装chef客户端服务端软件,并设置相关环境变量。
  • 设置server和client之间的认证。

语言:

Cookbook 介绍

Cookbook 是 Chef 框架的重要基础功能之一。在 Chef Server 对目标机器做安装部署的时候,是通过 Runlist。而 Runlist 里面又包含了一个一个具体的 Cookbook,所以,最终对一个目标机器的部署任务就落到了 Cookbook 上。而对于 Cookbook 来说,其中包含了多个组件,我们可以将 Cookbook 简单的理解成一个容器或者可以理解为一个包,里面包含了 recipes、files、templates、libraries、metadata 等信息。这些信息用于配置我们的目标机器。

Cookbook 的作用

Cookbook 可以通过封装,将安装部署和用户分隔开。用户不再需要了解如何安装一个环境,他们只需要用一套已经存在的 Cookbook 就可以部署出一套完整的用户环境。并且,Chef 框架支持重复部署的这个特点,使用户再也不用担心一次安装失败导致的环境不可重复安装的问题。Cookbook 支持版本管理,这样我们就可以根据不同的版本编写不同的 Cookbook,在使用的时候,我们只要在 Chef 框架的 Environment 里指定好 Cookbook 的版本就可以了。这样我们就可以在一套 Chef 框架里,根据 Cookbook 的不同,同时部署出不同的环境。

Cookbook 的结构介绍

Cookbook 主要分为如下几个组件:

  • Recipe 是用来定义对一个目标机器做部署的整个操作,比如,如何安装,安装哪些包,怎样做配置等。
  • Attribute 是用来定义一个目标机器的属性值的。类似于定义一个全局变量,通常用来给 Cookbook 的其他组件提供属性值。
  • File 是用来作部署的文件。一般会根据操作系统、平台等定义不同的文件配置。
  • Library 用来对 Cookbook 的功能做扩展。我们可以用 Ruby 语言编写自己的类来供 Recipe 调用。
  • Resource 用来自定义一个状态的运行规则。比如,针对服务的时候,我们可以定义几种不同的状态规则。
  • Provider 用来定义具体某个 Resource 的执行内容。从编程的角度可以理解为 Resource 定义了一个接口,而 Provider 是这个接口的实现。
  • Template 一些内嵌了 Ruby 标签的文件,通常用来定义配置文件。
  • Metadata 定义了 Cookbook 的属性值,比如,当前的 Cookbook 的版本,支持的平台,对其他 Cookbook 的依赖等信息。

简单例子:

在实际应用中,我们写一个cookbook保存到chef存放cookbook文件的目录,然后使用chef命令上传到chef server,并添加到需要应用的节点中。然后我们就可以在chef client上执行我们写的chef cookbook了。

目标:在服务器上创建一个文件,文件里的内容是一句问候语。

自动化部署工具:Ansible、Chef、Puppet、Saltstack对比

等上传到chef server上并应用与具体的管理节点后,

在chef client上执行命令:

自动化部署工具:Ansible、Chef、Puppet、Saltstack对比

我们可以看到“Hello World!”被成功输出。

自动化部署工具:Ansible、Chef、Puppet、Saltstack对比

跟docker关系:

在docker文档网站详细描述了使用chef安装docker的流程。chef已经实现了docker安装流程的抽象,可以直接使用chef在多种主机上安装docker。

自动化部署工具:Ansible、Chef、Puppet、Saltstack对比

跟openstack关系:

chef已经抽象了openstack的安装流程,可以使用chef自动安装openstack。详细见:
https://wiki.openstack.org/wiki/Chef

使用的大公司:

自动化部署工具:Ansible、Chef、Puppet、Saltstack对比

网上支持:

https://supermarket.chef.io/记录了大量的chef cookbook,可以参考。

Saltstack

SaltStack是基于Python开发的一套C/S架构配置管理工具(功能不仅仅是配置管理,如使用salt-cloud配置AWS EC2实例),它的底层使用ZeroMQ消息队列pub/sub方式通信,使用SSL证书签发的方式进行认证管理。号称世界上最快的消息队列ZeroMQ使得SaltStack能快速在成千上万台机器上进行各种操作。

Salt介绍

Salt是一个基础平台管理工具

Salt是一个配置管理系统,能够维护预定义状态的远程节点

Salt是一个分布式远程执行系统,用来在远程节点上执行命令和查询数据

Salt核心功能

使命令发送到远程系统是并行的而不是串行的

使用安全加密的协议

使用最小最快的网络载荷

提供简单的编程接口

Salt优点

Saltstack是用python语音编写 相当于设备是轻量级别的

Saltstack通讯采用ZEROMQ实现使得它很快速

Saltstack是开源的 通过python可以自己写模块

架构:

在SaltsStack架构中服务端叫作Master,客户端叫作Minion,都是以守护进程的模式运行,一直监听配置文件中定义的ret_port(saltstack客户端与服务端通信的端口,负责接收客户端发送过来的结果,默认4506端口)和publish_port(saltstack的消息发布系统,默认4505端口)的端口。当Minion运行时会自动连接到配置文件中定义的Master地址ret_port端口进行连接认证。

自动化部署工具:Ansible、Chef、Puppet、Saltstack对比

  • Master:控制中心,salt命令运行和资源状态管理
  • Minion : 需要管理的客户端机器,会主动去连接Mater端,并从Master端得到资源状态
  • 信息,同步资源管理信息
  • States:配置管理的指令集
  • Modules:在命令行中和配置文件中使用的指令模块,可以在命令行中运行
  • Grains:minion端的变量,静态的
  • Pillar:minion端的变量,动态的比较私密的变量,可以通过配置文件实现同步minions定义
  • highstate:为minion端下发永久添加状态,从sls配置文件读取.即同步状态配置
  • salt_schedule:会自动保持客户端配置

界面

Saltstack也有一个简单的网页管理界面:

自动化部署工具:Ansible、Chef、Puppet、Saltstack对比

安装:

  • 在服务端和客户端(被管理节点)分别安装saltstack服务端客户端软件。
  • 在服务端设置监听端口,在客户端设置服务端接口,各自启动saltstack服务
  • 建立服务端客户端之间加密通道

语言:

SaltStack使用state模块文件进行配置管理,state使用YAML语法编写,其实它也支持python编写。sls(salt state file)文件为SaltStack state模块的核心,sls文件表示一个系统应处于的系统状态,并且有一个简单的格式设置这些数据,称为配置管理。

其实sls文件只是一个数据结构,对于sls文件的深入理解会有助于对salt state的深入理解和应用。sls文件事实上只是一个字典、列表、字符串或者数字。通过对配置进行数据结构化,使其满足开发者的各种需求,写的越多,越易于理解。

所有的state file都可以通过top.sl文件来分配不同的主机使用,这是个整体入口描述,在执行命令的时候,会先检查这个文件,可以看作是基础配置文件

默认情况下salt表现的数据格式采用最简单的序列化数据格式-YAML,由于不同架构经常使用不同的名称和安装包,apache在红帽系列中是httpd,其他发行版多为apache,salt对于底层服务器管理使用init下的脚本,系统命令名,配置文件等,执行service.get_all函数来获取对应服务器可用的服务名称

简单例子:

安装软件包及启动服务

由于不同架构经常使用不同的名称和安装包,apache在红帽系列中是httpd,其他发行版多为apache,salt对于底层服务器管理使用init下的脚本,系统命令名,配置文件等,执行service.get_all函数来获取对应服务器可用的服务名称

自动化部署工具:Ansible、Chef、Puppet、Saltstack对比

这些sls数据确保apache包被安装而且apache服务处于运行状态。

第一行:被称为ID,这个ID是将要执行这些命令的名字

第二行和第四行:用来声明salt state开始的状态,分别使用包管理和服务管理,这个pkg状态管理,通过本地的软件包管理器进行软件安装,service管理系统守护进程

第三行、第五行:是要执行的function,这些函数被定义在pkg和service中,这里标示包会被安装,并且apache守护进行会运行

最后一行:require是一个必要的声明,用来定义状态之剑的依赖,他们保证apache服务安装成功后才会启动apache守护进程

在实际配置管理中,需要编写大量state.sls文件。这些文件会有一个top.sls(非必须)文件作为入口文件,负责指定minion调用某些state.sls文件。

跟docker关系:

在docker文档网站上没有看到saltstack的信息。

跟openstack关系:

Saltstack也可以用于安装openstack。详细可参考:

https://docs.saltstack.com/en/latest/topics/cloud/openstack.html

使用的大公司:

自动化部署工具:Ansible、Chef、Puppet、Saltstack对比

四大软件比较

比较项

puppet

chef

saltstack

ansible

开发语言

Ruby

Ruby

Python

Python

是否有客户端

是否支持二次开发

不支持

不支持

支持

支持

服务器与远程机器是否相互验证

服务器与远程机器通信是否加密

是,标准 SSL 协议

是,使用RSA加密

是,使用 AES 加密

是,使用 OpenSSH

平台支持

支持 AIX、BSD、HP-UX、Linux、 MacOSX、Solaris、 Windows

支持 AIX、BSD、HP-UX、Linux、 MacOSX、Solaris、 Windows

支持 BSD、Linux、Mac OS X、Solaris、 Windows

支持 AIX、BSD、 HP-UX、 Linux、Mac OSX、Solaris

是否提供 web ui

提供

提供

提供

提供,不过是商业版本

配置文件格式

Ruby 语法格式

Ruby 语法格式

YAML

YAML

命令行执行

不支持,但可通过配置模块实现

支持

支持

是否易于弹缩

容易

容易

容易

容易

可用性

支持服务端集群

支持服务端集群

支持服务端集群

支持服务端集群

是否难于管理

学习困难,基于puppet DSL,客户端从服务端下载配置

学习困难,基于ruby DSL,客户端从服务端下载配置

容易,基于yaml文件,服务端把配置推到客户端

容易,基于yaml文件,服务端把配置推到客户端

是否跨平台

服务端只支持linux,客户端可以支持windows和linux

服务端只支持linux,客户端可以支持windows和linux

服务端只支持linux,客户端可以支持windows和linux

服务端只支持linux,可以管理windows和linux

github活跃程度
贡献者:
commits:
branches:
release:

355
19595
9
291

369
12089
177
231

1041
49193
11
82

1003
13527
33
57

google流行度

稳定,目前居于第二

稳定,目前居于第三

稳定,目前居于第四

迅速增长,目前居于第一

创建时间

2005

2008

2012

2013

license

apache license v2

apache license v2

apache license v2

GNU Public license v3

商业支持

本网站所收集的部分公开资料来源于互联网,转载的目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。如果您发现网站上有侵犯您的知识产权的作品,请与我们取得联系,我们会及时修改或删除。http://www.yixao.net/soft/27174.html
Vedu

作者: Vedu

这个人很懒,什么都没有留下~

发表评论

联系我们

联系我们

15378714280

在线咨询: QQ交谈

邮箱: yixaonet@163.com

工作时间:周一至周五,9:00-17:30,节假日休息

关注微信
微信扫一扫关注我们

微信扫一扫关注我们

关注微博
返回顶部