以前一直用gitlab
来CI/CD
,去年换了个坑,新厂这边现在是用jenkins
来CI/CD
,以前听过jenkins
,但一直没有用过,虽然建议过用gitlab
的CI/CD
,但由于各种历史包袱,大家还是坚持用jenkins
,既然用这个,我当然不能对这玩意完全不了解啊,开始各种搜罗资料,了解jenkins
相关的知识。
流水线
构建一个自由风格的软件项目(free style project)
公司的流水线主要用的是这种,这个流水线有几个问题:
1. 对构建机有一定的依赖,比如你要执行`npm install`或者`go mod vendor`,构建机必须要安装了`node`和`go`环境,如果对版本有要求就更尴尬了
2. 如果同一个项目,我想指定分支来构建,这里不太好处理
流水线(workflow job)
这个流水线挺好的,可以动态设置pipeline script
内容,用来做DevOps
开发CI/CD
挺好的,根据用户设置,用接口动态修改pipeline script
的内容,不过也有一些小问题:
1. 如果同一个项目,我想指定分支来构建,这里不太好处理
多分支流水线(workflow multi branch project)
多分支流水线这个现在是我现在主要用的,如果你的项目有多个分支,每个分支下都有jenkinsfile
,构建的时候会根据你选的分支来构建,这样用来构建、发布不同的分支就很方便
pipeline script
流水线的问题解决了,现在的问题是怎么构建的问题了,基于以前用.gitlab-ci.yml
的经验,这里我还是打算用docker
来构建,有几处好处:
1. 对构建机的依赖比较小,只要有docker就可以了
2. 不用担心构建环境被破坏问题,添加新构建机也很方便
这里要先安装jenkins
插件docker pipeline
,并且在构建机安装docker
,jenkins
的pipeline script
的方法,可以看官方文档,里面写的很清楚了,以下是目前的jenkinsfile
前端 jenkinsfile
pipeline {
environment {
PROJECT = 'example-front'
DEPLOYMENT_NAME = 'example-front-deployment'
DOCKERHUB = 'xxxx.com'
BUILD_TIME = sh(script:"date '+%Y%m%d%H%M'", returnStdout: true).trim()
IMAGE_TAG = "${DOCKERHUB}/${PROJECT}:${BRANCH_NAME}-${BUILD_TIME}-${BUILD_ID}"
}
agent any
options {
retry(3)
}
stages {
stage('init') {
steps {
script {
// 初始化环境变量,这样后面就不用写 when 指令了
if (env.BRANCH_NAME == 'test') {
env.NAMESPACE = 'qa-ns'
env.K8SCONFIG = '/root/.kube/qa-ns.kubeconfig'
}else if (env.BRANCH_NAME == 'master') {
env.NAMESPACE = 'prod-ns'
env.K8SCONFIG = '/root/.kube/prod-ns.kubeconfig'
}
}
}
}
stage('build-dist') {
agent {
docker {
image 'node:14.17.0'
}
}
steps {
sh 'npm install --registry=https://registry.npm.taobao.org/ && npm run build'
archiveArtifacts artifacts: 'dist/', fingerprint: true
}
}
stage('build-image') {
agent {
docker {
image 'docker:19.03.12'
args '-v /var/run/docker.sock:/var/run/docker.sock -v /root/.docker:/root/.docker'
}
}
steps {
sh "docker build -t ${IMAGE_TAG} ."
sh "docker push ${IMAGE_TAG}"
}
}
stage('deploy') {
agent {
docker {
image 'roffe/kubectl:v1.13.2'
args '-v /root/.kube:/root/.kube'
}
}
steps {
sh "kubectl --kubeconfig ${K8SCONFIG} -n ${NAMESPACE} set image deployment/${DEPLOYMENT_NAME} ${PROJECT}=${IMAGE_TAG}"
}
}
}
}
后端(go) jenkinsfile
pipeline {
environment {
PROJECT = 'example-front'
DEPLOYMENT_NAME = 'example-front-deployment'
DOCKERHUB = 'xxxx.com'
BUILD_TIME = sh(script:"date '+%Y%m%d%H%M'", returnStdout: true).trim()
IMAGE_TAG = "${DOCKERHUB}/${PROJECT}:${BRANCH_NAME}-${BUILD_TIME}-${BUILD_ID}"
}
agent any
options {
retry(3)
}
stages {
stage('init') {
steps {
script {
if (env.BRANCH_NAME == 'test') {
env.NAMESPACE = 'qa-ns'
env.K8SCONFIG = '/root/.kube/qa-ns.kubeconfig'
}else if (env.BRANCH_NAME == 'master') {
env.NAMESPACE = 'prod-ns'
env.K8SCONFIG = '/root/.kube/prod-ns.kubeconfig'
}
}
}
}
stage('build-main') {
agent {
docker {
image 'golang:1.14-alpine'
}
}
steps {
sh 'go mod vendor'
sh 'go build -o main main.go'
archiveArtifacts artifacts: 'main', fingerprint: true
}
}
stage('build-image') {
agent {
docker {
image 'docker:19.03.12'
args '-v /var/run/docker.sock:/var/run/docker.sock -v /root/.docker:/root/.docker'
}
}
steps {
sh "docker build -t ${IMAGE_TAG} ."
sh "docker push ${IMAGE_TAG}"
}
}
stage('deploy') {
agent {
docker {
image 'roffe/kubectl:v1.13.2'
}
}
steps {
sh "kubectl --kubeconfig ${K8SCONFIG} -n ${NAMESPACE} set image deployment/${DEPLOYMENT_NAME} ${PROJECT}=${IMAGE_TAG}"
}
}
}
}
现在我们点一下构建,就会依次执行这些job
,最终更新k8s
的容器
有些构建任务,如果想并行执行的话,可以了解下 parallel
指令