使用jenkinsfile进行多分支自动化构建

自动化构建示意图

配置步骤

1、 新建任务

2、配置git仓库地址



3、jenkinsfile 示例文件

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
pipeline {
options {
# jenkins自身的配置项 构建的保留数量和天数
buildDiscarder(logRotator(numToKeepStr: '7', artifactNumToKeepStr: '10', daysToKeepStr: '5'))
}
# 构建节点
agent { label 'node_one' }
# jenkins构建前手动填写的参数
parameters {
booleanParam(name: 'SPEED_MODE', defaultValue: false, description: '极速模式下,将跳过构建、测试和静态扫描直接发布。')
}
# 环境变量
environment {
APPLICATION_NAME = 'ai_callcenter'
APPLICATION_DOCKER_TAG_NAME = 'ai_callcenter'
APPLICATION_DISPLAY_NAME = '智能呼叫中心'
APPLICATION_DEVELOPMENT_PORT = '18084'
APPLICATION_TESTING_PORT = '18084'
DOCKER_REGISTER = '192.168.20.192/we_eat_bugs'
}
# 构建阶段
stages {
stage('环境准备') {
# 构建步骤
steps {
# 更换执行目录
dir('devops') {
git url: 'git@10.100.5.99:yinghuo/yxx/devops.git', poll: false
}
# 不同分支对应的变量设置
script {
if (!env.BRANCH_NAME.startsWith('feature-') && env.BRANCH_NAME != 'master' && !env.BRANCH_NAME.startsWith('release-')) {
error("非法的分支名:$env.BRANCH_NAME. 自定义的分支应以 feature- 开头。")
}
env.PROJECT_VERSION = sh(
script: "cat build.gradle | grep '^version = ' |awk -F = '{gsub(\"\\047\", \"\", \$2); print \$2 }'",
returnStdout: true
).trim()
assert env.PROJECT_VERSION != ''
env.VERSION = "${env.PROJECT_VERSION.toLowerCase()}.${BUILD_ID}"
if (env.BRANCH_NAME.startsWith('feature') || env.BRANCH_NAME == "master") {
env.ENV_NAME = "development"
env.SPRING_PROFILES_ACTIVE = "development,swagger"
env.PORT = "${env.APPLICATION_DEVELOPMENT_PORT}"
env.DOCKER_IAMGE_NAME = "${APPLICATION_NAME}_development_${env.VERSION}"
env.xxl_port = 9998
}
if (env.BRANCH_NAME == 'release-testing') {
env.PORT = "${env.APPLICATION_TESTING_PORT}"
env.ENV_NAME = "testing"
env.SPRING_PROFILES_ACTIVE = "testing,swagger"
env.DOCKER_IAMGE_NAME = "${APPLICATION_NAME}_testing_${env.VERSION}"
env.xxl_port = 9998
}
if (env.BRANCH_NAME == 'release-production') {
env.ENV_NAME = "production"
env.DOCKER_IAMGE_NAME = "${APPLICATION_NAME}_testing_${env.VERSION}"
}
sh "echo Project Version: ${env.PROJECT_VERSION}"
sh "echo Build Version : ${env.VERSION}"
sh "echo Env name is : ${env.ENV_NAME}"
sh "echo Port is : ${env.PORT}"
sh "echo Image name is : ${env.DOCKER_IAMGE_NAME}"
sh "echo active profile is : ${env.SPRING_PROFILES_ACTIVE}"
}
}
}
stage('检查 & 构建 & 测试') {
steps {
sh 'chmod +x gradlew'
sh './gradlew clean build -x test --daemon -x war '
//sh './gradlew test'
stash allowEmpty: true, includes: 'build/**/*', name: 'buildResult'
}
}
stage("构建镜像") {
steps {
sh './gradlew clean bootRepackage buildDocker'
}
}
stage("发布镜像") {
steps {
script {
env.DOCKER_IAMGE_NAME = "${env.DOCKER_REGISTER}/${APPLICATION_NAME}-${ENV_NAME}:${env.VERSION}"
sh "docker tag ${env.APPLICATION_NAME} ${env.DOCKER_IAMGE_NAME}"
sh "docker login -u test -p 123456 192.168.20.192"
sh "docker push ${env.DOCKER_IAMGE_NAME}"
}
}
}
stage("发布应用到DEV|QA") {
when {
expression {
env.BRANCH_NAME.startsWith('feature') || env.BRANCH_NAME == 'release-testing'
}
}
steps {
ansiblePlaybook(
inventory: "devops/provision/inventories/${env.ENV_NAME}/hosts",
playbook: 'devops/provision/deploy.yml',
limit: "tianlai",
tags: 'new_java',
extraVars: [
workspace_path : "${WORKSPACE}",
application_name: "${APPLICATION_NAME}",
application_port: "${env.PORT}",
container_name : "${APPLICATION_NAME}_${ENV_NAME}",
image_name : "${DOCKER_IAMGE_NAME}",
run_container : "docker run -d -p ${env.PORT}:8080 -p ${env.xxl_port}:9998 -e 'SPRING_PROFILES_ACTIVE=${SPRING_PROFILES_ACTIVE}' -e JAVA_OPTS='-Xmx512m' -v /data/tianlai/localVoice:/home/yinghuo/localVoice --name ${APPLICATION_NAME}_${ENV_NAME} ${env.DOCKER_IAMGE_NAME}"
])
}
}
}
post {
success {
sendEmailNotification(true)
}
failure {
sendEmailNotification(false)
}
}
}
def sendEmailNotification(isSuccess) {
def subject
if (env.ENV_NAME == "development" || env.ENV_NAME == "testing" || env.ENV_NAME == "master") {
subject = isSuccess ? "【发布】${env.APPLICATION_DISPLAY_NAME}|已经成功发布到 ${env.ENV_NAME} 环境,请知悉。版本号:${env.VERSION}" : "【重要】${env.APPLICATION_DISPLAY_NAME}|发布到 ${env.ENV_NAME} 失败,请及时处理。版本号:${env.VERSION}"
}
if (env.BRANCH_NAME == "release-production") {
subject = isSuccess ? "【镜像构建完成】${env.APPLICATION_DISPLAY_NAME}的Docker镜像已经构建完成并发布,请知悉。镜像名:${env.DOCKER_IAMGE_NAME}" : "【重要-镜像构建失败】${env.APPLICATION_DISPLAY_NAME}的Docker镜像构建时出错,请及时处理。镜像名:${env.DOCKER_IAMGE_NAME}"
}
mail body: "访问 ${env.BUILD_URL} 查看Pipeline详情。", from: 'cd@yingyinglicai.com', replyTo: '', subject: " ${subject}", mimeType: 'text/html', to:
'xubitao@yingnagroup.com', cc: 'we-eat-bugs@yingyinglicai.com'
}

4、 节点构建服务器配置

5、 在节点服务器和应用服务器中均需要安装docker和ansible服务,安装步骤可参考RedHat上安装指定版本docker和docker-composeansible学习笔记。需要注意的是在应用服务器中为了能使docker正常pull镜像,需要进行以下操作。

1
2
3
4
5
6
vi /usr/lib/systemd/system/docker.service
ExecStart=/usr/bin/dockerd --insecure-registry 10.100.2.38 --insecure-registry 192.168.20.192
systemctl daemon-reload
systemctl restart docker

6、 配置dockerfile文件。dockerfile示例文件如下

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
# 基于什么镜像进行构建
FROM java:8
# 设置环境变量
ENV SPRING_OUTPUT_ANSI_ENABLED=ALWAYS \
YINGHUO_SLEEP=0 \
JAVA_OPTS="" \
TZ="Asia/Shanghai"
# Add a yinghuo user to run our application so that it doesn't need to run as root
RUN adduser --disabled-password yinghuo && mkdir -p /home/yinghuo/localVoice && mkdir -p /home/yinghuo/remoteVoice \
&& mkdir -p /data/xxl/logs && chown -R yinghuo:yinghuo /home/yinghuo/localVoice/ && chown -R yinghuo:yinghuo /home/yinghuo/remoteVoice/ && \
chown -R yinghuo:yinghuo /data/xxl/logs
# 等同于cd /home/yinghuo的意思
WORKDIR /home/yinghuo
# 添加启动脚本到容器中,设置权限
ADD entrypoint.sh entrypoint.sh
RUN chmod 755 entrypoint.sh && chown yinghuo:yinghuo entrypoint.sh
USER yinghuo
# 把构建好的war包放入容器中
ADD *.war app.war
# 执行启动命令
ENTRYPOINT ["./entrypoint.sh"]
# 容器暴露对外的端口号,需要在docker run时添加容器跟服务器的映射关系
EXPOSE 8080

工程项目结构图

7、进行ansible配置
在jenkinsfile中,会下载一个devops的项目,所有的ansible相关配置都在这个里面,当有新的应用服务器需要部署时,需要在ansible中hosts文件中添加相应的应用服务器信息。hosts文件在devops的devops/provision/inventories/development/路径下, 所有项目发布相关的ansible脚本在devops/provision/roles/deployment/tasks/这个路径下。

进行多分支构建

进入jenkins相关的项目后,点击扫描多分支流水线,扫描完毕后,选择需要构建的分支点击构建