如何用jenkins快速部署小型服务
开始前需要确定的事
1. 总共有几个组件
2. 每个组件有几台机器,机器间连接关系是怎样的
3. 组件之间关系是怎样的,也即,哪个先启动,哪个后启动
安装jenkins
本来是想jenkins和ansible一起用,但是由于权限的限制,无法安装ansible,故只用了jenkins。
mac下安装参考这个,https://zhuanlan.zhihu.com/p/33727806
由于权限的限制,我不能apt-get,故下载二进制包,进行安装。有权限的直接使用命令安装。
解压命令
dpkg -x jenkins_2.190_all.deb /xxx/jenkins_file
安装好以后,使用systemd启动
service文本参考
[Unit] Description=jenkins_service After=network.target After=network-online.target Wants=network-online.target [Service] Restart=always RestartSec=10s ExecStart=/bin/bash -c "/xxx/bin//java -jar /xxx/jenkin_file/usr/share/jenkins/jenkins.war --httpPort=8080" [Install] WantedBy=multi-user.target
服务启动以后,通过ip:8080访问,比如192.168.0.1:8080
进入密码设置,密码设置,插件安装和新建任务参考https://zhuanlan.zhihu.com/p/33727806,创建用户。
创建job
在本次部署中,总的两个repo,一个开源组件etcd。
repo1包含三个组件:api abc def
repo2包含三个组件:ghi jkl mno
build job: 编译任务。release job: 发布任务。
etcd需要build job两个,release job一个。
repo1, repo2分别需要build job两个,release job三个。
每一个repo,需要两个build job,一个build最新版本,一个build任意版本。
每一个组件,需要一个release job。
此外,总的系统发布,需要release job。
jenkins中,每个job都有一个workspace,设置了git url和branch以后,就会下载到这个目录,(可以设置下载地址,但是就成全局了的,不方便)但是这个目录不方便编译。所以一个build job通常包括四步,第一步从git上下载,第二步拷贝到指定的目录,第三步编译,第四部拷贝到指定的back_up目录(以方便回滚)。
这四步,第一步在源码管理完成,后面的三步在构建添加shell脚本完成。
为了版本管理,在构建环境中如下设置
BUILD_VERSION :创建了个环境变量,叫BUILD_VERSION,为下文的shell脚本使用
${GIT_COMMIT}_${BUILD_DATE_FORMATTED, "yyyyMMdd"} :这个BUILD_VERSION的格式是commit_id_20190827这样的形式。你可以自己的喜好更改。
build demo
#!/bin/bash BUILD_ID=dontKillMe #变量的设置 root=/home/xxx/xxx/go build_path=/home/xxx/repo1/ project_path=/home/xxx/project/repo1/ go=/home/xxx/go work_dir=/home/xxx/.jenkins/workspace/repo1/ chmod -R 770 ${root} ${project_path} ${work_dir} #进入这个job的workspace cd ${work_dir} #将git下来的文件拷贝到工作目录 cp -r $work_dir $build_path #调到编译目录,设置环境变量 cd $build_path && cd cmd export GOROOT=$root export GOPATH=$project_path #编译api api_name=api_${BUILD_VERSION} cd api/ && $go build -o $api_name && cd .. #编译另外的两个组件 #拷贝到备份目录,为传输做准备 cmd_dir=${build_path}/cmd cp ${cmd_dir}/api/$api_name ${project_path}/api_backup/ #将这个版本号记录下来 #判断这个文件是否存在 cd ${project_path} if [ ! -f "version.txt" ]; then echo -e "${BUILD_VERSION}\n" >> ${project_path}/version.txt else #判断文档中是否含有这个字符串 str_version=`cat version.txt` result=$(echo $str_version | grep "${BUILD_VERSION}") echo $result if [[ "$result" != "" ]]; then echo "包含" else echo "不包含" echo -e "${BUILD_VERSION}\n" >> ${project_path}/version.txt fi fi
经过上面的job,二进制文件以及拷贝至back_up目录
发布有两种方式,一个是发布最新版本,一个是发布任意版本(涵盖了回滚)。
release demo
#!/bin/bash BUILD_ID=dontKillMe #变量的设置 #版本号更改就是这里,改version version=commit_id dest_dir=/home/xxx/api/bin stop_cmd="systemctl --user stop api.service" start_cmd="systemctl --user start api.service" project_path=/home/xxx/repo1/ #如果是灰度,将ip里的ip改为需要上线的ip即可 ip="192.168.0.1 192.168.0.2" #寻找此版本的文件名 cd ${project_path}/api_backup/ file_name=`ls -l *${version}* |awk '{print $9}'` echo ${file_name} #进行传输 for i in $ip ;do { scp ${file_name} tiger@${i}:${dest_dir} } done cp_cmd="cp ${dest_dir}/${file_name} ${dest_dir}/api" rm_cmd="rm ${dest_dir}/${file_name}" cmd="${stop_cmd} && ${cp_cmd} && ${start_cmd} && ${rm_cmd}" #登录到被控机器指定目录 操作进程重启 #这里有个需要注意的地方,scp的时候,不要后台运行(并发),容易造成还没scp完就进行下面的操作 #正确的步骤是,顺序scp,并发cp for i in $ip ;do { ssh tiger@${i} "${cmd}" }& done
其他
发布最近版本的脚本和任意脚本的相差不大,区别在于去备份目录下寻找最近更新的文件。
project_path=/home/xxx/repo1/ #找到最近更新的一个文件 file_name=`find ${project_path}/api/ -type f -printf '%T@ %p\n' | sort -n | tail -1 | cut -f2- -d" "` short_name=${file_name##*/}
所有的组件都可以任意发布以后,按照服务启动的顺序,将任务one by one启动,就是部署大礼包了,也就是最后一个job,这个job是安装最新版。当然也可以任意组合。
容易忽略的
配置文件的更改,都符合规划吗
里面涉及的data,log目录,都建立好了吗
写脚本的时候,#!/bin/bash加了吗
BUILD_ID=dontKillMe记得加上,这句的意思是,我的脚本退出以后,启动的任务不要自己死掉,在我这次任务中不太重要,但是如果你是别的任务,这就很容易变成坑了。
最最重要的,权限,很多时候运行失败,就是权限的问题
chmod -R 770 dir
#笔记#