如何用jenkins优雅的CI/CD

之前一直用gitlabCI/CD,去年换了个坑,新厂这边如今是用jenkinsCI/CD,之前听过jenkins,但一直没有用过,虽然建议过用gitlabCI/CD,但因为各类历史包袱,你们仍是坚持用jenkins,既然用这个,我固然不能对这玩意彻底不了解啊,开始各类搜罗资料,了解jenkins相关的知识。前端

流水线

构建一个自由风格的软件项目(free style project)

公司的流水线主要用的是这种,这个流水线有几个问题:node

1. 对构建机有必定的依赖,好比你要执行`npm install`或者`go mod vendor`,构建机必需要安装了`node`和`go`环境,若是对版本有要求就更尴尬了
2. 若是同一个项目,我想指定分支来构建,这里不太好处理
复制代码

流水线(workflow job)

这个流水线挺好的,能够动态设置pipeline script内容,用来作DevOps开发CI/CD挺好的,根据用户设置,用接口动态修改pipeline script的内容,不过也有一些小问题:git

1. 若是同一个项目,我想指定分支来构建,这里不太好处理
复制代码

多分支流水线(workflow multi branch project)

多分支流水线这个如今是我如今主要用的,若是你的项目有多个分支,每一个分支下都有jenkinsfile,构建的时候会根据你选的分支来构建,这样用来构建、发布不一样的分支就很方便golang

image.png

pipeline script

流水线的问题解决了,如今的问题是怎么构建的问题了,基于之前用.gitlab-ci.yml的经验,这里我仍是打算用docker来构建,有几处好处:docker

1. 对构建机的依赖比较小,只要有docker就能够了
2. 不用担忧构建环境被破坏问题,添加新构建机也很方便
复制代码

这里要先安装jenkins插件docker pipeline,而且在构建机安装dockerjenkinspipeline script的方法,能够看官方文档,里面写的很清楚了,如下是目前的jenkinsfilenpm

前端 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()
        // LABEL = 'nodelabel' // 若是要指定构建机,请设置构建机 label
        IMAGE_TAG = "${DOCKERHUB}/${PROJECT}:${BRANCH_NAME}-${BUILD_TIME}-${BUILD_ID}"
        // 我这用了apollo 配置服务,配置服务地址写到 jenkins的凭据里了
        APOLLO_QA = credentials('APOLLO_QA')
        APOLLO_PROD = credentials('APOLLO_PROD')
    }
    agent any

    options {
        retry(3)
    }

    stages {
        stage('init') {
            steps {
                script {
                    // 初始化环境变量,这样后面就不用写 when 指令了
                    if (env.BRANCH_NAME == 'test') {
                        env.APOLLO = APOLLO_QA
                        env.NAMESPACE = 'qa-ns'
                        env.K8SCONFIG = '/root/.kube/qa-ns.kubeconfig'
                   }else if (env.BRANCH_NAME == 'master') {
                        env.APOLLO = APOLLO_PROD
                        env.NAMESPACE = 'prod-ns'
                        env.K8SCONFIG = '/root/.kube/prod-ns.kubeconfig'
                    }
                }
            }
        }
        stage('build-dist') {
            agent {
                docker {
                    image 'node:14.17.0'
                    // label "${LABEL}" // 若是要指定构建机,请设置构建机 label
                }
            }
            steps {
                sh 'npm install --registry=https://registry.npm.taobao.org/ && npm run build'
                // 把构建的制品存起来,把 fingerprint 设置为 true,后期若是有问题,
                // 能够经过 Check File Fingerprint 快速定位到构建制品的流水线
                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'
                    // label "${LABEL}" // 若是要指定构建机,请设置构建机 label
                }
            }
            steps {                
                sh "docker build ."
                // registry已经在构建机登陆了,经过 -v /root/.docker:/root/.docker 把登陆信息共享过来了,
                // 这里没有办法,我没有 registry 的帐号信息,
                // 建议你们把 registry 的信息写到 jenkins 的凭据里面,经过 credentials 来读取,
                // 而后用 docker login 登陆
                sh "docker push ${IMAGE_TAG}"
            }
        }
        stage('deploy') {
            agent {
                docker {
                    image 'roffe/kubectl:v1.13.2'
                    // 这里是共享k8s信息,缘由同上,没有帐号,建议同上,用凭据来管理
                    args '-v /root/.kube:/root/.kube'
                    // label "${LABEL}" // 若是要指定构建机,请设置构建机 label
                }
            }
            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}"
        APOLLO_QA = credentials('APOLLO_QA')
        APOLLO_PROD = credentials('APOLLO_PROD')
    }
    agent any
    options {
        retry(3)
    }
    stages {
        stage('init') {
            steps {
                script {
                    if (env.BRANCH_NAME == 'test') {
                        env.APOLLO = APOLLO_QA
                        env.NAMESPACE = 'qa-ns'
                        env.K8SCONFIG = '/root/.kube/qa-ns.kubeconfig'
                   }else if (env.BRANCH_NAME == 'master') {
                        env.APOLLO = APOLLO_PROD
                        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 ."
                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 指令markdown

相关文章
相关标签/搜索