1. 程式人生 > 程式設計 >docker + gitlab + jenkins 自動部署及回滾

docker + gitlab + jenkins 自動部署及回滾

按之前配置已經完成了專案推送至 tag 後,jenkins host 會自動構建 docker 映象,並將映象推送至 阿里雲 registry,然後 jenkins host 會通過 Publish over SSH 外掛,將生成一個自動部署的指令碼push到指定的主機中,然後自動停止之前的映象並 pull 當前的映象並執行

遺留問題

  1. 版本回退功能未實現

    需要實現版本回退功能支援對緊急問題的規避

  2. 回退版本記錄

    構建的 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 記錄

再次手動點選任務構建,這次不勾選自定義構建引數來進行版本回退操作

目前版本已經回退至上個版本並清除版本記錄,功能正常