前面利用gitlab钩子触发push 动作,通知jenkins 分配salve节点执行 构建java项目,利用ansible-playbook批量部署网站。
在执行playbook的部署的时候,有备份的操作。
就是切到tomcat webapps目录下,备份ROOT.war项目文件到备份目录。
回滚策略
当我们的项目出现问题,紧急情况下我们要恢复到上一生产版本,这时候需要回滚项目
思路:
因是用jenkins_salve上的ansible执行yml文件去部署的。所以在备份的文件都是备份到了web服务器的本地备份目录下,恢复的时候在重新覆盖现有的ROOT.war 重启tomcat即可。
主要要将web服务器备份目录下的文件,按规范命名,输出到一个txt文件列表中。发送到jenkins服务器上,
目的就是让jenkins可以识别到一份回滚目录清单来提供 回滚job的参数化选项。 这样就可以通过参数化的变量
来 恢复。
项目发布脚本
先修改下之前java发布的流水线job 脚本中的playbook.yml的内容
在发布构建的时候级应该处理好回滚目录列表出来 发到jenkins上,让其识别内容
cat >/opt/jenkins_home/.playbook.yml << EOF
- hosts: $host_group
vars:
workspace: $WORKSPACE
build_number: $BUILD_NUMBER
tomcat_dir: /usr/local/tomcat
backup_dir: "/data/backup"
backup_filename: "pipe-ROOT-\$(date +%F)-{{ build_number }}.war"
tasks:
- name: scp war package
copy: src="{{item}}" dest=/tmp/ROOT.war
with_fileglob:
- "{{ workspace }}/target/*.war"
- name: Backup java file
tags: bk
shell: cd {{ tomcat_dir }}/webapps && mv ROOT.war {{ backup_dir }}/{{ backup_filename }} &&
ls {{ backup_dir }}|sort -t "-" -k6 -nr|head -n 3| awk 'BEGIN{ printf \"abc=\"}{printf \\\$1 \",\"}'>/tmp/backup_version.txt &&
cp -f /tmp/backup_version.txt /opt/jenkins_home/data_back/
#生成回滚清单文件,并复制到jenkins服务器目录下
- name: Bushu war and resstart tomcat service
tags: bushu
shell:
mv /tmp/ROOT.war {{ tomcat_dir }}/webapps/ROOT.war &&
cd {{ tomcat_dir }} &&
/bin/sh -x restart.sh| cat
EOF
变化的部分:
变量部分新增
build_number: $BUILD_NUMBER
backup_filename: "pipe-ROOT-\$(date +%F)-{{ build_number }}.war"
部署部分新增
ls {{ backup_dir }}|sort -t "-" -k6 -nr|head -n 3| awk 'BEGIN{ printf \"abc=\"}{printf \\\$1 \",\"}'>/tmp/backup_version.txt &&
cp -f /tmp/backup_version.txt /opt/jenkins_home/data_back/
说明:
$BUILD_NUMBER :jenkisn内置变量,构建编号
backup_filename: 规范化备份文件名称。(job名-项目名-日期-构建编号.war)
下面命令查看备份目录下下的文件生成到一个txt文件。
ls {{ backup_dir }}|sort -t "-" -k6 -nr|head -n 3| awk 'BEGIN{ printf \"abc=\"}{printf \\\$1 \",\"}'>/tmp/backup_version.txt
因为在jenkins流水线界面直接用shell的$ 会被jenkins认为是引用jenkins变量所以出现双引号和$,就要转义 \\,经过测试$前面要3个斜杠才能正常转义成功
(sort -t 指定分隔符 -k 按第几列排序, -r 降序排序,不写默认升序)
(awk BEGIN 指在print之前要做什么,printf格式化输出)
输出的文件列表要赋予一个变量 如 abc 。因为Jenkins后面要读取这个文件,填入这个key值会用到。
- 将文件发送到jenkins服务器
cp -f /tmp/backup_version.txt /opt/jenkins_home/data_back/
我这里用的是直接cp过去的,试验中我的jenkins也是web服务器。所以在同一台中,并且jenkins是docker安装的,所以直接拷贝到了启动jenkins镜像时持久化出来的目录,/opt/jenkins_home中(对应容器中/var/jenkins_home)
如果不在一个服务器的,可用scp命令。提前做免密或者利用jenkins凭据的方式,将凭据保存在变量中,用sshpass -p "$password" scp xxxxxx 。
最终完整java发布网站流水线:
pipeline {
agent {
label '112'
}
parameters {
gitParameter branch: '', branchFilter: '.*', defaultValue: 'origin/dev', description: '你选择的分支?', name: 'branch', quickFilterEnabled: false, selectedValue: 'NONE', sortMode: 'NONE', tagFilter: '*', type: 'PT_BRANCH'
choice choices: ['java', 'java2', 'java3'], description: '选择发布的主机组', name: 'host_group'
}
stages {
stage('拉取git代码') {
steps {
checkout([$class: 'GitSCM', branches: [[name: '$branch']], doGenerateSubmoduleConfigurations: false, extensions: [], submoduleCfg: [], userRemoteConfigs: [[credentialsId: 'd386c248-cf59-45c5-9731-b8f2d42411e9', url: 'http://192.168.1.112:85/webservice/java_web.git']]])
}
}
stage('编译构建') {
steps {
sh label: '', script: 'mvn clean package -Dmaven.test.skip=true'
}
}
stage('项目测试') {
steps {
echo 'Java Web Project Test is Suessful '
}
}
stage('拷贝构建文件到远程主机') {
steps {
withCredentials([usernamePassword(credentialsId: 'dee60f63-fcf8-405b-a199-55b53ea2b9f6', passwordVariable: 'password', usernameVariable: 'username')]) {
// some block //lianjie链接jenkins服务器 凭据
sh """
#######################################主机清单文件##############################################
cat >/opt/jenkins_home/.hosts <<EOF
[java]
192.168.1.252
[java2]
192.168.1.252
[java3]
192.168.1.252
EOF
######################################Playbook文件################################################
cat >/opt/jenkins_home/.playbook.yml << EOF
- hosts: $host_group
vars:
workspace: $WORKSPACE
build_number: $BUILD_NUMBER
tomcat_dir: /usr/local/tomcat
backup_dir: "/data/backup"
backup_filename: "pipe-ROOT-\$(date +%F)-{{ build_number }}.war"
tasks:
- name: scp war package
copy: src="{{item}}" dest=/tmp/ROOT.war
with_fileglob:
- "{{ workspace }}/target/*.war"
- name: Backup java file
tags: bk
shell: cd {{ tomcat_dir }}/webapps && mv ROOT.war {{ backup_dir }}/{{ backup_filename }} &&
ls {{ backup_dir }}|sort -t "-" -k6 -nr|head -n 3| awk 'BEGIN{ printf \"abc=\"}{printf \\\$1 \",\"}'>/tmp/backup_version.txt &&
cp -f /tmp/backup_version.txt /opt/jenkins_home/data_back/
#生成回滚清单文件,并复制到jenkins服务器目录下
- name: Bushu war and resstart tomcat service
tags: bushu
shell:
mv /tmp/ROOT.war {{ tomcat_dir }}/webapps/ROOT.war &&
cd {{ tomcat_dir }} &&
/bin/sh -x restart.sh| cat
EOF
"""
}
ansiblePlaybook inventory: '/opt/jenkins_home/.hosts', playbook: '/opt/jenkins_home/.playbook.yml'
}
}
}
}
回滚
新建一个流水线项目
回滚job代码:
pipeline {
agent {
label '112'
}
parameters {
extendedChoice description: '选择回滚版本', multiSelectDelimiter: ',', name: 'select_version', propertyFile: '/var/jenkins_home/data_back/backup_version.txt', propertyKey: 'abc', quoteValue: false, saveJSONParameterToFile: false, type: 'PT_SINGLE_SELECT', visibleItemCount: 5
choice choices: ['java', 'java2', 'java3'], description: '选择发布的主机组', name: 'host_group'
}
stages {
stage('正在回滚到上一版本') {
steps {
sh """
#######################################主机清单文件##############################################
cat >/opt/jenkins_home/.hosts <<EOF
[java]
192.168.1.252
[java2]
192.168.1.252
[java3]
192.168.1.252
EOF
######################################Playbook文件################################################
cat >/opt/jenkins_home/.playbook.yml << EOF
- hosts: $host_group
vars:
workspace: $WORKSPACE
build_number: $BUILD_NUMBER
tomcat_dir: /usr/local/tomcat
backup_dir: "/data/backup"
backup_filename: $select_version
tasks:
- name: HUIFU JAVA WEB...
tags: hf
shell:
cd {{ tomcat_dir }}/webapps && mv ROOT.war /tmp/ROOT-BUG-{{ build_number }} &&
mv {{ backup_dir }}/{{ backup_filename }} ROOT.war &&
cd {{ tomcat_dir }} &&
/bin/sh -x restart.sh| cat
EOF
"""
ansiblePlaybook inventory: '/opt/jenkins_home/.hosts', playbook: '/opt/jenkins_home/.playbook.yml'
}
}
}
}
看到只是在发布脚本上删减一下,修改下参数化构建。
测试: