热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

6.Gitlab集成Jenkins静态页面发布

4Jenkins4.1Jenkins介绍Jenkins是一个开源的CI/CD工具,由java语言编写其本质就是一
4 Jenkins

4.1 Jenkins介绍

  • Jenkins是一个开源的CI/CD工具, 由java语言编写
  • 其本质就是一个调度平台, 本身不处理任何事情, 而是调用插件来完成所有的工作

4.2 Jenkins部署

4.2.1 环境

CentOS-7
10.0.0.237 - Gitlab - gitlab-ce-12.0.3
10.0.0.227 - Jenkins - Jenkins-2.176.1
CentOS-8
10.0.0.82 - 开发机-developer-2 / websrv-2
10.0.0.81 - 开发机-developer-1 / websrv-1

4.2.2 安装Jenkins

[18:52:58 root@jenkins ~]#yum localinstall jenkins-2.176.1-1.1.noarch.rpm -y
[19:03:12 root@jenkins ~]#yum -y install java-1.8.0-openjdk.x86_64 # Jenkins需要Java环境
yum -y install git
[19:03:30 root@jenkins ~]#systemctl start jenkins
[19:03:37 root@jenkins ~]#systemctl status jenkins
● jenkins.service - LSB: Jenkins Automation Server
   Loaded: loaded (/etc/rc.d/init.d/jenkins; bad; vendor preset: disabled)
   Active: active (running) since Wed 2020-12-30 19:03:37 CST; 6s ago

4.2.2.1 Jenkins监听8080端口

LISTEN     0      50                                                          [::]:8080                                                                    [::]:* 

4.2.3 配置Windows客户端和jenkins服务器本地域名解析

10.0.0.237 gitlab.abc.com
10.0.0.227 jenkins.abc.com
10.0.0.237 gitlab.abc.com
10.0.0.227 jenkins.abc.com

4.2.4 访问jenkins

  1. http://jenkins.abc.com:8080
6. Gitlab集成Jenkins-静态页面发布
图片.png
  1. 从文件中获得jenkins密码
[19:09:04 root@jenkins ~]#cat /var/lib/jenkins/secrets/initialAdminPassword
f19096b3376b48b8a8bb2f45183fc963
  1. 跳过插件安装, 稍后手动安装
6. Gitlab集成Jenkins-静态页面发布
图片.png
6. Gitlab集成Jenkins-静态页面发布
图片.png
  1. 修改admin密码
6. Gitlab集成Jenkins-静态页面发布
图片.png
6. Gitlab集成Jenkins-静态页面发布
图片.png

4.2.5 插件安装

6. Gitlab集成Jenkins-静态页面发布
图片.png
6. Gitlab集成Jenkins-静态页面发布
图片.png
6. Gitlab集成Jenkins-静态页面发布
图片.png

4.2.5.1 调整jenkins插件源, 使用清华源

https://mirrors.tuna.tsinghua.edu.cn/jenkins/updates/update-center.json

6. Gitlab集成Jenkins-静态页面发布
图片.png

4.2.5.2 在线安装插件

如需在线安装, 只要进到Available然后再搜索栏搜索即可

6. Gitlab集成Jenkins-静态页面发布
图片.png

4.2.5.3 从清华源下载.hpi文件后安装插件

实例: 安装jenjins的git插件

  1. 下载插件

https://mirrors.tuna.tsinghua.edu.cn/jenkins/plugins/

  1. 上传插件
6. Gitlab集成Jenkins-静态页面发布
图片.png
6. Gitlab集成Jenkins-静态页面发布
图片.png
  1. 安装插件

上传后, 点Upload即可, 之后会在线安装

4.2.5.4 离线安装插件

  1. 停止jenkins服务
[19:17:30 root@jenkins ~]#systemctl stop jenkins
  1. jenkins插件目录
[19:44:59 root@jenkins ~]#ll /var/lib/jenkins/plugins/
total 0
  1. 移走现有的plugins目录, 如果里面有内容, 然后把本地的插件包解压, 移动到/var/lib/jenkins/目录下
[19:45:27 root@jenkins ~]#rm -rf /var/lib/jenkins/plugins
[19:47:30 root@jenkins ~]#tar xf jenkins_2.176_plugins.tar.gz
[19:47:52 root@jenkins ~]#mv plugins/ /var/lib/jenkins/
[19:48:49 root@jenkins ~]#chown -R jenkins.jenkins /var/lib/jenkins
  1. 启动jenkins
[19:50:50 root@jenkins ~]#systemctl start jenkins
  1. 查看日志
[19:53:02 root@jenkins ~]#tail -f /var/log/jenkins/jenkins.log
INFO: Completed initialization
Dec 30, 2020 7:53:34 PM hudson.WebAppMain$3 run
INFO: Jenkins is fully up and running  # 看到这句话就说明启动成功
  1. 登录jenkins

  2. 配置警告信息

6. Gitlab集成Jenkins-静态页面发布
图片.png
6. Gitlab集成Jenkins-静态页面发布
图片.png
  1. 把所有警告信息取消, 保存即可

4.2.6 Jenkins自由风格软件项目简单测试

  1. 创建项目

    6. Gitlab集成Jenkins-静态页面发布
    图片.png
  2. 设置保留最近10个构建项目

    6. Gitlab集成Jenkins-静态页面发布
    图片.png
  3. 构建操作, 执行Shell, 这里的Shell命令会在Jenkins拉取Gitlab代码后, 在Jenkins服务器上执行

6. Gitlab集成Jenkins-静态页面发布
图片.png
6. Gitlab集成Jenkins-静态页面发布
图片.png
  1. 立即构建
6. Gitlab集成Jenkins-静态页面发布
图片.png
  1. 查看控制台输出
6. Gitlab集成Jenkins-静态页面发布
图片.png

6. Gitlab集成Jenkins-静态页面发布
图片.png
6. Gitlab集成Jenkins-静态页面发布
图片.png
  • 通过这种构建方法, 只要登录到jenkins上, 操作立即构建, 即可完成项目构建, 把代码从Gitlab拉取到Jenkins服务器, 之后在推送到后端服务器, 这样就无需登录到Jenkins服务器了
  • Jenkins可以实现权限控制, 不同人访问不同的项目
  1. 构建后的文件

构建后的内容都会存在jenkins服务器上的, /var/lib/jenkins/workspace目录, 以项目名为目录做区分

[19:54:39 root@jenkins ~]#ll /var/lib/jenkins/workspace/
total 0
drwxr-xr-x 2 jenkins jenkins 31 Dec 30 20:24 test-project
[20:30:11 root@jenkins ~]#ll /var/lib/jenkins/workspace/test-project/
total 0
-rw-r--r-- 1 jenkins jenkins 0 Dec 30 20:24 file_from_jenkins

4.3 Jenkins集成Gitlab

4.3.1 Gitlab创建项目

用developer-2管理员用户

6. Gitlab集成Jenkins-静态页面发布
图片.png

4.3.2 将项目包拷贝到developer-2用户的git客户端, 并解压

[13:51:18 root@developer-2 ~]#ls
monitor_html.tar.gz
[13:51:56 root@developer-2 ~]#tar xf monitor_html.tar.gz 
[13:52:16 root@developer-2 ~]#ls
monitor  monitor_html.tar.gz
[13:52:17 root@developer-2 ~]#ls monitor
404.html       charts.html           dianfei.html             form-components.html  img           LICENSE         messages.html            QHME.iml        typography.html
alerts.html    components.html       efficiencyAnalysis.html  form-elements.html    index.html    list-view.html  mstp_105_SuperAdmin.iml  readme.md       userMng.html
assets         content-widgets.html  energy_consumption.html  form-examples.html    js            login.html      mstp_map.html            real-time.html
buttons.html   css                   file-manager.html        form-validation.html  keyInfo.html  media           other-components.html    sa.html
calendar.html  deviceManager.html    fonts                    images-icons.html     labels.html   media.html      profile-page.html        tables.html

buttons.html   css                   file-manager.html        form-validation.html  keyInfo.html  media           other-components.html    sa.html
calendar.html  deviceManager.html    fonts                    images-icons.html     labels.html   media.html      profile-page.html        tables.html

4.3.3 关联远程仓库, 推送本地现有文件夹

# 先将原有的仓库信息删除, 如果已有
[13:52:33 root@developer-2 ~]#cd monitor/
[13:53:17 root@developer-2 ~/monitor]#git remote -v
origin  https://gitee.com/kangjie1209/monitor.git (fetch)
origin  https://gitee.com/kangjie1209/monitor.git (push)
[13:53:21 root@developer-2 ~/monitor]#git remote remove origin
[13:53:28 root@developer-2 ~/monitor]#git init
Reinitialized existing Git repository in /root/monitor/.git/
[13:53:45 root@developer-2 ~/monitor]#git remote add origin git@gitlab.abc.com:devops/monitor.git
[13:54:00 root@developer-2 ~/monitor]#git add .
[13:54:03 root@developer-2 ~/monitor]#git commit -m "第一次提交代码"
On branch master
nothing to commit, working tree clean
[13:54:15 root@developer-2 ~/monitor]#git push origin master
Enumerating objects: 435, done.
Counting objects: 100% (435/435), done.
Compressing objects: 100% (372/372), done.
Writing objects: 100% (435/435), 8.78 MiB | 6.19 MiB/s, done.
Total 435 (delta 53), reused 435 (delta 53), pack-reused 0
remote: Resolving deltas: 100% (53/53), done.
To gitlab.abc.com:devops/monitor.git
 * [new branch]      master -> master

4.3.4 Gitlab验证

6. Gitlab集成Jenkins-静态页面发布
图片.png

4.3.5 jenkins安装gitlab插件

这里前期已经统一离线导入了插件, 所以无需再安装

6. Gitlab集成Jenkins-静态页面发布
image.png
  • Credential: 允许Jenkins中存储认证的凭据
  • Git Client: 允许Jenkins使用Git
  • Git: 允许Jenkins集成Git
  • Gitlab: 允许Gitlab触发Jenkins构建, 并在Gitlab中显示
  • Gitlab Hook Plugin: 允许Gitlab自动触发Jenkins构建项目
  • Gitlab Authentication: Gitlab身份验证插件

4.3.6 Jenkins创建freestyle项目, 然后配置gitlab仓库项目对应地址

6. Gitlab集成Jenkins-静态页面发布
image.png
6. Gitlab集成Jenkins-静态页面发布
image.png

添加git仓库地址后, 如果出现以下报错, 可能是jenkins服务器没有装git, 需要安装

6. Gitlab集成Jenkins-静态页面发布
图片.png

安装git后, 如果出现如下报错, 是因为没有配置验证

  1. 在jenkins服务器生成root账号的ssh秘钥
[21:31:57 root@jenkins ~]#ssh-keygen
  1. 把公钥放到gitlab上, 公钥放到任何一个对项目有权限的用户的账户里即可

  2. 添加jenkins凭据

6. Gitlab集成Jenkins-静态页面发布
图片.png

这里要把jenkins上用root用户创建的私钥添加进去, 因为我们把root的公钥放到了gitlab上, jenkins连接gitlab时, gitlab会用拿到的公钥做认证

6. Gitlab集成Jenkins-静态页面发布
图片.png
6. Gitlab集成Jenkins-静态页面发布
图片.png
  1. 保存后点击构建
6. Gitlab集成Jenkins-静态页面发布
图片.png
  1. 构建成功后, 返回工程, 进入工作区
6. Gitlab集成Jenkins-静态页面发布
image.png
6. Gitlab集成Jenkins-静态页面发布
image.png
6. Gitlab集成Jenkins-静态页面发布
image.png
[21:44:23 root@jenkins ~]#ll /var/lib/jenkins/workspace/
total 4
drwxr-xr-x 9 jenkins jenkins 4096 Dec 30 21:40 freestyle-monitor
drwxr-xr-x 2 jenkins jenkins    6 Dec 30 21:40 freestyle-monitor@tmp
drwxr-xr-x 2 jenkins jenkins   31 Dec 30 20:24 test-project
[21:44:24 root@jenkins ~]#ll /var/lib/jenkins/workspace/freestyle-monitor
total 1364
-rw-r--r--  1 jenkins jenkins  1208 Dec 30 21:40 404.html
-rw-r--r--  1 jenkins jenkins 27249 Dec 30 21:40 alerts.html
drwxr-xr-x  5 jenkins jenkins    64 Dec 30 21:40 assets
-rw-r--r--  1 jenkins jenkins 34972 Dec 30 21:40 buttons.html
...

到此, 完成了jenkins从gitlab拉取代码, 下面实现项目发布

4.4 手动实现集群架构代码上线

环境:

CentOS 7
----------------------------------
Gitlab - 10.0.0.237 - gitlab.abc.com
Jenkins - 10.0.0.227 - jenkins.abc.com
SonarQube - 10.0.0.207 - sonarqube.abc.com
Nginx-LB - 10.0.0.217 nginx负载均衡服务器后端代理 web服务器 - html.abc.com, 和tomcat服务器, java.abc.com, 需要在windows做域名解析 512MB

CentOS-8
10.0.0.82 - 开发机-developer-2 / websrv-2
10.0.0.81 - 开发机-developer-1 / websrv-1

----------------------------------

4.4.1 配置负载均衡服务器 10.0.0.217

[21:57:44 root@lb ~]#yum -y install nginx
[21:58:02 root@lb ~]#cd /etc/nginx/conf.d
[21:59:45 root@lb /etc/nginx/conf.d]#vim proxy_html.abc.com.conf

upstream html {
    server 10.0.0.81;
    server 10.0.0.82;


}

server {
    listen 80;
    server_name html.abc.com;
    location / {
            proxy_pass http://html;
            proxy_set_header Host $http_Host;       # 如果后端nginx配置了单独的虚拟主机, 并且指定了主机头为访问的域名html.abc.com, 那么就需要再反向代理加上proxy_set_header, 把用户请求报文的Host字段传给后端服务器, 否则因为upstream定义的是ip地址,  那么转给后端服务器后, 就是转给了默认的虚拟主机, 这样就访问不到子配置文件中的虚拟主机                                                                                      
    } 
[22:07:27 root@lb /etc/nginx/conf.d]#nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
[22:07:33 root@lb /etc/nginx/conf.d]#systemctl restart nginx

4.4.2 配置web1

[22:09:39 root@web1 ~]#yum -y install nginx
[22:11:55 root@web1 ~]#vim /etc/nginx/conf.d/html.abc.com.conf
server {

    listen 80;
    server_name html.abc.com;
    root /code/web;

    location / {                                                                                                                                    
        index index.html;

    }

}
~  
[22:17:31 root@web1 ~]#nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
[22:17:36 root@web1 ~]#systemctl restart nginx
[22:18:14 root@web1 ~]#mkdir /code/web -pv
mkdir: created directory ‘/code’
mkdir: created directory ‘/code/web’

4.4.2 配置web2

[22:09:52 root@web2 ~]#yum -y install nginx
[22:11:56 root@web2 ~]#vim /etc/nginx/conf.d/html.abc.com.conf
server {
                                                                                                                                                    
    listen 80;
    server_name html.abc.com;
    root /code/web;

    location / {
        index index.html;

    }

}
[22:19:26 root@web2 ~]#nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
[22:19:28 root@web2 ~]#systemctl restart nginx
[22:19:33 root@web2 ~]#mkdir -pv /code/web
mkdir: created directory ‘/code’
mkdir: created directory ‘/code/web’

这时访问html.abc.com会有403报错, 因为后端web服务器还没有代码上线

6. Gitlab集成Jenkins-静态页面发布
image.png

4.4.3 将jenkins服务器上workspace里的代码手动拷贝到两台web服务器上

[22:29:52 root@jenkins ~]#cd /var/lib/jenkins/workspace/freestyle-monitor
[22:29:52 root@jenkins /var/lib/jenkins/workspace/freestyle-monitor]#scp -r * 10.0.0.81:/code/web
[22:31:27 root@jenkins /var/lib/jenkins/workspace/freestyle-monitor]#scp -r * 10.0.0.82:/code/web

再次访问html.abc.com验证负载均衡成功

6. Gitlab集成Jenkins-静态页面发布
image.png

这样就实现了Jenkins集成Gitlab, 通过构建一个freestyle静态项目, 从Gitlab拉取代码到Jenkins, 再手动把代码从Jenkins复制到后端服务器, 实现代码部署

4.5 实现自动集群架构代码上线

思路:

  1. 手动搭建nginx集群架构
  2. 开发提交代码至gitlab, Jenkins手动构建拉取代码
  3. 在jenkins上编写shell构建脚本, 由jenkins调用, 并推送代码至web服务器组

4.5.1 编写jenkins推送代码脚本

[22:59:49 root@jenkins /data/scripts]#cat html_deploy.sh 
#!/bin/bash
DATE=`date +%Y-%m-%d-%H-%M-%S`
web_server="10.0.0.81 10.0.0.82"
#代码打包路径
sdir="/opt" # 把workspace目录下的代码打包到jenkins的/opt目录
#代码部署路径
ddir="/code"
#1. 进入到项目目录, 将内容进行打包
get_code(){
        cd ${WORKSPACE} &&   # WORKSPACE变量会返回当前Jenkins项目的目录, 也就是/var/lib/jenkins/workspace/freestyle-monitor
        tar czf ${sdir}/web-${DATE}.tar.gz ./*
}
#2. 将内容通过scp拷贝至web集群组
scp_web_server(){
for host in $web_server; do
    scp ${sdir}/web-${DATE}.tar.gz root@$host:${sdir}
    ssh root@$host "mkdir -p ${ddir}/web-${DATE} && 
                    tar xf ${sdir}/web-${DATE}.tar.gz -C ${ddir}/web-${DATE}
                    rm -rf ${ddir}/web &&   
#/code/web指向真正的代码目录, 因此. 每次构建都要把软连接删除, 重新添加软连接到新的代码目录, 这样静态页面的代码上线就是自动变成新的版本了
                    ln -s ${ddir}/web-${DATE} ${ddir}/web"
done
}
deploy(){
        get_code
        scp_web_server

}

deploy

4.5.2 将脚本添加到jenkins

6. Gitlab集成Jenkins-静态页面发布
image.png
6. Gitlab集成Jenkins-静态页面发布
image.png
6. Gitlab集成Jenkins-静态页面发布
image.png

将jenkins设置成以root用户运行, 避免脚本执行过程中由于默认的jenkins用户没有权限导致脚本执行失败, 把jenkins设置为sudo也行

vim  /etc/sysconfig/jenkins
JENKINS_USER="root" 
systemctl restart jenkins

将jenkins的公钥推送到后端web服务器, 实现ssh免秘钥认证

ssh-copy-id -i ~/.ssh/id_rsa.pub root@10.0.0.81
ssh-copy-id -i ~/.ssh/id_rsa.pub root@10.0.0.82

4.5.3 构建工程, 查看控制台输出

6. Gitlab集成Jenkins-静态页面发布
image.png

构建如果出现报错, 要配合控制台输出进行排错后再次构建, 构建成功后要去web服务器目录下把错误的输出文件都删除

6. Gitlab集成Jenkins-静态页面发布
图片.png
6. Gitlab集成Jenkins-静态页面发布
图片.png

静态页面自动上线思路:

  1. 开发将代码推送到gitlab
  2. jenkins需要事先配置好集成gitlab, 通过构建项目, 添加gitlab项目的目录, Jenkins私钥认证, 以及jenkins公钥添加到Gitlab, 以及构建脚本
  3. 进到项目工作区, 通过手动点击构建. jenkins会到gitlab上把代码拉取到jenkins本地/var/lib/jenkins/workspace/项目目录, 然后执行sh脚本, 把代码在部署到后端服务器
  4. 这种方式适用于静态页面上线, 因为不需要编译, 直接把代码部署到后端服务器即可
  5. 对于php也适用, 不过部署完代码后需要重启php-fpm, 并且删除之前的缓存

4.5.4 实现项目代码升级的发布

测试小案例

  1. 直接修改gitlab上的index.html页面, 省去开发将项目拉取到本地修改, 在推送到gitlab的过程
6. Gitlab集成Jenkins-静态页面发布
  1. 构建, 验证修改
6. Gitlab集成Jenkins-静态页面发布
image.png

4.6 Jenkins实现基于版本tag发布

  • 让项目基于tag的方式发布

4.6.1 为什么要让项目支持tag版本方式上线?

由于之前上线方式是直接获取最新代码, 那么会造成后期回退变困难. 如果采用tag的方式, 比如第一次上线 tag v1.1, 第二次上线 tag v1.2. 如果上线v1.2出现问题, 那么我们可以快速回退至上一个版本v1.1

4.6.2 实现tag版本上线方式思路

  1. 开发如果需要发布新版本, 必须将当前的版本打上一个标签
  2. Jenkins需要让其脚本支持传参, 比如用户传递v1.1则拉取项目v1.1的标签

4.6.3 Jenkins参数化构建介绍

  1. 定义文本参数

    6. Gitlab集成Jenkins-静态页面发布
    image.png
  2. 定义选项参数

    6. Gitlab集成Jenkins-静态页面发布
    image.png
  3. 修改构建Shell命令, 测试文本参数和选项参数功能

6. Gitlab集成Jenkins-静态页面发布
image.png
  1. 这时工作区不会显示立即构建, 而是Build with Parameter
6. Gitlab集成Jenkins-静态页面发布
image.png
  1. 手动指定git_version变量值, 选择部署还是发布, 点击开始构建
6. Gitlab集成Jenkins-静态页面发布
image.png
6. Gitlab集成Jenkins-静态页面发布
image.png
  1. 测试结果

从构建结果可以看出, git_version 和 deploy_env可以作为变量, 在构建Shell命令的脚本里调用, 实现从Jenkins界面在构建时指定参数, 传给脚本, 这样Jenkins在拉取代码时可以基于tag版本拉取, 同时, 也可以指定, 本次构建是拉取还是回退操作.

4.7 实战Jenkins部署tag版本

  1. 首先安装Git Parameter插件, 然后配置Jenkins参数化构建, 让用户在构建时选择对应的tag版本
6. Gitlab集成Jenkins-静态页面发布
image.png
[01:08:33 root@jenkins ~]#tail -f /var/log/jenkins/jenkins.log 
Dec 31, 2020 1:15:45 AM jenkins.InitReactorRunner$1 onAttained
INFO: Augmented all extensions
Dec 31, 2020 1:15:45 AM jenkins.InitReactorRunner$1 onAttained
INFO: Loaded all jobs
Dec 31, 2020 1:15:45 AM jenkins.InitReactorRunner$1 onAttained
INFO: Completed initialization
Dec 31, 2020 1:15:46 AM hudson.PluginManager dynamicLoad
INFO: Plugin git-parameter:0.9.13 dynamically installed
Dec 31, 2020 1:15:46 AM hudson.model.UpdateCenter$DownloadJob run
INFO: Installation successful: Git Parameter
6. Gitlab集成Jenkins-静态页面发布
image.png
  1. 配置参数化构建, 选择Git Parameter
  • Jenkins会根据构建时, 选择的版本号, 去Git拉取对应的版本
6. Gitlab集成Jenkins-静态页面发布
6. Gitlab集成Jenkins-静态页面发布
图片.png
  1. 修改构建脚本, 把参数加进去
[12:32:33 root@jenkins /data/scripts]#vim html_deploy_tag.sh
DATE=`date +%Y-%m-%d-%H-%M-%S`
web_server="10.0.0.81 10.0.0.82"
#代码打包路径
sdir="/opt"
#代码部署路径
ddir="/code"
#1. 进入到项目目录, 将内容进行打包
get_code(){
        cd ${WORKSPACE} && 
        tar czf ${sdir}/web-${DATE}-${git_version}.tar.gz ./*
}
#2. 将内容通过scp拷贝至web集群组
scp_web_server(){
for host in $web_server; do
    scp ${sdir}/web-${DATE}-${git_version}.tar.gz root@$host:${sdir}
    ssh root@$host "mkdir -p ${ddir}/web-${DATE}-${git_version} && 
                    tar xf ${sdir}/web-${DATE}-${git_version}.tar.gz -C ${ddir}/web-${DATE}-${git_version}
                    rm -rf ${ddir}/web && 
                    ln -s ${ddir}/web-${DATE}-${git_version} ${ddir}/web"                                                                                                           
done
}
deploy(){
        get_code
        scp_web_server

}

deploy
6. Gitlab集成Jenkins-静态页面发布
图片.png
  1. 执行构建
  • 可以看到此时没有tag可供选择, 因为Gitlab代码还没有加tag

    6. Gitlab集成Jenkins-静态页面发布
  1. Gitlab上给代码加tag
  • 用10.0.0.82, developer-2的开发机, 拉取代码到本地, 添加tag, 重新上传
[19:51:29 root@developer-2 ~]#ls
monitor  monitor_html.tar.gz
[19:51:31 root@developer-2 ~]#cd monitor/
[19:51:45 root@developer-2 ~/monitor]#git pull origin master 
[19:51:51 root@developer-2 ~/monitor]#git tag -a "v1.1" -m "测试tag-v1.1"
[19:52:39 root@developer-2 ~/monitor]#git tag
v1.1
[19:52:41 root@developer-2 ~/monitor]#git push origin v1.1
  1. 修改index.html文件, 推送v1.2版本
6. Gitlab集成Jenkins-静态页面发布
图片.png
[19:52:50 root@developer-2 ~/monitor]#vim index.html 
[19:53:49 root@developer-2 ~/monitor]#git add .
[19:53:52 root@developer-2 ~/monitor]#git commit -m "v1.2"
[master dbebf09] v1.2
 1 file changed, 1 insertion(+), 1 deletion(-)
[19:53:58 root@developer-2 ~/monitor]#git push origin master
Enumerating objects: 5, done.
Counting objects: 100% (5/5), done.
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 307 bytes | 307.00 KiB/s, done.
Total 3 (delta 2), reused 0 (delta 0), pack-reused 0
To gitlab.abc.com:devops/monitor.git
   26cd3d5..dbebf09  master -> master
[19:54:08 root@developer-2 ~/monitor]#git tag -a "v1.2" -m "提交v1.2版本"
[19:54:20 root@developer-2 ~/monitor]#git push origin v1.2
Enumerating objects: 1, done.
Counting objects: 100% (1/1), done.
Writing objects: 100% (1/1), 182 bytes | 182.00 KiB/s, done.
Total 1 (delta 0), reused 0 (delta 0), pack-reused 0
To gitlab.abc.com:devops/monitor.git
 * [new tag]         v1.2 -> v1.2
  1. 再修改index.html, 推送v1.3版本
6. Gitlab集成Jenkins-静态页面发布
图片.png
[19:54:39 root@developer-2 ~/monitor]#vim index.html 
[19:55:37 root@developer-2 ~/monitor]#git add .
[19:55:43 root@developer-2 ~/monitor]#git commit -m "提交v1.3版本"
[master 747844f] 提交v1.3版本
 1 file changed, 1 insertion(+), 1 deletion(-)
[19:55:55 root@developer-2 ~/monitor]#git push origin master
Enumerating objects: 5, done.
Counting objects: 100% (5/5), done.
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 328 bytes | 328.00 KiB/s, done.
Total 3 (delta 2), reused 0 (delta 0), pack-reused 0
To gitlab.abc.com:devops/monitor.git
   dbebf09..747844f  master -> master
[19:56:06 root@developer-2 ~/monitor]#git tag -a "v1.3" -m "提交v1.3版本"
[19:56:21 root@developer-2 ~/monitor]#git push origin v1.3
Enumerating objects: 1, done.
Counting objects: 100% (1/1), done.
Writing objects: 100% (1/1), 181 bytes | 181.00 KiB/s, done.
Total 1 (delta 0), reused 0 (delta 0), pack-reused 0
To gitlab.abc.com:devops/monitor.git
 * [new tag]         v1.3 -> v1.3

现在有三个版本,v1.1,v1.2,v1.3, 可以基于tag部署

  1. 回到jenkins, 验证tag可用, 构建v1.3版本
6. Gitlab集成Jenkins-静态页面发布
图片.png
6. Gitlab集成Jenkins-静态页面发布
图片.png
[10:56:13 root@web1 ~]#ll /code
total 16
lrwxrwxrwx 1 root root   34 Dec 31 12:59 web -> /code/web-2020-12-31-12-59-05-v1.3
  1. 测试回退到v1.2
6. Gitlab集成Jenkins-静态页面发布
图片.png
6. Gitlab集成Jenkins-静态页面发布
图片.png

但是, 此时, 每次构建, 项目代码都会拷贝到web服务器的项目目录下, 之后要解决这个问题

[13:00:51 root@web1 ~]#ll /code
total 20
lrwxrwxrwx 1 root root   34 Dec 31 13:04 web -> /code/web-2020-12-31-13-04-52-v1.2
drwxr-xr-x 8 root root 4096 Dec 30 23:28 web-2020-12-30-23-28-26
drwxr-xr-x 8 root root 4096 Dec 30 23:59 web-2020-12-30-23-59-56
drwxr-xr-x 2 root root    6 Dec 31 00:21 web-2020-12-31-00-21-46
drwxr-xr-x 5 root root   80 Dec 31 00:23 web-2020-12-31-00-23-42
drwxr-xr-x 2 root root    6 Dec 31 00:24 web-2020-12-31-00-24-20
drwxr-xr-x 8 root root 4096 Dec 31 00:25 web-2020-12-31-00-25-47
drwxr-xr-x 8 root root 4096 Dec 31 12:59 web-2020-12-31-12-59-05-v1.3
drwxr-xr-x 8 root root 4096 Dec 31 13:04 web-2020-12-31-13-04-52-v1.2

到此为止, 只是实现了利用tag, 部署不同的版本, 但是每次都会再web目录下,生成新的项目代码, 下面实现回退功能

  1. 添加选项参数
6. Gitlab集成Jenkins-静态页面发布
图片.png
6. Gitlab集成Jenkins-静态页面发布
图片.png
  1. 修改构建脚本, 这里先把deploy_env传进去, 实现deploy功能, rollback稍后实现
[13:12:42 root@jenkins /data/scripts]#cp html_deploy_tag.sh html_deploy_tag_deploy.sh 
[13:12:55 root@jenkins /data/scripts]#vim html_deploy_tag_deploy.sh 

DATE=`date +%Y-%m-%d-%H-%M-%S`
web_server="10.0.0.81 10.0.0.82"
#代码打包路径
sdir="/opt"
#代码部署路径
ddir="/code"
#1. 进入到项目目录, 将内容进行打包
get_code(){
        cd ${WORKSPACE} && 
        tar czf ${sdir}/web-${DATE}-${git_version}.tar.gz ./*
}
#2. 将内容通过scp拷贝至web集群组
scp_web_server(){
for host in $web_server; do
    scp ${sdir}/web-${DATE}-${git_version}.tar.gz root@$host:${sdir}
    ssh root@$host "mkdir -p ${ddir}/web-${DATE}-${git_version} && 
                    tar xf ${sdir}/web-${DATE}-${git_version}.tar.gz -C ${ddir}/web-${DATE}-${git_version}
                    rm -rf ${ddir}/web && 
                    ln -s ${ddir}/web-${DATE}-${git_version} ${ddir}/web"
done
}
deploy(){
        get_code
        scp_web_server

}
rollback(){

        echo "rollback"

}

if [ ${deploy_env} == "deploy" ]; then
    deploy
elif [ ${deploy_env} == "rollback" ]; then 
    rollback 
fi
  1. 修改构建
6. Gitlab集成Jenkins-静态页面发布
图片.png
  1. 重新构建, 测试部署v1.3
  • 此时, 选择tag后, 还可以选择选项, deploy还是rollback
6. Gitlab集成Jenkins-静态页面发布
图片.png

当前版本:

6. Gitlab集成Jenkins-静态页面发布
图片.png

构建v1.3后:

6. Gitlab集成Jenkins-静态页面发布
图片.png
  • 可以看到, 拉取的tag是v1.3
6. Gitlab集成Jenkins-静态页面发布
图片.png
  1. 增加回退功能, 编写回退脚本
    1. 先把两台web服务器上, 重复的版本目录删除
[13:07:28 root@web1 ~]#ll /code
total 24
lrwxrwxrwx 1 root root   34 Dec 31 13:31 web -> /code/web-2020-12-31-13-31-36-v1.3
drwxr-xr-x 8 root root 4096 Dec 30 23:28 web-2020-12-30-23-28-26
drwxr-xr-x 8 root root 4096 Dec 30 23:59 web-2020-12-30-23-59-56
drwxr-xr-x 2 root root    6 Dec 31 00:21 web-2020-12-31-00-21-46
drwxr-xr-x 5 root root   80 Dec 31 00:23 web-2020-12-31-00-23-42
drwxr-xr-x 2 root root    6 Dec 31 00:24 web-2020-12-31-00-24-20
drwxr-xr-x 8 root root 4096 Dec 31 00:25 web-2020-12-31-00-25-47
drwxr-xr-x 8 root root 4096 Dec 31 12:59 web-2020-12-31-12-59-05-v1.3
drwxr-xr-x 8 root root 4096 Dec 31 13:04 web-2020-12-31-13-04-52-v1.2
drwxr-xr-x 8 root root 4096 Dec 31 13:31 web-2020-12-31-13-31-36-v1.3
[13:42:12 root@web1 ~]#rm -rf /code/web-2020-12-31-12-59-05-v1.3
[10:56:09 root@web2 ~]#ll /code
total 24
lrwxrwxrwx 1 root root   34 Dec 31 13:31 web -> /code/web-2020-12-31-13-31-36-v1.3
drwxr-xr-x 8 root root 4096 Dec 30 23:28 web-2020-12-30-23-28-26
drwxr-xr-x 8 root root 4096 Dec 30 23:59 web-2020-12-30-23-59-56
drwxr-xr-x 2 root root    6 Dec 31 00:21 web-2020-12-31-00-21-46
drwxr-xr-x 5 root root   80 Dec 31 00:23 web-2020-12-31-00-23-42
drwxr-xr-x 2 root root    6 Dec 31 00:24 web-2020-12-31-00-24-20
drwxr-xr-x 8 root root 4096 Dec 31 00:25 web-2020-12-31-00-25-47
drwxr-xr-x 8 root root 4096 Dec 31 12:59 web-2020-12-31-12-59-05-v1.3
drwxr-xr-x 8 root root 4096 Dec 31 13:04 web-2020-12-31-13-04-52-v1.2
drwxr-xr-x 8 root root 4096 Dec 31 13:31 web-2020-12-31-13-31-36-v1.3
[13:46:58 root@web2 ~]#rm -rf /code/web-2020-12-31-12-59-05-v1.3
    1. 修改脚本
DATE=`date +%Y-%m-%d-%H-%M-%S`
web_server="10.0.0.8110.0.0.82"
#代码打包路径
sdir="/opt"
#代码部署路径
ddir="/code"
#1. 进入到项目目录, 将内容进行打包
get_code(){
        cd ${WORKSPACE} && 
        tar czf ${sdir}/web-${DATE}-${git_version}.tar.gz ./*
}
#2. 将内容通过scp拷贝至web集群组
scp_web_server(){
for host in $web_server; do
    scp ${sdir}/web-${DATE}-${git_version}.tar.gz root@$host:${sdir}
    ssh root@$host "mkdir -p ${ddir}/web-${DATE}-${git_version} && 
                    tar xf ${sdir}/web-${DATE}-${git_version}.tar.gz -C ${ddir}/web-${DATE}-${git_version}
                    rm -rf ${ddir}/web && 
                    ln -s ${ddir}/web-${DATE}-${git_version} ${ddir}/web"
done
}
deploy(){
        get_code
        scp_web_server

}
rollback(){

rollback_file=`ssh root@10.0.0.81 "find /code/ -maxdepth 1 -type d -name "web-*-${git_version}""`   # 找到需要回退到的那个目录的目录名, 这样回退时就可以把当前的软连接删除, 重新连接到这个版本上, 这样就不会再重新生成一个目录了

for host in $web_server; do
    ssh root@$host "rm -rf ${ddir}/web && 
                    ln -s ${rollback_file} ${ddir}/web"  # 删除当前的软连接后, 重新创建软连接, 指向上面找到的要回退的那个版本, 这样回退就不用jenkins去拉代码, 然后重复部署到web服务器了.
done                                                                                                                                                                                


}

if [ ${deploy_env} == "deploy" ]; then
    deploy
elif [ ${deploy_env} == "rollback" ]; then 
    rollback 
fi
  1. 配置构建
6. Gitlab集成Jenkins-静态页面发布
图片.png
  1. 构建, 回退到1.2版本
6. Gitlab集成Jenkins-静态页面发布
图片.png
6. Gitlab集成Jenkins-静态页面发布
[13:50:28 root@web1 ~]#ll /code
total 20
lrwxrwxrwx 1 root root   34 Dec 31 14:01 web -> /code/web-2020-12-31-13-04-52-v1.2  # 重新把软连接指向v1.2版本, 而且并没有重新部署一次代码.
drwxr-xr-x 8 root root 4096 Dec 30 23:28 web-2020-12-30-23-28-26
drwxr-xr-x 8 root root 4096 Dec 30 23:59 web-2020-12-30-23-59-56
drwxr-xr-x 2 root root    6 Dec 31 00:21 web-2020-12-31-00-21-46
drwxr-xr-x 5 root root   80 Dec 31 00:23 web-2020-12-31-00-23-42
drwxr-xr-x 2 root root    6 Dec 31 00:24 web-2020-12-31-00-24-20
drwxr-xr-x 8 root root 4096 Dec 31 00:25 web-2020-12-31-00-25-47
drwxr-xr-x 8 root root 4096 Dec 31 13:04 web-2020-12-31-13-04-52-v1.2
drwxr-xr-x 8 root root 4096 Dec 31 13:31 web-2020-12-31-13-31-36-v1.3

注意:回退一定要是之前部署过的版本才能回退

  1. 重复构建
  • 相同的版本, 多次部署构建, 就是重复构建, 这时, 这个版本就会被拉取到web服务器多次, 这时通过find命令查找到了指定版本号的目录就是多个了, 需要再次取最后一行才能拿到想要的版本, 所以, 多次构建相同的版本时, 不能每次都部署代码到后端服务器

  • 对于重复构建, 只要在构建历史中把成功构建的记录删除, 就可以重复构建了, 因为GIT_PREVIOUS_SUCCESSFUL_COMMIT对比的就是本次构建的commit id是否在构建历史中存在

  1. Jenkins的环境变量
GIT_COMMIT
    The commit hash being checked out.

GIT_PREVIOUS_SUCCESSFUL_COMMIT  # 该变量会记录上一次成功提交的信息(commit ID). 如果是第一次提交, 这个变量的值就是个空值. 如果上一次提交成功, 那么这个previous变量就会记录上一次提交的信息(commit ID). 我们可以实现, 如果重复提交就会报错. 可以通过变量判断实现
    The hash of the commit last successfully built on this branch, if any.

if [ ${GIT_COMMIT} == ${GIT_PREVIOUS_SUCCESSFUL_COMMIT} ];
        说明项目已经部署过

举例:

假设第一次提交, commit id是123456, 这时两个变量值是不相等的, 如果不相等, 我们就执行部署. 如果成功, 那么123456就会存到previous变量

如果第二次又提交123456这个ID号, 那么这时两个变量的值就是相当的, 我们就认为这个commit已经部署过了, 就不在部署了

  1. 修改构建脚本, 静态页面最终版
vim html_deploy_tag_rollback.sh
DATE=`date +%Y-%m-%d-%H-%M-%S`
web_server="10.0.0.81 10.0.0.82"
#代码打包路径
sdir="/opt"
#代码部署路径
ddir="/code"
#1. 进入到项目目录, 将内容进行打包
get_code(){
        cd ${WORKSPACE} && 
        tar czf ${sdir}/web-${DATE}-${git_version}.tar.gz ./*
}
#2. 将内容通过scp拷贝至web集群组
scp_web_server(){
for host in $web_server; do
    scp ${sdir}/web-${DATE}-${git_version}.tar.gz root@$host:${sdir}
    ssh root@$host "mkdir -p ${ddir}/web-${DATE}-${git_version} && 
                    tar xf ${sdir}/web-${DATE}-${git_version}.tar.gz -C ${ddir}/web-${DATE}-${git_version}
                    rm -rf ${ddir}/web && 
                    ln -s ${ddir}/web-${DATE}-${git_version} ${ddir}/web"
done
}
deploy(){
        get_code
        scp_web_server

}


rollback(){

rollback_file=`ssh root@10.0.0.81 "find /code/ -maxdepth 1 -type d -name "web-*-${git_version}""`

for host in $web_server; do
    ssh root@$host "rm -rf ${ddir}/web && 
                    ln -s ${rollback_file} ${ddir}/web"
done


}

if [ ${deploy_env} == "deploy" ]; then
# 如果选择了deploy部署, 就要判断这次部署的commit id, 是否在历史成功记录中有记录, 如果有就提示已经部署过了. GIT_COMMIT是jenkins拉取某个版本的代码后, 返回其commit id, 而GIT_PREVIOUS_SUCCESSFUL_COMMIT返回的是, 当前要部署的这个代码的COMMIT ID在整个jenkins部署成功历史中有没有记录, 如果没有记录就会返回空, 那么说明这个版本没有部署过, 如果有记录, 就会返回这个commit id, 通过条件判断, 因为这时这个commit id和当前要部署的id是相等的, 就会提示已经部署过
    if [ ${GIT_COMMIT} == ${GIT_PREVIOUS_SUCCESSFUL_COMMIT} ]; then
        echo "已经部署过该版本, ${git_version}"
        exit 1
    else
        deploy
    fi
    
    
elif [ ${deploy_env} == "rollback" ]; then 
    rollback 
fi 
  1. 测试脚本, 部署此前部署过的版本
  • v1.3已经部署过了, 如果再次部署, 会按照构建脚本的定义不再部署, 直接退出
6. Gitlab集成Jenkins-静态页面发布
图片.png
6. Gitlab集成Jenkins-静态页面发布
图片.png
  1. 测试部署新的版本
  • 开发机修改index.html
[20:49:18 root@developer-2 ~/monitor]#vim index.html
 哈哈哈-v.1.4/a> 
[20:49:37 root@developer-2 ~/monitor]#git add .
[20:49:40 root@developer-2 ~/monitor]#git commit -m "v1.4"
[master a6f547f] v1.4
 1 file changed, 1 insertion(+), 1 deletion(-)
[20:49:45 root@developer-2 ~/monitor]#git push origin master
Enumerating objects: 5, done.
Counting objects: 100% (5/5), done.
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 304 bytes | 304.00 KiB/s, done.
Total 3 (delta 2), reused 0 (delta 0), pack-reused 0
To gitlab.abc.com:devops/monitor.git
   747844f..a6f547f  master -> master
[20:49:54 root@developer-2 ~/monitor]#git tag -a "v1.4" -m "v1.4"
[20:50:04 root@developer-2 ~/monitor]#git push origin v1.4
Enumerating objects: 1, done.
Counting objects: 100% (1/1), done.
Writing objects: 100% (1/1), 159 bytes | 159.00 KiB/s, done.
Total 1 (delta 0), reused 0 (delta 0), pack-reused 0
To gitlab.abc.com:devops/monitor.git
 * [new tag]         v1.4 -> v1.4
  • 此时v1.4版本是没有部署过的, 因此肯定部署会成功
6. Gitlab集成Jenkins-静态页面发布
图片.png
  • 如果再次部署v1.4就会提示已经部署过了
6. Gitlab集成Jenkins-静态页面发布
图片.png

推荐阅读
  • Centos7.6安装Gitlab教程及注意事项
    本文介绍了在Centos7.6系统下安装Gitlab的详细教程,并提供了一些注意事项。教程包括查看系统版本、安装必要的软件包、配置防火墙等步骤。同时,还强调了使用阿里云服务器时的特殊配置需求,以及建议至少4GB的可用RAM来运行GitLab。 ... [详细]
  • 如何实现织梦DedeCms全站伪静态
    本文介绍了如何通过修改织梦DedeCms源代码来实现全站伪静态,以提高管理和SEO效果。全站伪静态可以避免重复URL的问题,同时通过使用mod_rewrite伪静态模块和.htaccess正则表达式,可以更好地适应搜索引擎的需求。文章还提到了一些相关的技术和工具,如Ubuntu、qt编程、tomcat端口、爬虫、php request根目录等。 ... [详细]
  • 基于PgpoolII的PostgreSQL集群安装与配置教程
    本文介绍了基于PgpoolII的PostgreSQL集群的安装与配置教程。Pgpool-II是一个位于PostgreSQL服务器和PostgreSQL数据库客户端之间的中间件,提供了连接池、复制、负载均衡、缓存、看门狗、限制链接等功能,可以用于搭建高可用的PostgreSQL集群。文章详细介绍了通过yum安装Pgpool-II的步骤,并提供了相关的官方参考地址。 ... [详细]
  • 本文介绍了Java工具类库Hutool,该工具包封装了对文件、流、加密解密、转码、正则、线程、XML等JDK方法的封装,并提供了各种Util工具类。同时,还介绍了Hutool的组件,包括动态代理、布隆过滤、缓存、定时任务等功能。该工具包可以简化Java代码,提高开发效率。 ... [详细]
  • 本文介绍了在Windows环境下如何配置php+apache环境,包括下载php7和apache2.4、安装vc2015运行时环境、启动php7和apache2.4等步骤。希望对需要搭建php7环境的读者有一定的参考价值。摘要长度为169字。 ... [详细]
  • 本文介绍了在mac环境下使用nginx配置nodejs代理服务器的步骤,包括安装nginx、创建目录和文件、配置代理的域名和日志记录等。 ... [详细]
  • 本文介绍了在CentOS上安装Python2.7.2的详细步骤,包括下载、解压、编译和安装等操作。同时提供了一些注意事项,以及测试安装是否成功的方法。 ... [详细]
  • CEPH LIO iSCSI Gateway及其使用参考文档
    本文介绍了CEPH LIO iSCSI Gateway以及使用该网关的参考文档,包括Ceph Block Device、CEPH ISCSI GATEWAY、USING AN ISCSI GATEWAY等。同时提供了多个参考链接,详细介绍了CEPH LIO iSCSI Gateway的配置和使用方法。 ... [详细]
  • 本文介绍了使用CentOS7.0 U盘刻录工具进行安装的详细步骤,包括使用USBWriter工具刻录ISO文件到USB驱动器、格式化USB磁盘、设置启动顺序等。通过本文的指导,用户可以轻松地使用U盘安装CentOS7.0操作系统。 ... [详细]
  • Linux服务器密码过期策略、登录次数限制、私钥登录等配置方法
    本文介绍了在Linux服务器上进行密码过期策略、登录次数限制、私钥登录等配置的方法。通过修改配置文件中的参数,可以设置密码的有效期、最小间隔时间、最小长度,并在密码过期前进行提示。同时还介绍了如何进行公钥登录和修改默认账户用户名的操作。详细步骤和注意事项可参考本文内容。 ... [详细]
  • 本文介绍了在Python3中如何使用选择文件对话框的格式打开和保存图片的方法。通过使用tkinter库中的filedialog模块的asksaveasfilename和askopenfilename函数,可以方便地选择要打开或保存的图片文件,并进行相关操作。具体的代码示例和操作步骤也被提供。 ... [详细]
  • 本文介绍了数据库的存储结构及其重要性,强调了关系数据库范例中将逻辑存储与物理存储分开的必要性。通过逻辑结构和物理结构的分离,可以实现对物理存储的重新组织和数据库的迁移,而应用程序不会察觉到任何更改。文章还展示了Oracle数据库的逻辑结构和物理结构,并介绍了表空间的概念和作用。 ... [详细]
  • Ubuntu 9.04中安装谷歌Chromium浏览器及使用体验[图文]
    nsitionalENhttp:www.w3.orgTRxhtml1DTDxhtml1-transitional.dtd ... [详细]
  • 本文介绍了如何使用C#制作Java+Mysql+Tomcat环境安装程序,实现一键式安装。通过将JDK、Mysql、Tomcat三者制作成一个安装包,解决了客户在安装软件时的复杂配置和繁琐问题,便于管理软件版本和系统集成。具体步骤包括配置JDK环境变量和安装Mysql服务,其中使用了MySQL Server 5.5社区版和my.ini文件。安装方法为通过命令行将目录转到mysql的bin目录下,执行mysqld --install MySQL5命令。 ... [详细]
  • Windows 7 部署工具DISM学习(二)添加补丁的步骤详解
    本文详细介绍了在Windows 7系统中使用部署工具DISM添加补丁的步骤。首先需要将光驱中的安装文件复制到指定文件夹,并进行挂载。然后将需要的MSU补丁解压并集成到系统中。文章给出了具体的命令和操作步骤,帮助读者完成补丁的添加过程。 ... [详细]
author-avatar
手浪用户2502939427_143
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有