Jenkins与gitlib实现自动化部署与持续构建

Jenkins概念

Jenkins是一个功能强大的应用程序,允许持续集成和持续交付项目,无论用的是什么平台。这是一个免费的源代码,可以处理任何类型的构建或持续集成。集成Jenkins可以用于一些测试和部署技术。Jenkins是一种软件允许持续集成。

 Jenkins目的

1、持续、自动地构建/测试软件项目。 
2、监控软件开放流程,快速问题定位及处理,提示开放效率。

特性

开源的java语言开发持续集成工具,支持CI,CD。 
易于安装部署配置:可通过yum安装,或下载war包以及通过docker容器等快速实现安装部署,可方便web界面配置管理。 
消息通知及测试报告:集成RSS/E-mail通过RSS发布构建结果或当构建完成时通过e-mail通知,生成JUnit/TestNG测试报告。 
分布式构建:支持Jenkins能够让多台计算机一起构建/测试。 
文件识别:Jenkins能够跟踪哪次构建生成哪些jar,哪次构建使用哪个版本的jar等。 
丰富的插件支持:支持扩展插件,你可以开发适合自己团队使用的工具,如git,svn,maven,docker等。

 产品发布流程

产品设计成型 -> 开发人员开发代码 -> 测试人员测试功能 -> 运维人员发布上线 
持续集成 (Continuous integration,简称CI) 
持续交付(Continuous delivery) 
持续部署(continuous deployment)

持续集成:多名开发者在开发不同功能代码的过程中,可以频繁的将代码进行合并到一起不相互影响工作。

持续部署:是基于某种工具或平台实现代码自动化的构建、测试和部署到线上环境以实现交付高质量的产品,持续部署在某种程度上代表了一个开发团队的更新迭代速率。

上线方案

开发自己上传
--最原始的方案
开发给运维手动上传
--运维自己手动部署
运维使用脚本复制
--半自动化
结合web界面一键部署
--自动化

版本控制系统

在公司的服务器安装某种程序,该程序用于按照特定格式和方式记录和保存公司多名开发人员不定期提交的源代码,且后期可以按照某种标记及方式对用户提交的数据进行还原。

CVS--早期的集中式控制系统
SVN--集中式版本控制系统
--集中式管理,依赖于网络,一台服务器集中管理 Gitlib--分布式版本控制系统 --2002年由Linux内核作者linus使用C语言开发
--分布式版本控制系统,不依赖于服务器,离线依然可以工作

网站:https://github.com

集中式版本控制系统

任何的提交和回滚都依赖于连接服务器

SVN服务器是单点

分布式版本控制系统

Git在每个用户都有一个完整的服务器,然后在有一个中央服务器,用户可以先将代码提交到本地,没有网络也可以先提交到本地,然后在有网络的时候再提交到中央服务器,这样就大大方便了开发者,而相比CVS和SVN都是集中式的版本控制系统,工作的时候需要先从中央服务器获取最新的代码,改完之后需要提交,如果是一个比较大的文件则需要足够快的网络才能快速提交完成,而使用分布式的版本控制系统,每个用户都是一个完整的版本库,即使没有中央服务器也可以提交代码或者回滚,最终再把改好的代码提交至中央服务器进行合并即可。

系统环境准备

最小化服务器安装,配置如下:

# yum install vim gcc gcc-c++ wget net-tools lrzsz iotop lsof iotop bash-completion -y
# yum install curl policycoreutils openssh-server openssh-clients postfix -y
# wget -O /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo
# systemctl  disable firewalld
# sed -i '/SELINUX/s/enforcing/disabled/' /etc/sysconfig/selinux
# hostnamectl  set-hostname xxx.com.cn
# yum update –y && reboot

Gitlib安装

# vim /etc/yum.repos.d/gitlib.repo
[gitlab-ce]
name=gitlab-ce
baseurl=http://mirrors.tuna.tsinghua.edu.cn/gitlab-ce/yum/el7
repo_gpgcheck=0
gpgcheck=0
enabled=1
gpgkey=https://packages.gitlab.com/gpg.key
# yum install gitlab-ce

Gitlib配置

Rpm包下载地址:
https://mirrors.tuna.tsinghua.edu.cn/gitlab-ce/yum/
[root@gitlib-server ~]#vim /etc/gitlab/gitlab.rb 

external_url 'http://192.168.10.130'

external_url ‘http://192.168.10.130‘ #服务器IP地址

gitlab_rails['smtp_enable'] = true 
gitlab_rails['smtp_address'] = "smtp.163.com"
gitlab_rails['smtp_port'] = 25
gitlab_rails['smtp_user_name'] = "rooroot@163.com"
gitlab_rails['smtp_password'] = "zhang@123"
gitlab_rails['smtp_domain'] = "163.com"
gitlab_rails['smtp_authentication'] = :login
gitlab_rails['smtp_enable_starttls_auto'] = true
gitlab_rails['smtp_tls'] = false
gitlab_rails['gitlab_email_from'] = "rooroot@163.com"
user["git_user_email"] = "rooroot@163.com"

Gitlib服务器初始化

执行配置并启动服务:
#  gitlab-ctl reconfigure  #修改完配置文件要执行此操作
# gitlab-ctl  start
# gitlab-ctl  stop
# gitlab-ctl  restar

Gitlib验证启动

#ss -ntl

验证端口及状态
80端口和8080端口是在初始化gitlib的时候启动的,因此如果之前的有程序占用会导致初始化失败或无法访问!

登陆web页面

登录web页面并设置密码,最少8位:
http://192.168.130.8

登录Gitlib

登陆,默认用户weiroot

 默认页面

注册账号

默认情况下可以直接注册账号,因此,一般都关闭此功能

关闭账号注册功能

取消账户注册功能之后点save

验证账号注册功能是否关闭

添加账号

添加一个账号

设置新账户密码

使用第一次的新账号登录要设置密码

 

 发送设置密码邮件

设置密码

在收件箱打开邮件设置密码

设置密码

 创建项目

使用管理员创建项目

创建组

组里可以有多个项目分支,可以将开发添加到组里面进行设置权限,不同的组就是公司不同的开发项目或者业务模块,不同的组添加不同的开发即可实现对开发设置权限的管理

将用户添加到组

为项目创建一个index页面

找到项目界面

 

添加一个页面

安装git客户端 

# yum install git –y
# mkdir  /source
# cd /source/
# git clone http://192.168.10.130/myweb/myweb1.git

验证index.html文件是否存在

编辑文件并提交

# git config --global user.name "jack“
# git config --global user.email 2973707860@qq.com
# cd myweb1
# vim index.html
# git add index.html
# git commit -m "333“
# git push -u origin

Git常用命令总结

git config --global user.name “name“ #设置全局用户名,可以非真实账户
git config --global user.email  xxx@xx.com #设置全局邮箱,可以非真实邮箱
git config --global –list #列出用户全局设置
git  add index.html  #添加文件到暂存区
git commit -m “11“  #提交文件到工作区
git status #查看工作区的状态
git push #提交代码到服务器
git pull  #获取代码到本地
git log #查看操作日志
vim  .gitignore  #定义忽略文件
git reset --hard  HEAD^  #git版本回滚, HEAD为当前版本,加一个^为上一个,^^为上上一个版本
git reflog # #获取每次提交的ID,可以使用--hard根据提交的ID进行版本回退
git reset --hard 5ae4b06 #回退到指定id的版本
# git branch  #查看当前所处的分支
git checkout --  file  #从服务器更新某个那文件覆盖本地的文件

部署tomcat服务器

各web服务器准备tomcat运行环境

# useradd  www  -u 2000
# mkdir /apps && cd /apps
# tar xvf jdk-7u79-linux-x64.tar.gz
# ln -sv /apps/jdk1.7.0_79 /apps/jdk
# vim /etc/profile
export export LANG="en_US.utf-8"
export JAVA_HOME=/apps/jdk
export CLASSPATH=.:$JAVA_HOME/jre/lib/rt.jar:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
export PATH=$PATH:$JAVA_HOME/bin
# source  /etc/profile && java -version
# tar xvf apache-tomcat-7.0.59.tar.gz
# ln -sv /apps/apache-tomcat-7.0.59 /apps/tomcat

准备tomcat启动脚本

# cp /root/tomcatd /etc/init.d/

部署app

确认各web服务器访问正常

# mkdir  /data/tomcat_appdir #保存web压缩包
# mkdir /data/tomcat_webdir #保存解压后的web目录
# cd tomcat_webdir
# mkdir myapp
# echo tomcatX > /apps/tomcat_webdir/myapp/index.html

确认各web服务器访问正常

部署haproxy

部署haproxy

# tar xvf haproxy-1.5.18.tar.gz
# cd haproxy-1.5.18
# make TARGET=linux2628 PREFIX=/usr/local/haproxy-1.5.18
# make install PREFIX=/usr/local/haproxy-1.5.18
# ln -sv /usr/local/haproxy-1.5.18/ /usr/local/haproxy
# cp examples/haproxy.init  /etc/init.d/haproxy #启动脚本
# chmod  a+x /etc/init.d/haproxy
# chkconfig  --add haproxy &&  chkconfig  haproxy on
# ln  -sv /usr/local/haproxy/sbin/haproxy  /usr/sbin/
# mkdir /etc/haproxy
# cp examples/haproxy.cfg  /etc/haproxy/

编辑本机hosts文件,将myapp.web.com解析到对应的IP负载IP

C:\Windows\System32\drivers\etc\hosts
192.168.10.132  myapp.web.com

记录haproxy日志

# vim /etc/rsyslog.conf:
 14 # Provides UDP syslog reception
 15 $ModLoad imudp #去掉注释
 16 $UDPServerRun 514 #去掉注释
 18 # Provides TCP syslog reception
 19 $ModLoad imtcp #去掉注释
 20 $InputTCPServerRun 514 #去掉注释
# systemctl  restart  rsyslog
log 127.0.0.1 local0 info #global部分
frontend web_port #监听端口
        bind 0.0.0.0:80
        mode http
        option httplog
        log global
        option  forwardfor

重启rsyslog和haproxy服务,验证/var/log/haproxy.log可以记录日志:

访问负载状态页面

验证反向代理功能

安装jenkins

可以将数据保存在单独的磁盘

mkfs.xfs  /dev/sdb
mount /dev/sdb  /data/
chown   jenkins.jenkins  /data/ -R

jenkins安装及启动

通过rpm包安装jenkins

rpm –ivh jdk-8u111-linux-x64.rpm
rpm –ivh https://pkg.jenkins.io/redhat/jenkins-2.27-1.1.noarch.rpm
/etc/init.d/jenkins start
 chkconfig  jenkins on  

日志显示启动并运行

jenkins启动报错

无法正常启动jenkins

没有java环境

配置java环境

使用官方仓库安装:
# wget -O /etc/yum.repos.d/jenkins.repo https://pkg.jenkins.io/redhat/jenkins.repo
# rpm --import https://pkg.jenkins.io/redhat/jenkins.io.key
# yum install java jenkins
直接下载二进制安装包:
# tar xvf jdk-8u111-linux-x64.tar.gz  -C /usr/local/src/
# ln -sv /usr/local/src/jdk1.8.0_111 /usr/local/jdk
# vim /etc/profile
export JAVA_HOME=/usr/local/jdk
export PATH=$JAVA_HOME/bin:$JAVA_HOME/jre/bin:$PATH
export CLASSPATH=.$CLASSPATH:$JAVA_HOME/lib:$JAVA_HOME/jre/lib:$JAVA_HOME/lib/tools.jar
# source  /etc/profile && java –version
使用rpm安装包安装java并启动jenkins:
#rpm –ivh jdk-8u111-linux-x64.rpm

配置jenkins

# vim /etc/sysconfig/Jenkins
JENKINS_HOME=“/data“  #数据目录,使用高IO大容量磁盘
JENKINS_USER=“jenkins“ #启动用户
JENKINS_PORT=“8080“  #启动端口

访问web界面

如果虚拟及配置较低,则启动页面可能需要很长的时间,因此推荐4G或更多内存,4C或更多CPU

重新完成的日志

# tail /var/log/jenkins/jenkins.log  -f

安装密码

输入安装的下一步

Jenkins插件安装

插件安装过程中,如果由安装失败没关系,可以后期安装

如果自动安装失败,可以减压准备好的插件

#cd /var/lib/jenkins/plugins
#tar xvf jenkins_plugin.tar.gz
#chown  jenkins.jenkins ./* -R
#/etc/init.d/jenkins  start

插件下载地址

http://updates.jenkins-ci.org/download/plugins/

注:未安装成功的插件最好重新安装下

创建用户

创建登录用户

账号创建完成

登录成功

邮件配置

设置管理员邮件地址

发送邮件设置

从git获取代码

gitLab
gitlab Hook Plugin 

安装查件中

插件安装界面,会额外安装一些依赖关系的插件,jenkins插件有的基于ruby开发,所以会安装ruby环境

添加git用户

在gitlab管理界面将用户添加到一个项目,下一步要用此用户拉取项目代码

权限确认

确认用户对项目有提交的权限

添加部署key

部署key可以用于获取代码

测试部署key

测试可以不使用用户名密码,直接获取代码

Jenkins添加git用户

添加一个认证用户,拉取git代码的时候使用

http://192.168.10.131:8080/credentials/store/system/domain/_/newCredentials

Jenkins创建项目

创建项目

配置适用git源

配置git项目地址和用户

使用Jenkins构建项目

点击立即构建

代码测试sonar

官网:hrttp://www.sonarqube.org/

Sonar 是一个用于代码质量管理的开放平台,通过插件机制,Sonar 可以集成不同的测试工具,代码分析工具,以及持续集成工具。与持续集成工具(例如 Hudson/Jenkins 等)不同,Sonar 并不是简单地把不同的代码检查工具结果(例如FindBugs,PMD等)直接显示在Web页面上,而是通过不同的插件对这些结果进行再加工处理,通过量化的方式度量代码质量的变化,从而可以方便地对不同规模和种类的工程进行代码质量管理。在对其他工具的支持方面,Sonar 不仅提供了对 IDE 的支持,可以在 Eclipse 和 IntelliJ IDEA 这些工具里联机查看结果;同时Sonar还对大量的持续集成工具提供了接口支持,可以很方便地在持续集成中使用 Sonar,此外,Sonar 的插件还可以对 Java 以外的其他编程语言提供支持,对国际化以及报告文档化也有良好的支持。

安装数据库

数据库不支持5.5的版本,支持5.6以后的版本。

# yum -y install autoconf   && tar xvf mysql-5.6.34-linux-glibc2.5-x86_64.tar.gz
#ln -sv /usr/local/src/mysql-5.6.34-linux-glibc2.5-x86_64 /usr/local/mysql
#cd /usr/local/mysql/
# useradd  mysql  -s /sbin/nologin
#  chown  -R mysql.mysql  ./* -R
# mkdir /data && chown  mysql.mysql /data/ -R
# /usr/local/mysql/scripts/mysql_install_db  --user=mysql --datadir=/data/ --basedir=/usr/local/mysql/
#cp /usr/local/mysql/support-files/mysql.server /etc/init.d/mysql
#cp /usr/local/mysql/my.cnf  /etc/my.cnf
# vim /etc/my.cnf
basedir = /usr/local/mysql
datadir = /data
port = 3306
#/etc/init.d/mysql  start
#ln -sv /usr/local/mysql/bin/mysql /usr/bin/

mysql数据库创建及授权

# /usr/local/mysql/bin/mysql
CREATE DATABASE sonar CHARACTER SET utf8 COLLATE utf8_general_ci;
GRANT ALL ON sonar.* TO sonar@"jenkins-server.example.com"  IDENTIFIED BY "123456";
GRANT ALL ON sonar.* TO sonar@"192.168.100.%" IDENTIFIED BY "123456";
FLUSH PRIVILEGES;
/usr/local/mysql/bin/mysql  -usonar -p123456 -h192.168.10.131

部署sonar

sonar依赖于java环境,而且java版本必须是1.8版本或更高,否则sonar启动失败

# unzip sonarqube-5.6.zip
#ln -sv /usr/local/src/sonarqube-5.6 /usr/local/sonar
[root@jenkins-server ~]# grep "^[za-Z]" /usr/local/sonar/conf/sonar.properties
sonar.jdbc.username=sonar
sonar.jdbc.password=123456
sonar.jdbc.url=jdbc:mysql://192.168.10.131:3306/sonar?useUnicode=true&characterEncoding=utf8&rewriteBatchedStatements=true&useConfigs=maxPerformance
sonar.web.port=8800

# /usr/local/sonar/bin/linux-x86-64/sonar.sh  start

点击右上角login登录,默认用户名密码都是admin

sonar安装中文支持

#/usr/local/sonar/extensions/plugins/ #插件本地路径
安装中文插件:
administration-system-update center-available,在后面的搜索框搜索插件名称,然后点install安装: 
或在插件目录/usr/local/sonar/extensions/plugins执行wget https://github.com/SonarQubeCommunity/sonar-l10n-zh/releases/download/sonar-l10n-zh-plugin-1.11/sonar-l10n-zh-plugin-1.11.jar然后重启服务: 
# /usr/local/sonarqube-5.6/bin/linux-x86-64/sonar.sh  restart 

部署扫描器

Sonar通过扫描器进行代码质量分析,即扫描器的具体工作就是扫描代码

下载地址:

http://docs.sonarqube.org/display/SCAN/Analyzing+with+SonarQube+Scanner
# unzip sonar-scanner-2.6.1.zip 
# ln -sv /usr/local/src/sonar-scanner-2.6.1 /usr/local/sonar-scanner
# cd /usr/local/sonar-scanner/
# grep "^[a-Z]" conf/sonar-scanner.properties 
sonar.host.url=http://localhost:8800
sonar.sourceEncoding=UTF-8
sonar.jdbc.username=sonar
sonar.jdbc.password=123456
sonar.jdbc.url=jdbc:mysql://192.168.10.131:3306/sonar?useUnicode=true&characterEncoding=utf8

准备测试代码

# cd /home/jack/
# unzip sonar-examples-master.zip 
# cd  sonar-examples-master
# cat  projects/languages/php/php-sonar-runner/sonar-project.properties  #以下是默认配置
# Required metadata
sonar.projectKey=org.sonarqube:php-simple-sq-scanner #key
sonar.projectName=PHP :: Simple Project :: SonarQube Scanner #项目名称,会显示在仪表盘
sonar.projectVersion=1.0 #版本
# Comma-separated paths to directories with sources (required)
sonar.sources=src #代码目录
# Language
sonar.language=php #语言格式为php
# Encoding of the source files
sonar.sourceEncoding=UTF-8 #编码格式

执行扫描

#pwd
/home/jack/sonar-examples-master/projects/languages/php/php-sonar-runner
#/usr/local/sonar-scanner/bin/sonar-scanner  #手动在当前目录执行扫描,以下是扫描过程的提示信息

扫描的配置文件可以在每个项目都放一个,或在Jenkins界面做配置

让jenkins关联到sonar scanner

在jenkins插件安装界面安装sonar插件sonarqube plugin

系统管理—系统设置

添加扫描器

系统管理-Global Tool Configuration

配置扫描

选择自己的项目(demo)-->-构建触发器-- >构建-->execute

sonarqube scanner,将配置文件的内容修改成如下格式填写完成后点保存

sonar.projectKey=test-demo
sonar.projectName=test-demo
sonar.projectVersion=1.0
sonar.sources=./
sonar.language=php
sonar.sourceEncoding=UTF-8

点击项目的立即构建,下图是执行成功的信息

构建历史

 查看项目的构建历史

构建失败邮件通知

构建失败后会发送邮件通知管理员

部署代码

 将代码部署到web服务器

创建项目

新建一个项目叫test-deploy用于代码发布,上一个项目test-demo可用于代码测试,当测试阶段出现问题的时候也不会立即进行发布,只有当测试通过后才执行发布的项目。

如何将代发布到web服务器上?

可以通过执行命令或脚本的方式进行代码发布,在各web服务器包括Jenkins服务器创建一个www用户,保持id一致,用于启动web服务并进行代码发布

# useradd  www
# echo "123456" | passwd --stdin www
# su - www
$ ssh-keygen

添加key

添加jenkins服务器www用户的公钥到git服务器项目当中

确认key

 确认www用户的key可以拉取代码

Shell脚本

关于权限

一般使用非root用户启动web服务及完成代码发布,默认Jenkins运行使用的是Jenkins用户,因此需要赋予Jenkins用户一定的权限,另外发布的脚本可以在本机也可以不在本机,需要使用Jenkins用户ssh到发布服务器执行shell脚本。

将脚本放在/home/www用户家目录,git代码也放在家目录,因此需要jenkins服务器远程到代码发布服务器执行远程命令,需要做免登陆认证,将jenkins服务器root和www用户的公钥放在代码部署服务器的www用户家目录.ss/authorized_keys文件中:
# su - www
$ vim /home/www/.ssh/authorized_keys

$ chmod  600 authorized_keys

验证ssh

在root用户和www用户下ssh到本机的www用户,确认可以免密码登录,以便让部署服务器将用户的key添加到know_keys,否则报错Host key verification failed:

配置jenkins用户sudo权限

# vim /etc/sudoers
56 # Defaults    requiretty #不需要tty
99 jenkins ALL=(ALL)       NOPASSWD: /usr/bin/ssh #不需要使用密码即可执行ssh

脚本内容

$ cd /home/www/
$ vim deploy.sh
#!/bin/bash
echo $USER
cd /home/www/myweb1
git pull
scp -r  ./*  www@192.168.10.133:/apps/tomcat/webapps/myapp
scp -r  ./*  www@192.168.10.134:/apps/tomcat/webapps/myapp

测试执行命令

在test-deploy项目的构建步骤调用,项目—配制—构建

执行结果

Web服务器免密码登录

复制www用户公钥到各web服务器的www用户

$ ssh-copy-id    www@192.168.10.133
$ ssh-copy-id    www@192.168.10.134

提交代码

在另外一台服务器编辑代码后重新提交:
# git  clone http://192.168.10.130/web/myweb1.git
# echo “xxx” >>  index.html
# git add index.html
# git commit index.html
# git push

在jenkins执行项目构建
构建项目之前要在www用下的xxx项目里面进行git pull命令。否则第一次更新提示输入yes会导致部署失败
再次提交代码

项目关联

配置项目test-demo的构建后操作,demo构建完成后自动构建demp-deploy项目

添加构造后操作

构建关联成功

定义视图

 安装pipeline插

添加试图

定义名称

  配置视图

在pipeline进行构建

自动构建

GitLab触发jenkins构建项目
目的为在公司的测试环境当中一旦开发向gitlab仓库提交成功代码,gitlab通知jenkins进行构建项目、代码质量测试然后部署至测试环境,注意这只是测试环境,而生产环境依然需要手动部署代码

安装插件

安装Gitlab Hook Plugin插件:
#系统管理-管理插件-可选插件-Gitlab Hook Plugin和Build Authorization Token Root Plugin

 Token

# openssl  rand -hex 12
f7d0ead5398bd808ee139067

配置触发器

配置gitlib触发

#插件使用介绍,https://wiki.jenkins-ci.org/display/JENKINS/Build+Token+Root+Plugin 
#选择项目-设置-webhooks: 
http://192.168.10.131:8080/buildByToken/build?job=test-demo&token=f7d0ead5398bd808ee139067
格式如下:
http://X.X.X.X:8080/buildByToken/build?job=项目名&token=随机数

保存后进行测试

 

测试成功

测试git触发Jenkins自动部署 

在另一台向git服务器提交代码,验证是否自动化部署

# echo "ccc" >> index.html
# git add index.html
# git commit -m "ccc“
# git push

验证成功构建

实现在haproxy动态增减服务器

在Jenkins服务器复制www用户的公钥到haproxy服务器:
$ ssh-copy-id  root@192.168.10.132
# ssh-copy-id  root@192.168.10.132
Haproxy服务器编辑# vim /etc/sudoers必须要tty
# vim /etc/sudoers
root    ALL=(ALL)       ALL
jenkins ALL=(ALL)       NOPASSWD: /usr/bin/ssh
www     ALL=(ALL)       ALL

测试www和root用户的ssh功能

动态增减haproxy后端服务器

开启功能
# vim /etc/haproxy/haproxy.cfg
stats socket /usr/local/haproxy/stats mode 600 level admin
安装命令并测试
yum install socat
#echo "help"| socat stdio /usr/local/haproxy/stats
# echo "show info"| socat stdio /usr/local/haproxy/stats
#echo "show stat"| socat stdio /usr/local/haproxy/stats
# echo "disable server  myapp_host/web2"|socat stdio /usr/local/haproxy/stats

echo "enable  server  myapp_host/web2"|socat stdio /usr/local/haproxy/stats

分组是为了在代码分批次上线的时候对后端服务器的一种筛选方法

 

posted @ 2018-08-12 22:37  琼兔  阅读(4356)  评论(0编辑  收藏  举报