??(不要錯過!)【CI/CD技術(shù)專題】「Jenkins實戰(zhàn)系列」(3)Jenkinsfile+DockerFile實現(xiàn)自動部署

每日一句

沒有人會因?qū)W問而成為智者。學(xué)問或許能由勤奮得來,而機(jī)智與智慧卻有懶于天賦。

前提概要

  • Jenkins下用DockerFile自動部署Java項目,項目的部署放心推向容器化時代機(jī)制。
  • 本節(jié)需要對jenkinsfile有點了解,對dockerfile有點了解,對shell有點了解,對docker有點了解

環(huán)境準(zhǔn)備

新建-構(gòu)建一個Maven項目

image

需要提一下,現(xiàn)在新安裝的沒有這個選項,需要在插件里安裝一下 Maven Integration

image
image

java配置,其他配置查看以前文章

image

發(fā)布到服務(wù)器,DockerFile部署自動構(gòu)建

Publish SSH配置

image

執(zhí)行流程

  1. jenkins拉取代碼倉庫中的代碼
  2. jenkins執(zhí)行jenkinsfile文件(可指定文件名)
  3. 先在jenkins所在的服務(wù)器將拉取的項目build成docker鏡像
  4. 將鏡像發(fā)布到鏡像倉庫
  5. 在應(yīng)用服務(wù)器的節(jié)點上將該鏡像拉取下來(私有倉庫需要用戶名/密碼)
  6. 在應(yīng)用服務(wù)器上執(zhí)行該鏡像

jenkins配置

創(chuàng)建一個Pipeline SCM項目 jenkins項目名為sample-tezst (和發(fā)布的工程名保持一致)

image
  • Definition選擇 【Pipeline Script from SCM】

  • Branch Specifier(blank for 'any'):選擇分支

  • Additional Behaviours: 添加郵箱通知的發(fā)送者

  • Script Path: 填寫使用項目中的Jenkinsfile文件的名字

應(yīng)用工程配置

在工程的根目錄下創(chuàng)建Dockerfile文件和Jenkins_docker文件

jenkinsfile_docker文件內(nèi)容如下:

docker集成docker部署
pipeline {
    agent {label 'master'}
    tools{
        maven 'maven'
    }
    environment {
        GIT_PROJECT_ADDR="git@gitee.com:uncleqiao/springboot-test.git" //項目的git地址
        JENKINS_WORKSPACE="/root/.jenkins/workspace"    //jenkins存放文件的地址
        PROJECT_NAME="${JOB_NAME}"                      // 項目名
        JAR_NAME="sample-tezst-0.0.1-SNAPSHOT.jar"   // 項目生成的jar的名字
        IMAGE_NAME="sample-tezst"                    // 鏡像名一般和項目名相同
        IMAGE_ADDR="repository/qiao_namespace/${IMAGE_NAME}"    // 鏡像的位置
        VERSION_ID="${BUILD_ID}"
    }
    stages {
        stage('pullCode'){
            steps{
                echo 'This is a pullCode step'
                //git branch: "${BRANCH}", credentialsId: '1001', url: "${GIT_PROJECT_ADDR}"
                checkout scm
            }
        }
        stage('Build') {
            steps{
                echo 'This is a Build step'
                // 在有Jenkinsfile同一個目錄下(項目的根目錄下)
                sh 'mvn clean package -Dmaven.test.skip=true'
            }
        }
        // 創(chuàng)建目錄(如果不存在),并把jar文件上傳到該目錄下
        stage('ssh') {
            steps{
                echo 'push jar to target server'
                sh '''
                    ole_image_id=`docker images|grep ${IMAGE_NAME}|grep ${VERSION_ID}|awk '{print $3}'`
                    if [[ -n "${ole_image_id}" ]]; then
                        docker rmi -f ${ole_image_id}
                    fi
                    docker build -f  Dockerfile --build-arg jar_name=${JAR_NAME} -t ${IMAGE_NAME}:${VERSION_ID} .
                    new_image_id=`docker images|grep ${IMAGE_NAME}|grep ${VERSION_ID}|awk '{print $3}'`
                    sudo docker tag ${new_image_id} ${IMAGE_ADDR}:${VERSION_ID}
                    sudo docker push ${IMAGE_ADDR}:${VERSION_ID}
                '''
            }
        }
        stage('run') {
            // 在應(yīng)用服務(wù)器節(jié)點 test
            agent {
                node {
                    label 'test'
                    //customWorkspace "${SERVER_TARGET_PATH}"  //此參數(shù)會初始化目錄 注意填寫
                }
            }
            options {
                // 不讓它切換到節(jié)點上自動從倉庫拉取項目
                skipDefaultCheckout()
            }
            steps {
                echo 'pull image and docker run'
                withEnv(['JENKINS_NODE_COOKIE=dontKillMe']) {
                    sh '''
                        sudo docker login --username=yourusername --password=yourpassword ccr.ccs.tencentyun.com
                        sudo docker pull ${IMAGE_ADDR}:${VERSION_ID}

                        container_id=`docker ps|grep ${IMAGE_ADDR}:${VERSION_ID}|awk '{print $1}'`
                        if [ -n "${container_id}" ]; then
                            docker rm -f "${container_id}"
                        fi
                        old_pid=`ps -ef|grep ${JAR_NAME}|grep -v grep|awk '{print $2}'`
                        if [[ -n $old_pid ]]; then
                            kill -9 $old_pid
                        fi
                        old_image=`docker images|grep ${IMAGE_ADDR}|grep ${VERSION_ID}`
                        if [[ -n $old_image ]]; then
                            old_image_id=`echo ${old_image}|awk '{print $3}'`
                            docker rmi -f ${old_image_id}
                        fi
                        sudo docker run --name "${PROJECT_NAME}_${VERSION_ID}" -p 9001:8081 -d ${IMAGE_ADDR}:${VERSION_ID}
                    '''
                }
            }
        }
    }
}

注意:

if [ -n str ] 這個命令在使用的時候如果str為空,也是true,可以使用 if [ -n {str} -a "{str}x" != "x" ]或者使用if [[ -n {str} ]]來判斷 shell語法中,()` 和 `` (兩個單引號) 可以在子shell中執(zhí)行命令,但是這兒$()不支持

idea沒有jenkinsfile的語法提示,很容易出錯,這個很難受

步驟一:拉取項目 在【pullCode】步驟中

checkout scm , 這個scm是創(chuàng)建jenkins流水線時選擇的,屬于特殊變量,代表了你的倉庫信息,自動從倉庫中獲取項目

步驟二: 【Build】

將拉取下來的項目進(jìn)行編譯并打包

步驟三:【build_image】

將打包好的項目build成docker鏡像,然后推送到鏡像倉庫(這里可以分成兩步)

獲取已經(jīng)存在的鏡像
ole_image_id=`docker images| grep ${IMAGE_NAME} | grep ${VERSION_ID}|awk '{print $3}'`
刪掉存在的鏡像
if [[ -n "${ole_image_id}" ]]; then
    docker rmi -f ${ole_image_id}
fi
  • 通過項目根目錄下的Dockerfile來構(gòu)建鏡像
    • -f:[filename] --build-arg <key=value> 給Dockerfile傳遞參數(shù)
    • -t:鏡像的名稱:版本 這里我將jenkins的構(gòu)建次數(shù)當(dāng)作鏡像的版本
docker build -f Dockerfile --build-arg jar_name=${JAR_NAME} -t ${IMAGE_NAME}:${VERSION_ID} .
獲取構(gòu)建好的鏡像的id
new_image_id=`docker images | grep ${IMAGE_NAME} | grep ${VERSION_ID} | awk '{print $3}'`
根據(jù)生成的鏡像,tag出一個名稱空間不同的鏡像
sudo docker tag ${new_image_id} repoistory/qiao_namespace/${IMAGE_NAME}:${VERSION_ID}
將鏡像倉庫能夠識別的鏡像推送到倉庫
sudo docker push repoistory/qiao_namespace/${IMAGE_NAME}:${VERSION_ID}

步驟四:【run】

應(yīng)用服務(wù)器拉取項目并且運行, 這一步要選擇節(jié)點(應(yīng)用服務(wù)器,如果是集群,就不用節(jié)點用scp登陸吧)

登陸到鏡像倉庫
sudo docker login --username=yourusername --password=yourpassword repository
從倉庫中拉取剛才生成的鏡像
sudo docker pull repository/qiao_namespace/${IMAGE_NAME}:${VERSION_ID}
查看已經(jīng)存在的容器, 存在則刪掉 存在則刪掉 這里應(yīng)該是一個數(shù)組,有點小問題,待修改
container_id=`docker ps | grep ${IMAGE_ADDR}:${VERSION_ID} | awk '{print $1}'`
if [ -n "${container_id}" ]; then
    docker rm -f "${container_id}"
fi
查看已經(jīng)運行的同版本的項目, 存在則刪掉
pid=`ps -ef | grep ${JAR_NAME}| grep -v grep | awk '{print $2}'`
if [[ -n $pid ]]; then
    kill -9 $pid
fi
查看已經(jīng)存在的鏡像
old_image=`docker images|grep ${IMAGE_ADDR}|grep ${VERSION_ID}`
if [[ -n $old_image ]]; then
    old_image_id=`echo ${old_image}|awk '{print $3}'`
    docker rmi -f ${old_image_id}
fi

運行容器

sudo docker run --name "${PROJECT_NAME}_${VERSION_ID}" -p 9001:8081 -d ${IMAGE_ADDR}:${VERSION_ID}

Dockerfile

文件內(nèi)容如下

FROM repository/qiao_namespace/myjdk8:v1
默認(rèn)jar包的名字 注意分隔符為 :- 這里是由jenkinsfile中build dockerfile時傳遞過來的
ARG jar_name={jar_name:-sample-teszt-0.0.1-SNAPSHOT.jar}
RUN 用于容器內(nèi)部執(zhí)行命令
RUN mkdir -p /usr/local/project
WORKDIR /usr/local/project
將項目放到/usr/local/project下
COPY ./target/sample-teszt-0.0.1-SNAPSHOT.jar ./
EXPOSE 8081
CMD java -jar -Dserver.port=8081 springboot-test-0.0.1-SNAPSHOT.jar

執(zhí)行完畢后我們登陸到應(yīng)用服務(wù)器,看到容器已經(jīng)啟動

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容