之前一直用gitlab
來CI/CD
,去年換了個坑,新廠這邊如今是用jenkins
來CI/CD
,之前聽過jenkins
,但一直沒有用過,雖然建議過用gitlab
的CI/CD
,但因爲各類歷史包袱,你們仍是堅持用jenkins
,既然用這個,我固然不能對這玩意徹底不瞭解啊,開始各類蒐羅資料,瞭解jenkins
相關的知識。前端
公司的流水線主要用的是這種,這個流水線有幾個問題:node
1. 對構建機有必定的依賴,好比你要執行`npm install`或者`go mod vendor`,構建機必需要安裝了`node`和`go`環境,若是對版本有要求就更尷尬了
2. 若是同一個項目,我想指定分支來構建,這裏不太好處理
複製代碼
這個流水線挺好的,能夠動態設置pipeline script
內容,用來作DevOps
開發CI/CD
挺好的,根據用戶設置,用接口動態修改pipeline script
的內容,不過也有一些小問題:git
1. 若是同一個項目,我想指定分支來構建,這裏不太好處理
複製代碼
多分支流水線這個如今是我如今主要用的,若是你的項目有多個分支,每一個分支下都有jenkinsfile
,構建的時候會根據你選的分支來構建,這樣用來構建、發佈不一樣的分支就很方便golang
流水線的問題解決了,如今的問題是怎麼構建的問題了,基於之前用.gitlab-ci.yml
的經驗,這裏我仍是打算用docker
來構建,有幾處好處:docker
1. 對構建機的依賴比較小,只要有docker就能夠了
2. 不用擔憂構建環境被破壞問題,添加新構建機也很方便
複製代碼
這裏要先安裝jenkins
插件docker pipeline
,而且在構建機安裝docker
,jenkins
的pipeline script
的方法,能夠看官方文檔,裏面寫的很清楚了,如下是目前的jenkinsfile
npm
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}"
}
}
}
}
複製代碼
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