pipeline结合ansible剧本进行批量的部署与回滚配置
文章发布较早,内容可能过时,阅读注意甄别。
之前还在头疼批量部署与回滚的事情,最近各方面接触 ansible 开始多起来,于是将 ansible 接入到了部署流程中,从而将批量部署与回滚变得简化起来。
先看一下 ansible 的剧本构造:
[root@ops-eryajf-test-1 deploystatic]$tree
.
├── hosts
├── README.md
├── roles
│ ├── deploy
│ │ ├── files
│ │ │ └── keepfive.sh
│ │ └── tasks
│ │ └── main.yml
│ └── rollback
│ └── tasks
│ └── main.yml
└── site.yml
6 directories, 7 files
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
其中 hosts 文件不固定,由项目构建中灵活定义。
然后逐个查看内容:
$cat site.yml
---
- hosts: "remote"
name: "项目部署脚本"
remote_user: "root"
roles:
- deploy
- rollback
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
然后看两个剧本的具体内容:
$ cat roles/deploy/files/keepfive.sh
while true;do
A=`ls . | wc -l`
B=`ls -lrX . | tail -n 1 | awk '{print $9}'`
if [ $A -gt 5 ];then rm -rf ./$B;else break;fi;done
1
2
3
4
5
2
3
4
5
这个脚本定义了令远程版本库保留 5 个构建历史的操作。
$ cat roles/deploy/tasks/main.yml
---
- name: "创建远程主机上的版本目录"
file: path=/release/{{project}}/{{_version}} state=directory
tags: deploy
- name: "将代码同步到远程主机版本目录"
synchronize:
src: /{{WORKSPACE}}/
dest: /release/{{project}}/{{_version}}/
delete: yes
rsync_opts: --exclude-from=/{{WORKSPACE}}/excludefile
tags: deploy
- name: "将项目部署到生产目录"
file: path=/data/www/{{project}} state=link src=/release/{{project}}/{{_version}}
tags: deploy
- name: "使版本目录保持五个版本历史"
script: chdir=/release/{{project}} keepfive.sh
tags: deploy
- name: "生成远程版本号"
shell: "ls /release/{{project}} > /release/{{project}}.log"
tags: deploy
- name: "同步版本号到本地"
synchronize: "src=/release/{{project}}.log dest=/root/.jenkins/version/{{project}}.log mode=pull"
tags: deploy
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
定义了主要的部署流程
$ cat roles/rollback/tasks/main.yml
---
- name: "将项目回滚到对应期望的构建"
file: path=/data/www/{{project}} state=link src={{Version}}
tags: rollback
1
2
3
4
5
2
3
4
5
定义了回滚的流程。
看起来就这么多,也并不算复杂,只要里边的变量,以及参数定义好即可。现在将整个剧本放在 Jenkins 主机的 /root/.jenkins/ansible/deploystatic
目录下,以便如下脚本调用。
接下来就是核心的 Jenkinsfile 的定义了,目前初步定义为如下样子:
def createVersion() {
return new Date().format('yyyyMMddHHmmss') + "_${env.BUILD_ID}"
}
pipeline {
agent any
environment {
_version = createVersion()
// 需要修改此处,定义项目名称
project="admin-ansible"
// 定义项目git地址
git_url = "git@10.3.0.42:jenkins-learn/breeze-college.git"
remote_port="22"
remote_user="root"
// 定义项目的webroot目录
project_dir="/data/www/${project}"
//定义项目的版本目录,一般不用更改
version_dir="/release/$project/${_version}"
}
options {
timestamps()
disableConcurrentBuilds()
timeout(time: 10, unit: 'MINUTES')
buildDiscarder(logRotator(numToKeepStr: '10'))
}
triggers{
gitlab( triggerOnPush: true,
triggerOnMergeRequest: true,
branchFilterType: 'All',
secretToken: "${env.git_token}")
}
parameters {
string(name: 'branch', defaultValue: 'master', description: '请输入将要构建的代码分支')
choice(name: 'mode', choices: ['deploy','rollback'], description: '请选择发布或者回滚?')
string(name: 'version_id', defaultValue: '0', description: '回滚时用,默认回滚到上一次构建,如需要回滚到更早构建,请输入对应构建ID,只支持最近五次构建的回滚,部署请忽略此参数')
choice(name: 'remote_ip', choices: ['all','10.3.9.32','10.3.20.4'], description: '选择要发布的主机')
}
stages {
stage('拉取代码') {
steps {
echo 'Checkout'
script {
try {
git branch: "${branch}",url: "${git_url}"
}catch(err) {
echo "${err}"
}
}
}
}
stage('定义部署主机列表'){
steps{
script{
try{
sh '''
if [ $remote_ip == "all" ];then
cat > /root/.jenkins/ansible/deploystatic/hosts << EOF
[remote]
10.3.9.32 ansible_port=34222
10.3.20.4 ansible_port=34222
EOF
else
cat > /root/.jenkins/ansible/deploystatic/hosts << EOF
[remote]
$remote_ip ansible_port=34222
EOF
fi
'''
}catch(err) {
echo "${err}"
}
}
}
}
stage('定义忽略文件'){
steps{
script{
try {
sh '''
cat > excludefile << EOF
Jenkinsfile
excludefile
EOF
'''
}catch(err) {
echo "${err}"
}
}
}
}
stage('部署') {
when {
environment name: 'mode',value: 'deploy'
}
steps {
dir("/root/.jenkins/ansible/deploystatic"){
script {
try {
sh '''
ansible-playbook -i ./hosts --tags "deploy" site.yml -e "project"=$project -e "WORKSPACE"=$WORKSPACE -e "_version"=${_version}
'''
} catch(err) {
echo "${err}"
}
}
}
}
}
stage('回滚') {
when {
environment name: 'mode',value: 'rollback'
}
steps {
dir("/root/.jenkins/ansible/deploystatic"){
script {
try{
if (params.version_id == '0'){
sh '''
echo "选择回滚的版本是默认,将回滚到上次制品,回滚即将进行..."
Version="/release/$project/`tail -n2 /root/.jenkins/version/${project}.log | head -n1`"
ansible-playbook -i ./hosts --tags "rollback" site.yml -e "project"=${project} -e "Version"=${Version}
echo "=============="
echo "项目已回滚完成!"
echo "=============="
'''
} else{
sh '''
echo "选择回滚的版本是:${version_id},将回滚到 ${version_id} 的制品,回滚即将进行..."
Version="/release/$project/`grep "_$version_id" /root/.jenkins/version/${project}.log`"
ansible-playbook -i ./hosts --tags "rollback" site.yml -e "project"=${project} -e "Version"=${Version}
echo "项目回滚到 ${version_id} 完成!"
'''
}
} catch(err) {
echo "${err}"
}
}
}
}
}
}
post {
success {
dingTalk accessToken:'https://oapi.dingtalk.com/robot/send?access_token=改成自己的',
imageUrl:'https://ae01.alicdn.com/kf/Hdfe28d2621434a1eb821ac6327b768e79.png',
jenkinsUrl: "${env.JENKINS_URL}",
message:'构建成功 ✅',
notifyPeople:'李启龙'
}
failure {
dingTalk accessToken:'https://oapi.dingtalk.com/robot/send?access_token=改成自己的',
imageUrl:'https://ae01.alicdn.com/kf/Hdfe28d2621434a1eb821ac6327b768e79.png',
jenkinsUrl: "${env.JENKINS_URL}",
message:'构建失败 ❌',
notifyPeople:'李启龙'
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
核心脚本也不算复杂,只需要在新配置项目的时候调整一些参数即可投入使用。
上次更新: 2024/11/19, 23:11:42