應用部署是開發、測試、上線必須面對的一個過程,尤爲是微服務架構的出現,運維部署從單體的部署逐漸脫離出,而且越顯複雜。java
然而,拋開多語言,多環境,集羣,分佈式的部署以外。就單單討論增量部署和全量部署git
部署,除卻項目初始化部署,最理想的狀況即爲:新版本更改哪些內容則更新哪些內容github
增量部署通常指在每次部署過程當中首先提取當前版本和即將部署版本之間的增量(包括代碼、可執行文件或者配置等),並在部署過程當中僅更新增量部分。shell
增量部署 若存在其餘外在部署環境依賴,則下降部署效率數據庫
增量部署不像安全
部署環境多的狀況下,對可重複性要求高架構
增量部署對回滾操做變得不友好負載均衡
現有的自動化部署,大多數都 全量部署,但全量部署也有一些弊端。但能夠經過一些策略進行篩選:運維
對於現代系統中絕大部分狀態無關的部署單元(應用、模塊,微服務等),全量部署通常應是最優的選擇。而狀態相關的部署單元(數據庫等)則依然適合增量部署邏輯。maven
前面講述了一些關於增量和全量部署的狀況。接下來說述如何經過shell腳本結合Git Log進行增量部署
Java項目
Maven進行管理
Git做爲代碼倉庫
shell新手,寫得不夠完美,輕噴。
# git環境
if [[ ! -d ".git" ]]; then
ECHO error: please init Git Repository
exit 1;
fi
if [[ ! -z ${branch} ]]; then
git checkout ${branch}
fi
# 獲取默認commit-hash
if [[ -z "$begin_hash" ]] && [[ -z "$end_hash" ]] ; then
for p in $(git log --pretty=oneline -2) ; do
if [[ ${#p} -eq 40 ]]; then
if [[ -z ${begin_hash} ]]; then
begin_hash=${p}
else
end_hash=${p}
break
fi
fi
done
fi
is_begin_has=false
# 是否當前最新commit
if [[ $(git log --pretty=oneline -1) == *${begin_hash}* ]]; then
is_begin_has=true
fi
# 非當前最新分支commit,回滾到原始版本,可能當時maven原始配置不支持compile或會出現構建失敗(如:使用本地倉/私有倉庫等)
if [[ ${is_begin_has} = false ]]; then
project_path=$(pwd)
project_name=${project_path##*/}
cd ..
build_project_name=${project_name}_build_temp_project
if [[ ! -d ${build_project_name} ]]; then
mkdir ${build_project_name}
fi
\cp -rf ${project_name}/. ${build_project_name}
cd ${build_project_name}
git reset --hard ${begin_hash}
fi
複製代碼
if [[ ! -d ".git" ]]; then
ECHO error: please init Git Repository
exit 1;
fi
複製代碼
if [[ ! -z ${branch} ]]; then
git checkout ${branch}
fi
複製代碼
若執行構建時,沒給添加 --begin_hash= 和 --end_hash= 進行賦值,則默認使用最新的兩次commit來進行增量部署。
經過 git log --pretty=oneline -2 獲取最近兩次commit的hash
# 獲取默認commit-hash
if [[ -z "$begin_hash" ]] && [[ -z "$end_hash" ]] ; then
for p in $(git log --pretty=oneline -2) ; do
if [[ ${#p} -eq 40 ]]; then
if [[ -z ${begin_hash} ]]; then
begin_hash=${p}
else
end_hash=${p}
break
fi
fi
done
fi
複製代碼
若非當前分支最新commit hash,則須要回滾到對應commit,進行項目構建編譯
if [[ $(git log --pretty=oneline -1) == *${begin_hash}* ]]; then
is_begin_has=true
fi
複製代碼
若傳參begin_hash的值非當前最新commit hash。則須要回滾到對應commit進行構建編譯。
if [[ ${is_begin_has} = false ]]; then
project_path=$(pwd)
project_name=${project_path##*/}
cd ..
build_project_name=${project_name}_build_temp_project
if [[ ! -d ${build_project_name} ]]; then
mkdir ${build_project_name}
fi
\cp -rf ${project_name}/. ${build_project_name}
cd ${build_project_name}
git reset --hard ${begin_hash}
fi
複製代碼
對項目進行編譯,生成對應class文件以及相關配置文件
mvn clean compile -q -DskipTest
複製代碼
若歷史版本中存在使用本地倉庫,而maven中沒有配置好的狀況能夠從新配置,經過scope以及systemPath進行引入,如:
<dependency>
<groupId>cn.catalpaflat</groupId>
<artifactId>core</artifactId>
<version>1.0.0</version>
<scope>system</scope>
<systemPath>${project.basedir}/lib/core-1.0.jar</systemPath>
</dependency>
複製代碼
爲了防止增量文件夾被刪除或者被commit到git倉庫,能夠統一化到一個目錄中,並經過 .gitignore 對其進行忽略。能夠比對每次增量部署的差別
build_path=build-path/
current_date=`date +%Y%m%d%H%m%s`
if [[ ! -d "$build_path$current_date" ]]; then
mkdir -p ${build_path}${current_date}
else
rm -rf ${build_path}${current_date}
mkdir -p ${build_path}${current_date}
fi
複製代碼
若項目爲Maven項目,而且是Java項目,因爲存在Maven多模塊狀況,須要檢索每一個模塊下的編譯後的代碼路徑,用於後續進行class等文件的拷貝。
default_target_paths=()
default_java_file=java
module_index=0
# 檢索當前項目是否maven多模塊開發,遞歸檢索,並設置其編譯後的代碼位置(暫只提供了java類型)
obtain_module(){
for module in ` cat ./pom.xml | grep '<module>' | awk -F '>' '{print $2}' | awk -F '<' '{print $1}' `
do
cd ${module}
if [[ ! -d "/pom.xml" ]]; then
module_exist=`cat ./pom.xml | grep '<module>' | awk -F '>' '{print $2}' | awk -F '<' '{print $1}'`
if [[ -z ${module_exist} ]]; then
if [[ ! -d "/target" ]]; then
if [[ -z $1 ]]; then
default_target_paths[module_index]=${module}/target/classes
else
default_target_paths[module_index]=$1/${module}/target/classes
fi
((module_index++))
fi
else
if [[ -z $1 ]]; then
obtain_module ${module}
else
obtain_module $1/${module}
fi
fi
fi
cd ..
done
}
obtain_module
複製代碼
# 經過git diff --name-only實現兩次commit之間文件差別,而且將begin_hash的代碼進行編譯後,將差別的文件拷貝到「增量文件夾」中,以備後續進行增量部署
for file_path in $(git diff --name-only ${begin_hash} ${end_hash}) ; do
package_path=${file_path%/*}
file_name=${file_path##*/}
file_type=${file_name##*.}
# 文件所在校驗文件夾是否建立
if [[ ${package_path} != *.* ]]; then
if [[ ! -d "./${build_path}${current_date}/$package_path" ]] ; then
mkdir -p ./${build_path}${current_date}/${package_path}
fi
fi
# 是否java
if [[ ${file_type} = ${default_java_file} ]]; then
module_path=${package_path##*java}
file_class_name=${file_name%.*}
module_type=${package_path%%/*}
# 排查在哪一個maven模塊路徑下
for default_target_path in ${default_target_paths[@]}; do
target_module_path=$(echo ${default_target_path} | awk -F '/target/' '{print $1}')
file_target_module_path=$(echo ${package_path} | awk -F '/src/' '{print $1}')
file_target_package_path=$(echo ${package_path} | awk -F '/src/main/java/' '{print $2}')
default_module_type=${default_target_path%%/*}
if [[ ${target_module_path} = ${file_target_module_path} ]]; then
# 排查到對應maven模塊的target目錄,進行cp操做
cp -afx ${default_target_path}/${file_target_package_path}/${file_class_name}* ./${build_path}${current_date}/${package_path}
fi
done
else
# 非java文件,直接拷貝文件到對應目錄下
if [[ ${package_path} != *.* ]]; then
if [[ ! -d "./${build_path}${current_date}/$package_path" ]] ; then
mkdir -p ./${build_path}${current_date}/${package_path}
fi
else
package_path=${package_path%/*}
fi
cp -afx ${file_path} ./${build_path}${current_date}/${package_path}
fi
done
複製代碼
到此爲止,1.0版本的簡陋版本初步完成,目測可使用,哈哈哈哈