超详细!手把手教你用Jenkins pipeline + docker 打造前后端持续集成环境
基于Jenkins pipeline + dock...
基于Jenkins pipeline + docker 打造后端持续集成环境
本文将从零开始教你搭建一个实用的自动发布流程,文中相关示例代码已上传到 github仓库 需要的朋友可以自取~
发布流程设计
- 开发人员提交代码、合并分支推送到指定分支
- Jenkins人工/定时触发项目构建
- Jenkins拉取、编译构建、打包镜像、推送到镜像仓库
- Jenkins 执行远程脚本:远程服务器 pull 指定镜像,重启新版本容器
搭建步骤
搭建Jenkins + Docker发布环境
- 安装新版docker
$ vi /etc/yum.repos.d/docker.repo --- // 填入以下内容 [dockerrepo] name=Docker Repository baseurl=https://yum.dockerproject.org/repo/main/centos/7/ enabled=1 gpgcheck=1 gpgkey=https://yum.dockerproject.org/gpg --- $ sudo yum install -y docker-engine $ sudo systemctl enable docker.service $ sudo systemctl start docker $ docker -v
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 安装Jenkins,初始化设置
1. mkdir /var/jenkins_home
2. sudo chown -R 1000:1000 /var/jenkins_home // 开放权限
3. sudo docker run -d -u root -name jenkins -p 8080:8080 -v /var/jenkins_home:/var/jenkins_home -v /var/run/docker.sock:/var/run/docker.sock -v $(which docker):/bin/docker jenkinsci/blueocean
- 1
- 2
- 3
注意: 在启动Jenkins服务时要加上-v /var/run/docker.sock:/var/run/docker.sock -v $(which docker):/bin/docker,让我们可以在docker容器中使用外部docker (docker in docker)
当在jenkins启动成功后 浏览 http://localhost:8080 并等待 Unlock Jenkins 页面出现。
在命令行中输入docker logs jenkins, 复制自动生成的字母数字密码(在两组星号之间)。 在 Unlock Jenkins 页面, 粘贴该密码到 Administrator password 字段并点击 Continue。
选择install suggested pulgins 等待安装成功
创建用户,进入主页。
- 创建多分支流水线项目
选择创建多分支流水线
设置分支源(过滤出release开头的分支)
完成设置。
代码中配置Dockerfile和Jenkinsfile
Jenkins执行流程
- 初始化配置:判断发布环境加载环境设置
- 用户自定义设置:确定本次需要执行的步骤
- 获取最新的代码
- 安装依赖项
- 运行单元测试
- 构建docker镜像推送到远程镜像仓库
- 登录远程服务器拉取最新镜像,并重启服务
编写Dockerfile做项目运行环境
FROM node:9.6.0
RUN apt-get update
RUN apt-get install vim -y
RUN npm install -g pm2 --registry=https://registry.npm.taobao.org
ARG PRO_ENV=test # 接受运行参数
ENV PRO_ENV=$PRO_ENV
复制需要的目录
COPY ./ /demo
WORKDIR /demo
RUN /bin/bash scripts/build.sh
CMD /bin/bash scripts/start.sh
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
配置Jenkinsfile
- 注册一个腾讯云账号,开通容器镜像服务(免费)
将账号密码配置在jenkins凭据中
- 配置一个config.json文件做环境配置:
{
"version": "1.0.0",
"registryName": "ccr.ccs.tencentyun.com/yohann/demo",
"env": {
"test": {
"credentialsId": "ssh-test”,
"host": "123.206.25.28"
},
"pro": {
"credentialsId": "ssh-test",
"host": "123.206.25.28"
}
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
避免在代码中写入账号密码,我们在Jenkins中配置相关凭据:
- 在git项目中增加Jenkinsfile,编写流水线流程
流水线语法支持两种格式:
1. 声明式流水线
pipeline {
agent any
stages {
stage('Example') {
steps {
echo 'Hello World'
}
}
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
2.脚本化流水线
node {
stage('Example') {
if (env.BRANCH_NAME == 'master') {
echo 'I only execute on the master branch'
} else {
echo 'I execute elsewhere'
}
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
脚本化的流水线自由度更高,因此我们选择脚本的写法
完整代码如下
import groovy.json.JsonSlurper
node {
currentBuild.result = “SUCCESS”
echo “PWD: ${pwd()}”
// 判断发布环境
if (env.BRANCH_NAME == 'release') {
env.PRO_ENV = "pro"
} else {
env.PRO_ENV = "test"
}
// 默认设置
env.VERSION = '1.0.0'
env.credentialsId = ''
env.host = ''
env.registryName = ''
def imageName = ''
def input_result // 用户输入项
try {
stage('config') {
echo "Branch: ${env.BRANCH_NAME}, Environment: ${env.PRO_ENV}"
input_result = input message: 'Check Tasks', ok: 'ok', parameters: [
booleanParam(name: 'install', defaultValue: false),
booleanParam(name: 'test', defaultValue: true),
booleanParam(name: 'deploy', defaultValue: true)
]
}
stage('Checkout'){
// 重置本地修改项
try {
sh 'git checkout .'
} catch (err) {
}
checkout scm
// 读取配置信息
if(fileExists('config.json')) {
def str = readFile 'config.json'
def jsonSlurper = new JsonSlurper()
def obj = jsonSlurper.parseText(str)
env.registryName = obj.registryName
def envConifg = obj.env[env.PRO_ENV]
echo "envConifg: ${envConifg}"
env.VERSION = obj.version
env.credentialsId = envConifg.credentialsId
env.host = envConifg.host
imageName = "${env.registryName}:${env.VERSION}_${env.PRO_ENV}_${BUILD_NUMBER}"
echo "VERSION: ${env.VERSION} ${imageName}"
}
sh 'ls'
}
stage('Install'){
if(input_result.install) {
docker.image('node:9.6.0').inside {
sh 'node -v'
sh 'sh ./scripts/install.sh'
}
}
}
stage('Test'){
if(input_result.test) {
docker.image('node:9.6.0').inside {
sh 'sh ./scripts/test.sh'
}
}
}
stage('Build Docker'){
// 构建上传镜像到容器仓库
if(input_result.deploy) {
def customImage = docker.build(imageName, "--build-arg PRO_ENV=${env.PRO_ENV} .")
docker.withRegistry("https://${env.registryName}", 'docker-demo') {
/* Push the container to the custom Registry */
customImage.push()
}
}
}
stage('Deploy'){
if(input_result.deploy) {
// wechat服务器
withCredentials([usernamePassword(credentialsId: env.credentialsId, usernameVariable: 'USER', passwordVariable: 'PWD')]) {
def otherArgs = '-p 8001:8001' // 区分不同环境的启动参数
def remote = [:]
remote.name = 'ssh-deploy'
remote.allowAnyHosts = true
remote.host = env.host
remote.user = USER
remote.password = PWD
if(env.PRO_ENV == "pro") {
otherArgs = '-p 3000:3000'
}
try {
sshCommand remote: remote, command: "docker rm -f demo"
} catch (err) {
}
sshCommand remote: remote, command: "docker run -d --name demo -v /etc/localtime:/etc/localtime -e PRO_ENV='${env.PRO_ENV}' ${otherArgs} ${imageName}"
}
// 删除旧的镜像
sh "docker rmi -f ${imageName.replaceAll("_${BUILD_NUMBER}", "_${BUILD_NUMBER - 1}")}"
}
}
}
catch (err) {
currentBuild.result = "FAILURE"
throw err
}
}
执行流水线
在git仓库中提交代码到release-test分支
在jenkins中打开blue-ocean执行该分支
本项目git仓库
本项目中的示例代码已上传到 github仓库 需要的朋友可以自取~
参考文章
- Jenkins Pipeline语法参考: https://blog.csdn.net/boonya/article/details/77941975
- 构建多分支流水线项目:https://jenkins.io/zh/doc/tutorials/build-a-multibranch-pipeline-project/
更多推荐
所有评论(0)