基於Jenkins Pipeline自動化部署

微信公衆號「後端進階」,專一後端技術分享:Java、Golang、WEB框架、分佈式中間件、服務治理等等。 老司機傾囊相授,帶你一路進階,來不及解釋了快上車!node

最近在公司推行Docker Swarm集羣的過程當中,須要用到Jenkins來作自動化部署,Jenkins實現自動化部署有不少種方案,能夠直接在jenkins頁面寫Job,把一些操做和腳本都經過頁面設置,也能夠在每一個項目中直接寫Pipeline腳本,但像我那麼優秀,那麼追求極致的程序員來講,這些方案都打動不了我那顆騷動的心,下面我會跟大家講講我是如何經過Pipeline腳本實現自動化部署方案的,而且實現多分支構建,還實現了全部項目共享一個Pipeline腳本。git

使用Jenkins前的一些設置

爲了快速搭建Jenkins,我這裏使用Docker安裝運行Jenkins:程序員

$ sudo docker run -it -d \
  --rm \
  -u root \
  -p 8080:8080 \
  -v jenkins-data:/var/jenkins_home \
  -v /var/run/docker.sock:/var/run/docker.sock \
  -v "$HOME":/home \
  --name jenkins jenkinsci/blueocean

初次使用jenkins,進入Jenkins頁面前,須要密碼驗證,咱們須要進入docker容器查看密碼:github

$ sudo docker exec -it jenkins /bin/bash
$ vi /var/jenkins_home/secrets/initialAdminPassword

Docker安裝的Jenkins稍微有那麼一點缺陷,shell版本跟CenOS宿主機的版本不兼容,這時咱們須要進入Jenkins容器手動設置shell:docker

$ sudo docker exec -it jenkins /bin/bash
$ ln -sf /bin/bash /bin/sh

因爲咱們的Pipeline還須要在遠程服務器執行任務,須要經過ssh鏈接,那麼咱們就須要在Jenkins裏面生成ssh的公鑰密鑰:shell

$ sudo docker exec -it jenkins /bin/bash
$ ssh-keygen -C "root@jenkins"

在遠程節點的~/.ssh/authorized_keys中添加jenkins的公鑰(id_rsa.pub)後端

還須要安裝一些必要的插件:bash

  1. Pipeline Maven Integration
  2. SSH Pipeline Steps

安裝完插件後,還須要去全局工具那裏添加maven:服務器

maven

這裏後面Jenkinsfile有用到。微信

mutiBranch多分支構建

因爲咱們的開發是基於多分支開發,每一個開發環境都對應有一條分支,因此普通的Pipeline自動化構建並不能知足現有的開發部署需求,因此咱們須要使用Jenkins的mutiBranch Pipeline。

首先固然是新建一個mutiBranch多分支構建job:

maven

接着設置分支源,分支源就是你項目的git地址,選擇Jenkinsfile在項目的路徑

maven

接下來Jenkins會在分支源中掃描每一個分支下的Jenkinsfile,若是該分支下有Jenkinsfile,那麼就會建立一個分支Job

maven

該job下的分支job以下:

maven

這裏須要注意的是,只有須要部署的分支,才加上Jenkinsfile,否則Jenkins會將其他分支也建立一個分支job。

通用化Pipeline腳本

到這裏以前,基本就能夠基於Pipeline腳本自動化部署了,但若是你是一個追求極致,不甘於平庸的程序員,你必定會想,隨着項目的增多,Pipeline腳本不斷增多,這會形成愈來愈大的維護成本,隨着業務的增加,不免會在腳本中修改東西,這就會牽扯太多Pipeline腳本了,並且這些腳本基本都相同,那麼對於我這麼優秀的程序員,怎麼會想不到這個問題呢,我第一時間就想到通用化pipeline腳本。所幸,Jenkins已經看出了我不斷騷動的心了,Jenkins甩手就給我一個Shared Libraries。

Shared Libraries是什麼呢?顧名思義,它就是一個共享庫,它的主要做用是用於將通用的Pipeline腳本放在一個地方,其它項目能夠從它那裏獲取到一個全局通用化的Pipeline腳本,項目之間經過不通的變量參數傳遞,達到通用化的目的。

接下來咱們先建立一個用於存儲通用Pipeline腳本的git倉庫:

maven

倉庫目錄不是隨便亂添加了,Jenkins有一個嚴格的規範,下面是官方說明:

maven

官方已經講得很清楚了,大概意思就是vars目錄用於存儲通用Pipeline腳本,resources用於存儲非Groovy文件。因此我這裏就把Pipeline須要的構建腳本以及編排文件都集中放在這裏,徹底對業務工程師隱蔽,這樣作的目的就是爲了不業務工程師不懂瞎幾把亂改,致使出bug。

建立完git倉庫後,咱們還須要在jenkins的Manage Jenkins » Configure System » Global Pipeline Libraries中定義全局庫:

maven

這裏的name,能夠在jenkinsfile中經過如下命令引用:

@Library 'objcoding-pipeline-library'

下面咱們來看通用Pipeline腳本的編寫規則:

#!groovy

def getServer() {
    def remote = [:]
    remote.name = 'manager node'
    remote.user = 'dev'
    remote.host = "${REMOTE_HOST}"
    remote.port = 22
    remote.identityFile = '/root/.ssh/id_rsa'
    remote.allowAnyHosts = true
    return remote
}

def call(Map map) {

    pipeline {
        agent any

        environment {
            REMOTE_HOST = "${map.REMOTE_HOST}"
            REPO_URL = "${map.REPO_URL}"
            BRANCH_NAME = "${map.BRANCH_NAME}"
            STACK_NAME = "${map.STACK_NAME}"
            COMPOSE_FILE_NAME = "docker-compose-" + "${map.STACK_NAME}" + "-" + "${map.BRANCH_NAME}" + ".yml"
        }

        stages {
            stage('獲取代碼') {
                steps {
                    git([url: "${REPO_URL}", branch: "${BRANCH_NAME}"])
                }
            }

            stage('編譯代碼') {
                steps {
                    withMaven(maven: 'maven 3.6') {
                        sh "mvn -U -am clean package -DskipTests"
                    }
                }
            }

            stage('構建鏡像') {
                steps {
                    sh "wget -O build.sh https://git.x-vipay.com/docker/jenkins-pipeline-library/raw/master/resources/shell/build.sh"
                    sh "sh build.sh ${BRANCH_NAME} "
                }
            }

            stage('init-server') {
                steps {
                    script {
                        server = getServer()
                    }
                }
            }

            stage('執行發版') {
                steps {
                    writeFile file: 'deploy.sh', text: "wget -O ${COMPOSE_FILE_NAME} " +
                        " https://git.x-vipay.com/docker/jenkins-pipeline-library/raw/master/resources/docker-compose/${COMPOSE_FILE_NAME} \n" +
                        "sudo docker stack deploy -c ${COMPOSE_FILE_NAME} ${STACK_NAME}"
                    sshScript remote: server, script: "deploy.sh"
                }
            }
        }
    }
}
  1. 因爲咱們須要在遠程服務器執行任務,因此定義一個遠程服務器的信息其中remote.identityFile就是咱們上面在容器生成的密鑰的地址;
  2. 定義一個call()方法,這個方法用於在各個項目的Jenkinsfile中調用,注意必定得叫call;
  3. 在call()方法中定義一個pipeline;
  4. environment參數便是可變通用參數,經過傳遞參數Map來給定值,該Map是從各個項目中定義的傳參;
  5. 接下來就是一頓步驟操做啦,「編譯代碼」這步驟須要填寫上面咱們在全局工具類設置的maven,「構建鏡像」的構建腳本巧妙地利用wget從本遠程倉庫中拉取下來,」執行發版「的編排文件也是這麼作,「init-server」步驟主要是初始化一個server對象,供「執行發版使用」。

從腳本看出來Jenkins未來要推崇的一種思惟:配置即代碼。

寫完通用Pipeline腳本後,接下來咱們就須要在各個項目的須要自動化部署的分支的根目錄下新建一個Jenkinsfile腳本了:

maven

接下來我來解釋一下Jenkinsfile內容:

#!groovy

// 在多分支構建下,嚴格規定Jenkinsfile只存在能夠發版的分支上

// 引用在jenkins已經全局定義好的library
library 'objcoding-pipeline-library'
def map = [:]

// 遠程管理節點地址(用於執行發版)
map.put('REMOTE_HOST','xxx.xx.xx.xxx')
// 項目gitlab代碼地址
map.put('REPO_URL','https://github.com/objcoding/docker-jenkins-pipeline-sample.git')
// 分支名稱
map.put('BRANCH_NAME','master')
// 服務棧名稱
map.put('STACK_NAME','vipay')

// 調用library中var目錄下的build.groovy腳本
build(map)
  1. 經過library 'objcoding-pipeline-library'引用咱們在Jenkins定義的全局庫,定義一個map參數;
  2. 接下來就是將項目具體的參數保存到map中,調用build()方法傳遞給通用Pipeline腳本。

Shared Libraries共享庫極大地提高了Pipeline腳本的通用性,避免了腳本過多帶來的問題,也符合了一個優秀程序員的審美觀,若是你是一個有追求的程序員,你必定會愛上它。

流程圖:

maven

demo git 地址:

pipeline: https://github.com/objcoding/jenkins-pipeline-library

單項目部署: https://github.com/objcoding/docker-jenkins-pipeline-sample

多項目部署: https://github.com/objcoding/docker-jenkins-pipeline-sample2

公衆號「後端進階」,專一後端技術分享!

相關文章
相關標籤/搜索