1. 背景介绍
目前工作中,虽然作为一名开发,但是平时也较多地负责产品在各个环境的部署与更新,随着时间的推移与迭代的频率增加,一套自动化集成部署流程的应用势在必行。不仅节约时间,也避免在大量繁琐操作中的人为错误,同时也为了方便管理数量比较多的模块。
目前产品主要用到的语言主要有java、c,由于web端做了前后端分离,前端的工程化也已经成型,js(主要用到vue)也算上吧。
经过一段时间的了解与实践,最终决定集成jenkins与gitlab实现自动部署。
本文安装方式均采用yum方式进行。
2. gitlab安装
2.1. 安装依赖
sudo yum install curl openssh-server openssh-clients postfix cronie -y
2.2. 安装gitlab
curl -sS http://packages.gitlab.cc/install/gitlab-ce/script.rpm.sh | sudo bash
sudo yum install gitlab-ce
2.3. 启动gitlab
sudo gitlab-ctl reconfigure
gitlab运行相关进程如下:
[root@gitlab ~]# gitlab-ctl status
run: gitaly: (pid 690) 1031s; run: log: (pid 689) 1031s
run: gitlab-monitor: (pid 686) 1031s; run: log: (pid 684) 1031s
run: gitlab-workhorse: (pid 683) 1031s; run: log: (pid 681) 1031s
run: logrotate: (pid 688) 1031s; run: log: (pid 687) 1031s
run: nginx: (pid 685) 1031s; run: log: (pid 682) 1031s
run: node-exporter: (pid 674) 1031s; run: log: (pid 673) 1031s
run: postgres-exporter: (pid 691) 1031s; run: log: (pid 680) 1031s
run: postgresql: (pid 669) 1031s; run: log: (pid 667) 1031s
run: prometheus: (pid 679) 1031s; run: log: (pid 677) 1031s
run: redis: (pid 666) 1031s; run: log: (pid 665) 1031s
run: redis-exporter: (pid 671) 1031s; run: log: (pid 670) 1031s
run: sidekiq: (pid 678) 1031s; run: log: (pid 668) 1031s
run: unicorn: (pid 676) 1031s; run: log: (pid 675) 1031s
2.4. 相关配置
gitlab的配置详见/etc/gitlab/gitlab.rb,配置修改之后需执行gitlab-ctl reconfigure使配置生效。
gitlab的日志存放路径在/var/log/gitlab/下。
gitlab-ctl tail #查看所有日志
gitlab-ctl tail nginx/gitlab_access.log #查看nginx访问日志
3. jenkins安装
3.1. 介绍
Jenkins是一个功能强大的应用程序,允许持续集成和持续交付项目,无论用的是什么平台。这是一个免费的源代码,可以处理任何类型的构建或持续集成。集成Jenkins可以用于一些测试和部署技术。
3.2. 安装
注意,jenkins需要jdk支持。
yum install -y java-1.8.0-openjdk.x86_64
安装jenkins
cd /etc/yum.repos.d/
wget http://pkg.jenkins.io/redhat/jenkins.repo
rpm --import http://pkg.jenkins.io/redhat/jenkins.io.key
yum install -y jenkins
systemctl start jenkins
注意:由于本文的gitlab和jenkins安装在一台机器上,jenkins的默认端口被gitlab占用了,因此将jenkins端口改为了7070。可在/etc/sysconfig/jenkins中进行配置。
新版本的jenkins启动时需要输入一个密钥,可以在第一次启动日志里面看到,也可以通过/var/lib/jenkins/secrets/initialAdminPassword进行查看。将密钥输入到解锁页面的输入框即可。
接下来的插件安装选择推荐的即可。
至此,jenkins安装完成。
4. jenkins配置
先在jenkins上建立一个项目,选择”构建一个自由风格的软件项目”
在源码管理处选择Git,并填写相关信息。本文采用http的方式进行代码仓库的配置(也可以配置ssh方式,具体方式请自行google,额。。)
在构建触发器步骤选择”Build when a change is pushed to GitLab…”,表示在push代码到gitlab时触发构建。注意URL后面的地址等会儿在配置gitlab的webhook时用到。
在构建步骤选择执行shell,便可在触发事件执行时执行指定的shell脚本进行构建。
构建最核心的部分便在shell部分,这也是jenkins能在很多项目的构建中运用。因为之前的步骤全是一些通用的配置,针对不同的项目编写不同的部署脚本便可完成项目的自动构建于部署。本文采用的是vue项目做测试,在安装了nodejs的基础上,脚本内容如下(测试版本,细节请忽略-关键是shell脚本写的渣…)
注意: 在jenkins构建执行shell脚本时:单脚本时,若脚本中有exit 1(非0时)则整个构建失败,结果显示为红色;多脚本时,若其中任意一个脚本返回exist 1,则结果为警告,显示为黄色。
在/nick/ci/hxjpro/下准备了两个脚本:
[root@gitlab ~]# cd /nick/ci/hxjpro/
[root@gitlab hxjpro]# ls
deploy.sh scp.exp
其中deploy用于编译vue工程并打包(例子中没有以压缩包的方式进行传输,因为那样的话还需要远程执行命令,在实际使用中可以打包项目进行传输,然后执行远程命令。具体远程执行命令方式可参考linux expect使用),scp用于将文件传输到远程服务器。
deploy.sh内容
echo "start deploying ..."
echo "------------------------------"
echo "executing 'cnpm install'..."
cnpm install
echo "'cnpm install done!'"
echo "------------------------------"
echo "executing 'npm run build'..."
npm run build
echo "'npm run build' done!"
echo "------------------------------"
echo "packaging dist"
tar -zcvf dist.tar.gz ./dist
echo "package done!"
echo "------------------------------"
echo "sending dist to remote server : 192.168.0.106"
./scp.exp ./dist root@192.168.0.106:/nick/proj/hxjpro/
echo "send file to remote server done!"
echo "------------------------------"
echo "deploy finished!"
scp.exp脚本内容
#!/usr/bin/expect
set timeout 20
if { [llength $argv] < 2} {
puts "Usage:"
puts "$argv0 local_file remote_path"
exit 1
}
set local_file [lindex $argv 0]
set remote_path [lindex $argv 1]
set passwd nick123
set passwderror 0
spawn scp -r $local_file $remote_path
expect {
"*assword:*" {
if { $passwderror == 1 } {
puts "passwd is error"
exit 2
}
set timeout 1000
set passwderror 1
send "$passwd\r"
exp_continue
}
"*es/no)?*" {
send "yes\r"
exp_continue
}
timeout {
puts "connect is timeout"
exit 3
}
}
以上便是jenkins的配置内容,关键是脚本的编写。
在真实项目中,项目的构建脚本一般比较复杂。比如java可以采用maven进行编译构建打包,或者ant进行构建打包。C可以采用对应的方式进行构建打包。而这些步骤均可整理成脚本,按以上方式进行配置即可。
5. gitlab与jenkins集成
5.1. 准备
为了方便,本文以一个前端(基于vue)工程为例子进行自动化构建部署实验。
gitlab与jenkins集成的原理主要通过gitlab的webhook实现,通过在gitlab上配置相关事件便可触发。
5.2. gitlab配置
将工程提交到gitlab(可参考gitlab新建项目下的指导步骤)。然后在gitlab上进入工程详情页面,点击左边的Setting -> Integrations,将jenkins构建触发器配置的URL内容填写到URL输入框然后保存。
填完之后,点击”Test -> Push events”测试一下webhook地址,若返回200则表示配置成功!!!
特别注意:我在配置此步骤时花费了很多时间,因为gitlab和jenkins安装在同一台机器上,且gitlab版本较新,所以在测试url地址时老是报错,然后跟踪gitlab日志,发现
WARN: URI::InvalidURIError: URI::InvalidURIError
...
最开始以为是配置问题,经过几遍的重复配置,发现没效果。然后经过不断google(吐血了…),终于发现这篇文章:Webhook does not work for me when i update to date!,大概意思就是说新版的gitlab在http模块部分有一个”允许本地请求”的判定,该配置默认是关闭的,需要通过配置打开。首先,用root账号登录gitlab,点击首页的”Configure GitLab”
找到左侧菜单底部的”Settings”,找到”Outbound requests”,勾选保存,OK!
(再次吐血…)
这时候,在回去点击webhook配置的”Test -> Push events”,如果提示403,可在jenkins的”系统管理->全局安全配置”,将”启用安全”配置去掉即可(内网暂时不考虑安全性问题,若有需求可自行google哈)。
配置完成之后,点击test应该返回200,此时去到jenkins的工程的构建列表,应该可以看到一个正在构建的任务,该任务正好就是test触发的。至此,gitlab配置ok了!!!
6. 综合测试
在本地的git项目提交代码并push到gitlab远程仓库,便可看到jenkins触发了构建任务进行自动构建,等构建完成,访问目标服务器的地址,便可看到最新的代码已经被自动部署到远程服务器,而我们需要做的仅需要commit和push代码。
最后贴一个jenkins的完整构建日志(有点长):
Started by GitLab push by nick
构建中 在工作空间 /var/lib/jenkins/workspace/hxjpro 中
[WS-CLEANUP] Deleting project workspace...
[WS-CLEANUP] Done
Cloning the remote Git repository
Cloning repository http://gitlab.example.com/nick/hxjpro.git
> git init /var/lib/jenkins/workspace/hxjpro # timeout=10
Fetching upstream changes from http://gitlab.example.com/nick/hxjpro.git
> git --version # timeout=10
> git fetch --tags --progress http://gitlab.example.com/nick/hxjpro.git +refs/heads/*:refs/remotes/origin/*
> git config remote.origin.url http://gitlab.example.com/nick/hxjpro.git # timeout=10
> git config --add remote.origin.fetch +refs/heads/*:refs/remotes/origin/* # timeout=10
> git config remote.origin.url http://gitlab.example.com/nick/hxjpro.git # timeout=10
Fetching upstream changes from http://gitlab.example.com/nick/hxjpro.git
> git fetch --tags --progress http://gitlab.example.com/nick/hxjpro.git +refs/heads/*:refs/remotes/origin/*
skipping resolution of commit remotes/origin/master, since it originates from another repository
> git rev-parse refs/remotes/origin/master^{commit} # timeout=10
> git rev-parse refs/remotes/origin/origin/master^{commit} # timeout=10
Checking out Revision 795f5f5d9868bea52800540f1786a07af5c6bab6