首頁>技術>

構建前的執行引數定義

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

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

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

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

docker-compose配置compose模板檔案
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

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

映象名:${IMAGE_NAME}

映象tag:${VERSION},用於版本回滾

容器名:${CONTAINER_NAME}

JVM引數:${JAVA_OPTS}

埠對映:${PORT}

專案名:${APP_NAME}

健康檢查URL:${MONITOR_URL}

其中:映象tag是我們在回滾時需要輸入的引數,其他都是構建前根據實際情況插入到全域性環境變數中。

.env環境變數配置檔案

docker-compose預設使用同級目錄下的.env檔案作為環境變數配置檔案,藉助此檔案我們可以在構建前將jenkins中的全域性環境變數寫入此檔案,以便docker-compose使用。

#vim .envIMAGE_NAME=helloworld/helloworldCONTAINER_NAME=helloworldAPP_NAME=helloworldMONITOR_URL=http://127.0.0.1:8080PORT=9080:8080JAVA_OPTS=-Xmx129m -Xms129m -Dspring.profiles.active=testVERSION=5f06985aa4ed91a417ecd9b02abddb6efdbfd1b5
更新映象並啟動容器

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

docker-compose up -d --build

通過--build引數,在啟動容器前,都會更新使用的映象。

優化實現(加粗處是優化點)jenkins新建自由風格的job,名稱為docker-test-helloworld引數化構建插入全域性環境變數及設定Build Name

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

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

Build-環境校驗、操作校驗

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

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

(2)操作校驗

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

主要利用jenkins內建變數:

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

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

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

程式碼如下:

#!/bin/bashCHECK_ENV(){#判斷git分支是否與專案匹配,避免環境與專案混用ENV=`echo ${JOB_NAME}|awk -F'-' '{print $2}'`#測試分支develop,生產分支masterBRANCH=${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 1fi}#環境校驗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" || { \techo -e "\\033[31mmaven package fail\\033[0m" \texit 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 }fiBuild-遠端伺服器構建

通過“SSH Publishers”外掛登入遠端伺服器執行docker相關操作

#!/bin/bashIN_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,後續追加envINIT_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_VERSIONcase ${deploy_env} indeploy) 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

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

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

Post-build Actions#刪除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-prunefidocker image prune -f

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

總結

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

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

284

Docker

Git

最新評論
  • BSA-TRITC(10mg/ml) TRITC-BSA 牛血清白蛋白改性標記羅丹明
  • 知乎超高的12K贊回答!Java到底要學到什麼程度才能叫精通?