devops下项目ci的时候是通过docker拉起一个打包机进行项目打包,如果没有本地缓存就会出现所有包均需要取中央仓库或者私库拉取。
所以需要弄个共享磁盘作为本地缓存挂载到打包机中,那么新的问题又来了。
如果不同项目间存在依赖,此时打包就会出现串包现象。
所以就会出现莫名奇妙的问题,例如
- 我代码明明提交了,也打包成功了,为什么没有生效。百思不得其解
- 我明明没写这个代码,怎么给我报这个错误。
诸如此类的问题,在大型团队下就会频繁发生。
如果你生产环境也用的是snapshot,那么此时问题会更加严重,于是有人就想,我生产可以用release。又带来一个比较严重的问题,就是每次迭代,都要去改pom版本号,者用 maven reversion方式去替换版本号。如果不用release,开发环境打包又会出现包版本覆盖问题。导致生产事故频发。
接着演进就变成基于环境分仓,不同环境,本地都构建一个仓库,私服也构建一个仓库,准备四套maven setting.xml文件,构建时指定不同的setting文件。这种情况下解决了环境间的问题,但是还是无法解决同一环境下窜包的问题。
于是接着演进,变成根据分支分仓。大家互不干扰。你打你的包我打我的包。此时面临的问题又回到缓存的问题上。在这种方式下如果进行包缓存,就会出现共享磁盘容量炸裂,明明有很多公共包可以共用,但是maven却不支持本地多仓库。
所以接着演进:
每次打包开始前先进行pom文件扫描将需要的包从本地仓库拷贝到临时缓存,然后打包时将本地仓库指向各自的临时缓存。
仅本次打包有效。新的问题又随之而来,项目间的相互依赖问题,出现了。假如A项目引用了B项目,那么此时因为时临时缓存,各自的构建产物无法互相引用,为了解决这个问题,设计新的方案,如果项目存在互相引用,就设计一个引用列表,让它们在一次构建中完成操作。过程相对比较复杂,所以通过编写shell脚本进行构建。
将ci通过分支名分为两个阶段,一个为dev阶段一个为prod阶段。prod阶段不走脚本将包打到公共仓库去。
当然这种方案也不是每家公司都适用因为你有可能一个项目依赖了很多的外部项目,但是你本次开发就更改了其中一个项目。此时你要浪费大量的资源去打包那些没有变更的项目。但是这个方案对于我们却非常有用,我们每个项目只依赖一个公共项目,所以采用这种方案,能够做到,所有开发间打包互不影响的地步
脚本如下
#!/usr/bin/env bash
set -e
CUR_DIR=$(cd "$(dirname "$0")";pwd)
function build(){
cd "${CUR_DIR:-}/$1"
count=$(git branch -a|grep "${CI_COMMIT_REF_NAME}"|wc -l)
if [ "$count" != 0 ];then
maven_install
fi
cd "${CUR_DIR}"
rm -rf "${CUR_DIR:-}/$1"
}
function copy(){
GIT_URL="http://${GITLAB_USER:-user001}:${GITLAB_AT}@gitlab.xxx.cn/xxx-trading/$1.git"
if [ -d "$1" ];then
rm -rf "${CUR_DIR:-}/$1"
fi
git clone "$GIT_URL"
cd "${CUR_DIR:-}/$1"
count=$(git branch -a|grep "${CI_COMMIT_REF_NAME}"|wc -l)
if [ "$count" != 0 ];then
git checkout "${CI_COMMIT_REF_NAME}"
maven_copy
fi
cd "${CUR_DIR}"
}
function build_dependency(){
if [[ -n ${DEPENDENCY_LIST} ]];then
for PRE in $DEPENDENCY_LIST ;do
build "$PRE"
done
fi
}
function copy_dependency(){
if [[ -n ${DEPENDENCY_LIST} ]];then
for PRE in $DEPENDENCY_LIST ;do
copy "$PRE"
done
fi
}
function init(){
REMOTE_REPO="http://mvn.xxx.cn/nexus/content/repositories/xxxx-snapshot/"
LOCAL_REPO="/${GROUP_NAME}/${CI_COMMIT_REF_NAME}"
}
function maven_copy(){
mvn dependency:copy-dependencies -DoutputDirectory="${LOCAL_REPO}" -Dmdep.addParentPoms=true -Dmdep.useRepositoryLayout=true -Dmdep.copyPom=true -DoverWriteSnapshots=true -Dsilent=true
}
#从公共仓库拷贝一份dependency到本地分支仓库,然后执行install 指定仓库为分支仓库
function maven_install(){
mvn clean install -Dmaven.test.failure.ignore=true -DskipTests=true -Dmaven.repo.local="${LOCAL_REPO}" -Dmaven.repo.remote="${REMOTE_REPO}" -U
}
function main(){
init
copy_dependency
build_dependency
maven_install
}
main "$*"