Jenkins+Docker+git實現多環境快速交付-compose優化升級

Jenkins+Docker+git實現多環境快速交付-compose優化升級

Jenkins+Docker+git多分支實現springboot項目多環境快速交付一文我們介紹了CI/CD交付springboot項目過程中的環境校驗發版/回滾/重啟、操作校驗等步驟,在實際應用過程中有幾點思考:

  1. 構建前的運行參數定義

構建前我們只按規範定義了APP_NAME(項目名)、IMAGE_NAME(鏡像名)、MONITOR_URL(健康檢查URL),相關的JVM參數、端口映射等與實際運行的參數仍然需要在後續的容器運行時手動修改,增加了配置難度,因此我們考慮將其提取到環境變量統一設置,以降低出問題的概率。

  1. 繁瑣的pull/start/stop/rm操作


在構建過程中需要在遠程服務器上頻繁的docker pull/start/stop/rm等操作來更新鏡像,有沒有更好的方式來簡化這些操作,來讓整個過程更加簡潔。因此,我們使用容器編排工具docker-compose來更新鏡像、管理容器

以上兩點是本文重點解決的問題,我們使用docker-compose+環境變量來實現下。

docker-compose配置

  1. compose模板文件
<code>version: '3.7'
services:
  helloworld:
    image: harbor.test.cn/${IMAGE_NAME}:${VERSION}
    container_name: ${CONTAINER_NAME}
    restart: always
    environment:
      - JAVA_OPTS=${JAVA_OPTS}
    ports:
      - $PORT
    volumes:
      - /App/java_app/${APP_NAME}/logs:/logs
    healthcheck:
      test: ["CMD", "curl", "-fs", "$MONITOR_URL"]
      interval: 8s
      timeout: 10s
      retries: 3/<code>

我們主要提取了以下幾個變量:

鏡像名:${IMAGE_NAME}

鏡像tag:${VERSION},用於版本回滾

容器名:${CONTAINER_NAME}

JVM參數:${JAVA_OPTS}

端口映射:${PORT}

項目名:${APP_NAME}

健康檢查URL:${MONITOR_URL}

其中:鏡像tag是我們在回滾時需要輸入的參數,其他都是構建前根據實際情況插入到全局環境變量中。

  1. .env環境變量配置文件

docker-compose默認使用同級目錄下的.env文件作為環境變量配置文件,藉助此文件我們可以在構建前將jenkins中的全局環境變量寫入此文件,以便docker-compose使用。

<code>#vim .env
IMAGE_NAME=helloworld/helloworld
CONTAINER_NAME=helloworld
APP_NAME=helloworld
MONITOR_URL=http://127.0.0.1:8080
PORT=9080:8080
JAVA_OPTS=-Xmx129m -Xms129m -Dspring.profiles.active=test
VERSION=5f06985aa4ed91a417ecd9b02abddb6efdbfd1b5/<code>
  1. 更新鏡像並啟動容器

每次構建前修改.env文件後,我們可以通過docker-compose來pull指定的鏡像並啟動容器了。

<code>docker-compose up -d --build/<code>

通過--build參數,在啟動容器前,都會更新使用的鏡像。

優化實現(加粗處是優化點)

  1. jenkins新建自由風格的job,名稱為docker-test-helloworld
  2. 參數化構建
Jenkins+Docker+git實現多環境快速交付-compose優化升級

  1. 插入全局環境變量及設置Build Name
Jenkins+Docker+git實現多環境快速交付-compose優化升級

<code>APP_NAME=helloworld
IMAGE_NAME=helloworld/helloworld
MONITOR_URL="http://127.0.0.1:8080"
JAVA_OPTS="-Xmx129m -Xms129m -Dspring.profiles.active=$(echo ${JOB_NAME}|awk -F'-' '{print $2}')"
PORT=9080:8080/<code>

以上是插入的全局環境變量,整個項目我們只需在此處集中修改,以減少配置錯誤為目的。

  1. Build-環境校驗、操作校驗
Jenkins+Docker+git實現多環境快速交付-compose優化升級

Build過程主要進行環境校驗、操作校驗操作,用於

(1)環境校驗,判斷git分支與當前job-test/prod是否一致,不一致則停止後續發版操作;

(2)操作校驗

發版:git對應分支是否有更新,防止在沒有更新時構建多次,導致應用多次重啟;

主要利用jenkins內置變量:


GIT_PREVIOUS_SUCCESSFUL_COMMIT 上次構建成功後的git版本號

GIT_COMMIT 當前構建任務的git版本號

回滾:判斷遠程分支是否有與參數匹配的版本號,沒有則說明不合法,停止回滾;

代碼如下:

<code>#!/bin/bash
CHECK_ENV(){
#判斷git分支是否與項目匹配,避免環境與項目混用
ENV=`echo ${JOB_NAME}|awk -F'-' '{print $2}'`
#測試分支develop,生產分支master
BRANCH=${GIT_BRANCH}
if [ $BRANCH = "origin/develop" ];then 
    [ $ENV="test" ] &&  echo -e "\033[34m$ENV environment is in building \033[0m" || {
        echo -e "\033[31m git branch is $BRANCH, not match environment $ENV \033[0m"
        exit 1
    }
else
    echo -e "\033[31m git branch is $BRANCH, not match environment $ENV \033[0m"
    exit 1
fi
}

#環境校驗
CHECK_ENV


#操作校驗
if [ "${deploy_env}" = "deploy" ];then
    echo -e "\033[34mstart ${deploy_env}\033[0m"
    echo ${GIT_PREVIOUS_SUCCESSFUL_COMMIT}
    echo ${GIT_COMMIT}
    [ "${GIT_PREVIOUS_SUCCESSFUL_COMMIT}" != "${GIT_COMMIT}" ] && echo -e "\033[34mstart maven package\033[0m" || {
        #版本未更新,停止發版
        echo -e "\033[31mRepositories not update, stop ${deploy_env}\033[0m"
        exit 1
    }
      
    /usr/local/maven/bin/mvn clean package docker:build -DdockerImageTags=${GIT_COMMIT} -Dmaven.test.skip=true -DpushImageTag
    [ $? -eq 0 ] && echo -e "\033[32mmaven package success\033[0m" || {
    	echo -e "\033[31mmaven package fail\033[0m"
    	exit 1
    } 
elif [ "${deploy_env}" = "rollback" ];then
    echo -e "\033[34mstart ${deploy_env}\033[0m"
    echo ${GIT_PREVIOUS_SUCCESSFUL_COMMIT}
    echo ${GIT_COMMIT}
    #查看遠程分支是否有此版本
    git branch -r --contains $version
    [ $? -eq 0 ] && echo -e "\033[34mstart docker steps\033[0m" || {
        echo -e "\033[31mverison is wrong,please check version\033[0m"
        exit 1
    }
fi/<code>
  1. Build-遠程服務器構建
Jenkins+Docker+git實現多環境快速交付-compose優化升級

通過“SSH Publishers”插件登錄遠程服務器執行docker相關操作

<code>#!/bin/bash
IN_FACE=`/sbin/route -n |awk '{if($4~/UG/){print $8}}'|head -n 1`
LOCAL_IP=`/sbin/ip addr show "${IN_FACE}" | grep -w 'inet' | awk '{print $2}'`

CONTAINER_NAME=`echo ${IMAGE_NAME} | awk -F/ '{print $2}'`
#ENV=`echo ${JOB_NAME}|awk -F'-' '{print $2}'`

#刪除老鏡像
DEL_IMAGE() {
    echo -e "\033[34mrm image ${IMAGE_NAME}:$1\033[0m"
    sudo docker image rm harbor.test.cn/${IMAGE_NAME}:$1  --no-prune
    [ $? -eq 0 ] && echo -e "\033[32mrm ${IMAGE_NAME}:$1 succss \033[0m" || { 
        echo -e "\033[31mrm ${IMAGE_NAME}:$1 fail \033[0m"
        exit 1
    }
}

#健康檢查
HEALTHCHECK() {
    timeout=180
    echo -e "\033[34mhealth check\033[0m"
    for (( i=1;i<=$timeout;i++ ))
    do
        status=$(sudo docker inspect --format='{{json .State.Health}}' ${CONTAINER_NAME}|grep -Po '"Status[":]+\K[^"]+')
        echo $status
        if [ $status = 'healthy' ];then
           echo -e "\033[32m${LOCAL_IP} ${CONTAINER_NAME}  status is ${status}\033[0m"
           DEL_IMAGE ${OLD_VERSION}
           exit 0
        elif [ $status = 'starting' ];then
           sleep 23
        else
           echo -e "\033[31m${LOCAL_IP} ${CONTAINER_NAME} status is ${status}\033[0m"  
           exit 1  
        fi
    done
}


#定義docker-compose變量,注意第一步清空env,後續追加env
INIT_VAR() {
    echo -e "\033[34minit docker-compose variable\033[0m"
    echo "IMAGE_NAME=${IMAGE_NAME}" > .env
    echo "CONTAINER_NAME=${CONTAINER_NAME}" >> .env
    echo "APP_NAME=${APP_NAME}" >> .env
    echo "ENV=${ENV}" >> .env
    echo "MONITOR_URL=${MONITOR_URL}" >> .env
    echo "PORT=${PORT}" >> .env
    echo "JAVA_OPTS=${JAVA_OPTS}" >> .env
}

#進入項目目錄
cd /App/java_app_tmp/${APP_NAME}
#提前讀取env文件中的老版本號,用於刪除老鏡像
OLD_VERSION=$(grep VERSION .env|awk -F= '{print $2}')
echo $OLD_VERSION

case ${deploy_env} in
deploy)
    echo -e "\033[34mstart ${deploy_env} steps\033[0m"
    INIT_VAR
    echo "VERSION=${GIT_COMMIT}" >> .env
    sudo docker-compose up -d --build
    HEALTHCHECK
    ;;
rollback)
    echo -e "\033[34mstart ${deploy_env} steps\033[0m"
    INIT_VAR
    echo "VERSION=${version}" >> .env
    sudo docker-compose up -d --build
    HEALTHCHECK
    ;;
restart)
    sudo docker-compose restart
    HEALTHCHECK
    ;;
*)
    exit 1
    ;;
esac/<code>

通過docker-compose將之前的pull/stop/rm/start等一系列的docker操作全部用"docker-compose up -d --build"代替,大大簡化了代碼。

注意:每次構建前通過">"清除.env文件並重啟添加,之所以保留便於我們排查問題。

  1. Post-build Actions
Jenkins+Docker+git實現多環境快速交付-compose優化升級

<code>#刪除jenkins slave服務上的虛懸鏡像
echo -e "\033[34mrm old image on jenkins slave\033[0m"
if [ $(docker image ls harbor.test.cn/${IMAGE_NAME} -q|wc -l) -ne 0 ];then 
   docker image rm `docker image ls harbor.test.cn/${IMAGE_NAME} -q` -f --no-prune
fi
docker image prune -f/<code>

刪除jenkins slave服務上新構建的鏡像及虛懸鏡像,保持slave上的環境純淨。


通過以上步驟我們只在第3、5步配合docker-compose做了優化,其他不變仍可參考Jenkins+Docker+git多分支實現springboot項目多環境快速交付


總結

本文之所以是優化升級,因為在配置過程中提高可讀性、集中配置、簡化操作可以有效的減少出錯的概率,另外在DevOps中交付的效率問題也是非常重要的一個環節。

最重要的是目前的Docker實踐我們需要一步一個腳印的走過來,在這過程中要不斷的思考、總結。


我是【木訥大叔愛運維】,歡迎關注,與你分享運維路上的點點滴滴。


分享到:


相關文章: