docker + gitlab + jenkins 自動部署及回滾
按之前配置已經完成了專案推送至 tag 後,jenkins host 會自動構建 docker 映象,並將映象推送至 阿里雲 registry,然後 jenkins host 會通過 Publish over SSH 外掛,將生成一個自動部署的指令碼push到指定的主機中,然後自動停止之前的映象並 pull 當前的映象並執行
遺留問題
-
版本回退功能未實現
需要實現版本回退功能支援對緊急問題的規避
-
回退版本記錄
構建的 image 是以 gitlab tag 名稱來建立的,所以版本回退時,必須要知道上一次的 image 才能進行回退操作,所以需要記錄每次自動部署時的 image 以方便自動部署回滾
記錄自動部署歷史
修改構建ssh指令碼,生成自動部署的指令碼中,加入每次自動部署時將上次的image寫入本地歷史檔案中便於版本回退
CONTAINER_NAME="citest"
GIT_TAG=`git describe --always --tag`
CONTAINER_FULL_NAME=${CONTAINER_NAME}-${GIT_TAG}
REPOSITORY=registry.cn-shanghai.aliyuncs.com/xxx/${CONTAINER_NAME}:${GIT_TAG}
# 構建Docker映象
docker build -t $REPOSITORY -f Dockerfile .
# 推送Docker映象
docker login --username=xxx --password=password registry.cn-shanghai.aliyuncs.com
docker push $REPOSITORY
# 刪除生成的image
docker images | grep citest | awk '{print $1":"$2}' | xargs docker rmi || true
# 刪除名稱或標籤為none的映象
docker rmi -f `docker images | grep '<none>' | awk '{print $3}'` || true
mkdir -p ./release && rm -f ./release/repull && echo \
"docker ps | grep citest | awk '{print \$2}' >> /data/jenkins/mi_test_history\n"\
"echo /data/jenkins/mi_test_history\n"\
"docker ps | grep citest | awk '{print \$1}' | xargs docker kill || true\n"\
"docker images | grep citest | awk '{print \$1\":\"\$2}' | xargs docker rmi -f || true\n"\
"docker login --username=xxx --password=password registry.cn-shanghai.aliyuncs.com\n"\
"docker pull $REPOSITORY\n"\
"docker run -d $REPOSITORY" >> ./release/repull
複製程式碼
這裡每次完成構建後,會生成一個自動部署指令碼 repull 並將此指令碼傳送到其他指定的主機中執行自動部署,而修改後的 repull 指令碼會再每次自動部署前都記錄一下上次的 image 到 /data/jenkins/mi_test_history 檔案中,這個檔案每一行代表一次版本更新,每次更新都會新增記錄至檔案的最後一行
建立引數化構建任務
原來的job是通過監聽 gitlab 的 tag 推送事件來觸發的,為了支援回滾,所以新增一個引數化構建的任務,該任務支援手動構建及手動回退版本
新建立任務的 git 配置與之前任務一致,然後勾選 引數化構建過程 並配置引數,這裡目前新增一個bool值引數,true表示執行手動構建,false表示版本回退
建立構建執行的shell指令碼,並支援對構建配置的引數的解析,按引數執行不同的操作
if [ "$CTRL_BUILD" = "true" ]
then
echo "to build image"
CONTAINER_NAME="citest"
GIT_TAG=`git describe --always --tag`"_manual_$BUILD_NUMBER"
CONTAINER_FULL_NAME=${CONTAINER_NAME}-${GIT_TAG}
REPOSITORY=registry.cn-shanghai.aliyuncs.com/xxx/${CONTAINER_NAME}:${GIT_TAG}
# 構建Docker映象
docker build -t $REPOSITORY -f Dockerfile .
# 推送Docker映象
docker login --username=xxx --password=password registry.cn-shanghai.aliyuncs.com
docker push $REPOSITORY
# 刪除生成的image
docker images | grep citest | awk '{print $1":"$2}' | xargs docker rmi || true
# 刪除名稱或標籤為none的映象
docker rmi -f `docker images | grep '<none>' | awk '{print $3}'` || true
rm -f ./auto.sh && echo \
"docker ps | grep citest | awk '{print \$2}' >> /data/jenkins/mi_test_history\n"\
"echo /data/jenkins/mi_test_history\n"\
"docker ps | grep citest | awk '{print \$1}' | xargs docker kill || true\n"\
"docker images | grep citest | awk '{print \$1\":\"\$2}' | xargs docker rmi -f || true\n"\
"docker login --username=xxx --password=password registry.cn-shanghai.aliyuncs.com\n"\
"docker pull $REPOSITORY\n"\
"docker run -d $REPOSITORY" >> ./auto.sh
else
echo "to rollback image"
rm -f ./auto.sh && echo \
"popline(){ LC_CTYPE=C l=\`tail -\"\${2:-1}\" \"\$1\"; echo t\`; l=\${l%t}; truncate -s \"-\${#l}\" \"\$1\"; printf %s \"\$l\"; }\n"\
"last=\`popline /data/jenkins/mi_test_history || \"\"\`\n"\
"if [ -n \"\$last\" ]; then\n"\
"\tdocker ps | grep citest | awk '{print \$1}' | xargs docker kill || true\n"\
"\tdocker images | grep citest | awk '{print \$1\":\"\$2}' | xargs docker rmi -f || true\n"\
"\tdocker login --username=xxx --password=password registry.cn-shanghai.aliyuncs.com\n"\
"\tdocker pull \$last\n"\
"\tdocker run -d \$last\n"\
"\techo \"rollback to \$last success\"\n"\
"else\n"\
"\techo \"nothing to rollback\"\n"\
"fi\n" >> ./auto.sh
fi
複製程式碼
手動構建版本與自動觸發構建基本一致,只是 image 名稱會新增手動構建的標識及構建編號,回滾時會生成一個回滾的指令碼,回滾指令碼將會從 /data/jenkins/mi_test_history 檔案中 pop出最後一行,然後停止當前的任務並刪除 image,然後 pull 舊版本的 image 並執行
Publish over SSH 的配置與之前差不多,主要就是將生產的 auto.sh 指令碼傳輸到從機並執行
功能測試
手動點選任務構建,並勾選自定義構建引數
會生成一個新的 image 覆蓋之前的 image 並執行,也產生了 history 記錄
再次手動點選任務構建,這次不勾選自定義構建引數來進行版本回退操作
目前版本已經回退至上個版本並清除版本記錄,功能正常