① 开发人员每天把代码提交到 Gitlab 代码仓库
② Jenkins从 Gitlab中拉取项目源码,编译并打成jar包,然后构建成Docker镜像,将镜像上传到Harbor私有仓库。
③ Jenkins发送SSH远程命令,让生产部署服务器到Harbor私有仓库拉取镜像到本地,然后创建容器。
④ 最后,用户可以访问到容器
服务器名称 | IP地址 | 安装的软件 |
---|---|---|
代码托管服务器 | 192.168.8.18 | Gitlab |
持续集成服务器 | 192.168.8.19 | Jenkins,Maven,Docker18.06.1-ce |
Docker仓库服务器 | 192.168.8.20 | Docker18.06.1-ce,Harbor1.9.2 |
生产部署服务器 | 192.168.8.17 | Docker18.06.1-ce |
项目架构: 前后端分离
后端技术栈: SpringBoot+SpringCloud+SpringDataJpa(Spring全家桶)
微服务项目结构:
tensquare_parent: 父工程 , 存放基础配置
tensquare_common: 通用工程,存放工具类
tensquare_eureka_server: SpringCloud的Eureka注册中心
tensquare_zuul: SpringCloud 的网关服务
tensquare_admin_service: 基础权限认证中心,负责用户认证(使用JWT认证)
tensquare_gathering: 一个简单的业务模块,活动微服务相关逻辑
数据库结构
tensquare_user: 用户认证数据库,存放用户账户数据。对应tensquare_admin_service微服务tensquare_gathering: 活动微服务数据库。对应tensquare_gathering微服务
微服务配置分析:
tensquare_eureka ——》注册中心,优先开启
tensquare_zuul ——》网关
tensquare_admin_service ——》权限管理
tensquare_gathering——》业务活动
微服务项目包解压,目录在idea中打开,idea会自动下载相关组件插件(等待时间较长)
报错解决:
SpringBoot启动类报错can not resolve method 'run(java.lang.class,String [])'问题
修改配置文件组建下载地址设置
<mirror>
<id>aliyunmaven</id>
<mirrorOf>central</mirrorOf>
<name>aliyun maven</name>
<url>http://maven.aliyun.com/repository/public</url>
</mirror>
修改idea指向maven
自动更新
<build>
<plugins>
<plugin>
<!--提供打包(将应用打包成可执行的jar包)-->
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<!-- 指定maven编译的jdk版本 -->
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<verbose>true</verbose>
<fork>true</fork>
<!--jdk地址-->
<executable>C:/Program Files/Java/jdk1.8.0_152/bin/javac</executable>
</configuration>
</plugin>
</plugins>
</build>
安装完成以后需要配置环境变量
导入软件脚本到MySQL数据库中
#创建二个库
create database tensquare_gathering;
create database tensquare_user;
#导入脚本文件
use tensquare_gathering;
source D:/tensquare_gathering.sql;
use tensquare_user;
source D:/tensquare_user.sql;
Vscode终端中运行:npm run dev,会发现报错
解决方法:
npm install -g cnpm --registry=https://registry.npm.taobao.org
使用cmd切换到tensquareAdmin目录下执行 cnpm uninstall node-sass
再执行安装命令 cnpm install node-sass
启动前端项目 ——》cnpm run dev
到此位置,前端部分已经安装部署完成
修改配置文件application.yml
# 单机版
server:
port: 10086
#基本服务器信息
spring:
application:
name: eureka-server #服务ID
#enreka服务器配置
eureka:
client:
fetch-registry: false #单机版关闭enreka相互注册
register-with-eureka: false
service-url:
defaultZone: http://localhost:${server.port}/eureka #暴露eureka服务访问地址
server:
enable-self-preservation: false #关闭自我保护
到此,微服务的所有服务都已开启成功
获取token令牌
eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiIxMTk0MjgxNTMzMjMwNDE5OTY4Iiwic3ViIjoiYWRtaW4iLCJpYXQiOjE2NDUzNzM3OTMsInJvbGVzIjoiYWRtaW4iLCJleHAiOjE2NDUzNzU1OTN9.XyodVOf3_2ioYOO9F6EexxUA9Kruridt3AN0cmD3NE8
cnpm run dev
登录平台
http://localhost:9528
这里如果提示mvn无法识别则需要重启IDEA再进行打包
java -jar tensquare_eureka_server-1.0-SNAPSHOT.jar
使用浏览器访问
http://localhost:10086/
由此可以看出,对于打的jar包是可以单独在本地进行运行的
docker的部署及基础操作可参考前文
以下服务器上均需部署docker
Jenkins 服务器 192.168.8.19
Harbor镜像仓库服务器 192.168.8.20
生产部署服务器 192.168.8.17
#环境配置
systemctl stop firewalld
systemctl disable firewalld
vim /etc/selinux/config
SELINUX=disabled
vim /etc/resolv.conf
nameserver 114.114.114.114
#安装依赖包
yum install -y yum-utils device-mapper-persistent-data lvm2
#设置阿里云镜像源
cd /etc/yum.repos.d/
yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
#安装 docker-ce 社区版
yum install -y docker-ce
systemctl start docker
systemctl enable docker
#配置镜像加速,官方网址可参考:https://help.aliyun.com/document_detail/60750.html
mkdir -p /etc/docker
#直接命令行输入以下内容:
tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": ["https://t466r8qg.mirror.aliyuncs.com"]
}
EOF
#把Harbor地址加入到Docker信任列表(harbor仓库的docker中不需要配)
vim /etc/docker/daemon.json
{
"registry-mirrors": ["https://t466r8qg.mirror.aliyuncs.com"],
"insecure-registries": ["192.168.8.20:85"]
}
systemctl daemon-reload
systemctl restart docker
#网络优化
vim /etc/sysctl.conf
net.ipv4.ip_forward=1
sysctl -p
systemctl restart network
systemctl restart docker
docker version
注意:需要先部署docker,并且启动docker
cd /usr/local/bin/
#docker-compose下载好拖进该目录中
chmod +x /usr/local/bin/docker-compose
docker-compose -version
tar zxvf harbor-offline-installer-v1.9.2.tgz -C /opt/
cd /opt/harbor
vim harbor.yml
#修改 hostname 和 port hostname: 192.168.8.20
port: 85
./prepare
./install.sh
docker-compose up -d 启动
docker-compose stop 停止
docker-compose restart 重新启动
http://192.168.8.20:85
默认账户密码:admin/Harbor12345
创建项目
创建用户,分配权限
角色 | 权限说明 |
---|---|
访客 | 对于指定项目拥有只读权限 |
开发人员 | 对于指定项目拥有读写权限 |
维护人员 | 对于指定项目拥有读写权限,创建 Webhooks |
项目管理员 | 除了读写权限,同时拥有用户管理/镜像扫描等管理权限 |
利用Dockerfile制作一个Eureka注册中心的镜像
FROM openjdk:8-jdk-alpine
ARG JAR_FILE
COPY ${JAR_FILE} app.jar
EXPOSE 10086
ENTRYPOINT ["java","-jar","/app.jar"]
docker build --build-arg JAR_FILE=tensquare_eureka_server-1.0-SNAPSHOT.jar -t eureka:v1 .
docker run -i --name=eureka -p 10086:10086 eureka:v1
http://192.168.8.19:10086/
docker tag eureka:v1 192.168.8.20:85/tensquare/eureka:v1
docker login -u tom -p Abcd1234 192.168.8.20:85
docker push 192.168.8.20:85/tensquare/eureka:v1
docker login -u tom -p Abcd1234 192.168.8.20:85
docker pull 192.168.8.20:85/tensquare/eureka:v1
重新定义远程仓库地址
这里需要复制gitlab仓库中 tensquare_back 项目中 HTTP 的URL
Windows本地安装TortoiseGit(小乌龟)用来提交前端项目代码
右键桌面,点击设置进行汉化选择
到前端项目的路径下,右击鼠标选中Git同步
使用项目中Jenkinsfile方式去拉取代码
使用流水线语法中的片段生成器来进行生成拉取代码
//定义gitlab的凭证
def git_auth="03757112-b3bd-4955-93ef-ad84869f39a9"
//定义gitlab的URL路径
def git_url="[email protected]:gl/tensquare_back.git"
node {
stage('pull code') {
checkout([$class: 'GitSCM', branches: [[name: "*/${branch}"]], extensions: [], userRemoteConfigs: [[credentialsId: "${git_auth}", url: "${git_url}"]]])
}
}
使用上面的tensquare_back项目,并进行参数配置
tensquare_eureka_server
tensquare_zuul
tensquare_admin_service
tensquare_gathering
注册中心
服务网关
认证中心
活动微服务
# must be unique in a given SonarQube instance
sonar.projectKey=tensquare_admin_service
# this is the name and version displayed in the SonarQube UI. Was mandatory prior to SonarQube 6.1.
sonar.projectName=tensquare_admin_service
sonar.projectVersion=1.0
# Path is relative to the sonar-project.properties file. Replace "\" by "/" on Windows.
# This property is optional if sonar.modules is set.
sonar.sources=.
sonar.exclusions=**/test/**,**/target/**
sonar.java.binaries=.
sonar.java.source=1.8
sonar.java.target=1.8
#sonar.java.libraries=**/target/classes/**
# Encoding of the source code. Default is default system encoding
sonar.sourceEncoding=UTF-8
//定义gitlab的凭证
def git_auth="03757112-b3bd-4955-93ef-ad84869f39a9"
//定义gitlab的URL路径
def git_url="[email protected]:gl/tensquare_back.git"
node {
stage('pull code') {
//切换成变量,字符串符号使用双引号
checkout([$class: 'GitSCM', branches: [[name: "*/${branch}"]], extensions: [], userRemoteConfigs: [[credentialsId: "${git_auth}", url: "${git_url}"]]])
}
stage('check code') {
//定义SonarQubeScanner工具
def scannerHome = tool 'sonar-scanner'
//引用SonarQube系统环境
withSonarQubeEnv('sonarqube') {
sh """
cd ${project_name}
${scannerHome}/bin/sonar-scanner
"""
}
}
}
再次构建进行代码检查
在idea中对Jenkinsfile进行更改,增加安装common工具的命令
//定义gitlab的凭证
def git_auth="03757112-b3bd-4955-93ef-ad84869f39a9"
//定义gitlab的URL路径
def git_url="[email protected]:gl/tensquare_back.git"
node {
stage('pull code') {
checkout([$class: 'GitSCM', branches: [[name: "*/${branch}"]], extensions: [], userRemoteConfigs: [[credentialsId: "${git_auth}", url: "${git_url}"]]])
}
stage('check code') {
//定义SonarQubeScanner工具
def scannerHome = tool 'sonar-scanner'
//引用SonarQube系统环境
withSonarQubeEnv('sonarqube') {
sh """
cd ${project_name}
${scannerHome}/bin/sonar-scanner
"""
}
}
//编译,打包,镜像制作
stage('make package images') {
sh "mvn -f tensquare_common clean install"
}
}
问题分析:
在每一个微服务中都有一个pom.xml
文件,里面有指向父进程 pom.xml
的选项(如下图),common
工具在进行加载的时候会先对其中的 pom.xml 文件进行加载,挨个加载其中的插件,因为 common 本身是一个工具而不是服务,工具在进行打包编译的时候并不需要指定方式。
解决方案:
把父工程 pom.xml 中的 maven 插件代码移至除了 tensquare_common 以外每个子工程 pom.xml中
剪切的代码粘贴到每个微服务的pom.xml文件中,除了common不用放,其他四个微服务都需要操作
构建成功,公共子工程被安装到的路径:
/root/repo/com/tensquare/tensquare_common/1.0-SNAPSHOT/tensquare_common-1.0-SNAPSHOT.jar
在 Jenkinsfile 中写入微服务打包代码
//定义gitlab的凭证
def git_auth="03757112-b3bd-4955-93ef-ad84869f39a9"
//定义gitlab的URL路径
def git_url="[email protected]:gl/tensquare_back.git"
node {
stage('pull code') {
checkout([$class: 'GitSCM', branches: [[name: "*/${branch}"]], extensions: [], userRemoteConfigs: [[credentialsId: "${git_auth}", url: "${git_url}"]]])
}
stage('check code') {
//定义SonarQubeScanner工具
def scannerHome = tool 'sonar-scanner'
//引用SonarQube系统环境
withSonarQubeEnv('sonarqube') {
sh """
cd ${project_name}
${scannerHome}/bin/sonar-scanner
"""
}
}
//添加公共子工程
stage('make install public sub project') {
sh "mvn -f tensquare_common clean install"
}
//编译打包微服务
stage('make package') {
sh "mvn -f ${project_name} clean package"
}
}
进行代码提交
构建eureka服务
构建tensquare_zuul服务网关
失败原因:
因为Jenkins服务器中并没有tensquare_paren工程,而zuul需要依赖这个工程
解决方法:
传递父工程进Jenkins仓库
继续打包zuul服务网关
打包活动微服务
到此所有的微服务项目就已经全部打包成功了
利用 dockerfile-maven-plugin 插件构建 Docker 镜像
在每个微服务项目的 pom.xml 加入 dockerfile-maven-plugin 插件
<plugin>
<groupId>com.spotify</groupId>
<artifactId>dockerfile-maven-plugin</artifactId>
<version>1.3.6</version>
<configuration>
<repository>${project.artifactId}</repository>
<buildArgs>
<JAR_FILE>target/${project.build.finalName}.jar</JAR_FILE>
</buildArgs>
</configuration>
</plugin>
在每个微服务项目根目录下建立Dockerfile文件,需要注意的是每个项目公开的端口是不一样的
#FROM java:8
FROM openjdk:8-jdk-alpine
ARG JAR_FILE
COPY ${JAR_FILE} app.jar
EXPOSE 9001
ENTRYPOINT ["java","-jar","/app.jar"]
tensquare_eureka_server:
#FROM java:8
FROM openjdk:8-jdk-alpine
ARG JAR_FILE
COPY ${JAR_FILE} app.jar
EXPOSE 10086
ENTRYPOINT ["java","-jar","/app.jar"]
tensquare_gathering:
#FROM java:8
FROM openjdk:8-jdk-alpine
ARG JAR_FILE
COPY ${JAR_FILE} app.jar
EXPOSE 9002
ENTRYPOINT ["java","-jar","/app.jar"]
tensquare_zuul:
#FROM java:8
FROM openjdk:8-jdk-alpine
ARG JAR_FILE
COPY ${JAR_FILE} app.jar
EXPOSE 10020
ENTRYPOINT ["java","-jar","/app.jar"]
修改 Jenkinsfile ,在其中写入构建脚本
构建eureka服务
Jenkins服务器中查看镜像
制作其他微服务的镜像
到此为此,所有微服务镜像制作完成!!
修改Jenkinsfile脚本
//定义gitlab的凭证
def git_auth="03757112-b3bd-4955-93ef-ad84869f39a9"
//定义gitlab的URL路径
def git_url="[email protected]:gl/tensquare_back.git"
//镜像标签
def tag="latest"
//harbor的url地址
def harbor_url="192.168.8.20:85"
//镜像仓库名
def harbor_name="tensquare"
node {
stage('pull code') {
checkout([$class: 'GitSCM', branches: [[name: "*/${branch}"]], extensions: [], userRemoteConfigs: [[credentialsId: "${git_auth}", url: "${git_url}"]]])
}
stage('check code') {
//定义SonarQubeScanner工具
def scannerHome = tool 'sonar-scanner'
//引用SonarQube系统环境
withSonarQubeEnv('sonarqube') {
sh """
cd ${project_name}
${scannerHome}/bin/sonar-scanner
"""
}
}
//添加公共子工程
stage('make install public sub project') {
sh "mvn -f tensquare_common clean install"
}
//编译打包微服务,制作镜像
stage('make package') {
sh "mvn -f ${project_name} clean package dockerfile:build"
//定义镜像名称
def imageName="${project_name}:${tag}"
//对镜像打标签
sh "docker tag ${imageName} ${harbor_url}/${harbor_name}/${imageName}"
}
}
代码提交后,构建eureka测试打标签结果
对所有的微服务进行打标签
镜像上传 harbor 仓库需要先进行登录,但是如果把账号密码卸载脚本中并不是很安全也不切合实际,所以需要使用变量的方式来进行调用。
778a9460-c68d-4ab6-ab7f-f5113ec3a900
使用流水线语法中的片段生成器来生成代码,并把复制到Jenkinsfile脚本中
//定义gitlab的凭证
def git_auth="03757112-b3bd-4955-93ef-ad84869f39a9"
//定义gitlab的URL路径
def git_url="[email protected]:gl/tensquare_back.git"
//镜像标签
def tag="latest"
//harbor的url地址
def harbor_url="192.168.8.20:85"
//镜像仓库名
def harbor_name="tensquare"
//harbor凭证
def harbor_auth="778a9460-c68d-4ab6-ab7f-f5113ec3a900"
node {
stage('pull code') {
checkout([$class: 'GitSCM', branches: [[name: "*/${branch}"]], extensions: [], userRemoteConfigs: [[credentialsId: "${git_auth}", url: "${git_url}"]]])
}
stage('check code') {
//定义SonarQubeScanner工具
def scannerHome = tool 'sonar-scanner'
//引用SonarQube系统环境
withSonarQubeEnv('sonarqube') {
sh """
cd ${project_name}
${scannerHome}/bin/sonar-scanner
"""
}
}
//添加公共子工程
stage('make install public sub project') {
sh "mvn -f tensquare_common clean install"
}
//编译打包微服务,制作镜像
stage('make package') {
sh "mvn -f ${project_name} clean package dockerfile:build"
//定义镜像名称
def imageName="${project_name}:${tag}"
//对镜像打标签
sh "docker tag ${imageName} ${harbor_url}/${harbor_name}/${imageName}"
//镜像推送到harbor
withCredentials([usernamePassword(credentialsId: "${harbor_auth}", passwordVariable: 'password', usernameVariable: 'username')]) {
//登录harbor
sh "docker login -u ${username} -p ${password} ${harbor_url}"
//镜像上传
sh "docker push ${harbor_url}/${harbor_name}/${imageName}"
sh "echo 镜像上传成功"
}
}
}
更改提交代码后,测试镜像上传
登录harbor仓库查看项目中的镜像是否已经上传成功
到此,所有微服务的镜像成功上传到harbor仓库中
Publish Over SSH 插件可以实现远程发送Shell命令,安装完需要重启 Jenkins
拷贝公钥,从Jenkins服务器拷贝到生产服务器
ssh-copy-id 192.168.8.17
Jenkins 系统配置中添加远程服务器
//定义gitlab的凭证
def git_auth="03757112-b3bd-4955-93ef-ad84869f39a9"
//定义gitlab的URL路径
def git_url="[email protected]:gl/tensquare_back.git"
//镜像标签
def tag="latest"
//harbor的url地址
def harbor_url="192.168.8.20:85"
//镜像仓库名
def harbor_name="tensquare"
//harbor凭证
def harbor_auth="778a9460-c68d-4ab6-ab7f-f5113ec3a900"
node {
stage('pull code') {
checkout([$class: 'GitSCM', branches: [[name: "*/${branch}"]], extensions: [], userRemoteConfigs: [[credentialsId: "${git_auth}", url: "${git_url}"]]])
}
stage('check code') {
//定义SonarQubeScanner工具
def scannerHome = tool 'sonar-scanner'
//引用SonarQube系统环境
withSonarQubeEnv('sonarqube') {
sh """
cd ${project_name}
${scannerHome}/bin/sonar-scanner
"""
}
}
//添加公共子工程
stage('make install public sub project') {
sh "mvn -f tensquare_common clean install"
}
//编译打包微服务,制作镜像
stage('make package') {
sh "mvn -f ${project_name} clean package dockerfile:build"
//定义镜像名称
def imageName="${project_name}:${tag}"
//对镜像打标签
sh "docker tag ${imageName} ${harbor_url}/${harbor_name}/${imageName}"
//镜像推送到harbor
withCredentials([usernamePassword(credentialsId: "${harbor_auth}", passwordVariable: 'password', usernameVariable: 'username')]) {
//登录harbor
sh "docker login -u ${username} -p ${password} ${harbor_url}"
//镜像上传
sh "docker push ${harbor_url}/${harbor_name}/${imageName}"
sh "echo 镜像上传成功"
}
//部署应用
sshPublisher(publishers: [sshPublisherDesc(configName: 'master_server', transfers: [sshTransfer(cleanRemote: false, excludes: '', execCommand: "/opt/jenkins_shell/deploy.sh ${harbor_url} ${harbor_name} ${project_name} ${tag} ${port}", execTimeout: 120000, flatten: false, makeEmptyDirs: false, noDefaultExcludes: false, patternSeparator: '[, ]+', remoteDirectory: '', remoteDirectorySDF: false, removePrefix: '', sourceFiles: '')], usePromotionTimestamp: false, useWorkspaceInPromotion: false, verbose: false)])
}
}
添加端口新参数
#! /bin/sh
#接收外部参数
harbor_url=$1
harbor_project_name=$2
project_name=$3
tag=$4
port=$5
imageName=$harbor_url/$harbor_project_name/$project_name:$tag
echo "$imageName"
#查询容器是否存在,存在则删除
containerId=`docker ps -a | grep -w ${project_name}:${tag} | awk '{print $1}'`
if [ "$containerId" != "" ] ; then
#停掉容器
docker stop $containerId
#删除容器
docker rm $containerId
echo "成功删除容器"
fi
#查询镜像是否存在,存在则删除
imageId=`docker images | grep -w $project_name | awk '{print $3}'`
if [ "$imageId" != "" ] ; then
#删除镜像
docker rmi -f $imageId
echo "成功删除镜像"
fi
# 登录Harbor
docker login -u tom -p Abcd1234 $harbor_url
# 下载镜像
docker pull $imageName
# 启动容器
docker run -di -p $port:$port $imageName
echo "容器启动成功"
在生产服务器上创建目录,并放入脚本
mkdir /opt/jenkins_shell
cd /opt/jenkins_shell/
vim deploy.sh
chmod +x deploy.sh
Jenkinsfile更改提交进行构建测试
在生产服务器上检查结果
在浏览器中查看服务
tensquare_eureka_server
tensquare_gathering
修改完以后进行提交代码仓库
生产服务器上查看结果
登录注册中心查看是否注册成功
mysql -uroot -pabc123
grant all privileges on *.* to 'root'@'%' identified by 'abc123' with grant option;
create database tensquare_gathering;
create database tensquare_user;
#导入脚本文件
use tensquare_gathering;
source /root/tensquare_gathering.sql;
use tensquare_user;
source /root/tensquare_user.sql;
生产服务器上部署nginx服务器
yum install -y epel-release
yum -y install nginx
#修改nginx的端口,默认80,改为9090
vi /etc/nginx/nginx.conf
server {
listen 9090;
listen [::]:9090;
server_name _;
root /usr/share/nginx/html;
#关闭selinux,将SELINUX=disabled
setenforce 0 #先临时关闭
vi /etc/selinux/config #编辑文件,永久关闭 SELINUX=disabled
#启动Nginx
systemctl enable nginx 设置开机启动
systemctl start nginx 启动
systemctl stop nginx 停止
systemctl restart nginx 重启
访问:http://192.168.8.17:9090/
Manage Jenkins->Global Tool Configuration
创建前端流水线项目
添加参数化构建
添加声明式脚本代码
//harbor的凭证
def git_auth="03757112-b3bd-4955-93ef-ad84869f39a9"
node {
stage('pull code') {
//切换成变量,字符串符号使用双引号
checkout([$class: 'GitSCM', branches: [[name: "*/${branch}"]], extensions: [], userRemoteConfigs: [[credentialsId: "${git_auth}", url: '[email protected]:gl/tensquare_back.git']]])
}
stage('make package,deploy') {
//使用nodejs的npm打包
nodejs('nodejs12'){
sh '''
npm install
npm run build
'''
}
//远程部署
sshPublisher(publishers: [sshPublisherDesc(configName: 'master_server', transfers: [sshTransfer(cleanRemote: false, excludes: '', execCommand: '', execTimeout: 120000, flatten: false, makeEmptyDirs: false, noDefaultExcludes: false, patternSeparator: '[, ]+', remoteDirectory: '/usr/share/nginx/html', remoteDirectorySDF: false, removePrefix: 'dist', sourceFiles: 'dist/**')], usePromotionTimestamp: false, useWorkspaceInPromotion: false, verbose: false)])
}
}
点击提交以后,点击推送
构建完成以后重新登录