前言
书接【Bug周刊】的gitlab-ci
构建部分,我们已经对一个 maven
项目进行了CI构建,实现每次提交代码后自动打包为 jar
包,并在docker in docker
的镜像中 build
为 docker 镜像。避免跳转麻烦,把上文的构建内容放到了基础部分。
基础(可跳过)
问题描述
需要对一个maven
项目进行自动化构建,要求每次提交都会触发构建,减少运维的工作量,将构建好的jar包打包成docker镜像并推送至私有的镜像仓库。
详情如下:
1、自定义开发的common
模块并不完善,也没有上传至私有的nexus
仓库,需要打包的功能模块依赖于common
2、项目依赖的部分jar
包需要从私有的nexus
仓库下载,需要配置对应的仓库地址
3、构建时间的优化、提升
解决方案
1、在代码仓库中增加 .m2/settings.xml
文件,配置对应的私有nexus仓库地址、阿里云或者腾讯云的nexus地址提升下载速度
2、增加 localReposity
配置,告诉maven在找不到对应jar
包时,从本地读取,完成common
模块的引入。由于common模块是独立开发的,故和其他模块的pom父类并不一致,各个模块也有不同的配置,在原项目根目录下并没有pom文件,所以不能通过构建根pom文件的方式完成项目的打包。
3、引入cache
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
| variables: RELEASE_TAG: "1.0.0" MAVEN_CLI_OPTS: "../.m2/settings.xml --batch-mode -Dmaven.repo.local=$CI_PROJECT_DIR/.m2/repository"
cache: key: ${CI_COMMIT_REF_SLUG} paths: - ~/.m2/repository/ - target/
stages: - package - release
package: image: maven:3.6.1-jdk-8-alpine stage: package only: - master tags: - docker script: - cd test-common - mvn -s $MAVEN_CLI_OPTS -e package install - cd ../test-app - mvn -s $MAVEN_CLI_OPTS -e package artifacts: paths: - test-app/target/test-app-application-exec.jar expire_in: 1 hours
release: image: docker:20-dind stage: release only: - master tags: - docker-slim before_script: - docker login --username=username -p $REPOS_PASSWORD test.com script: - df -h - docker build -t test/test-app:$RELEASE_TAG . - docker push test.com/test-image/test-app:$RELEASE_TAG
|
进阶
问题描述
目前的业务需求是,在原maven项目的基础上,根目录增加了同级的模块,需要分模块构建,并且每次提交代码只对产生变更的模块进行打包。
文件夹树如下:
1 2 3 4 5 6 7 8 9 10
| |---.m2 |---gateway |---moudle |---hr |---manage |---adminstrive |---.gitlab-ci.yml |---dockerfile |---startup.sh
|
解决方案
1、对变更模块进行判断,需要使用 git diff
命令
单纯的maven3.6版本的镜像没有git,同时也未安装对应的命令行工具,如apt、apk、yum等,因此无法在 before_script
阶段安装 git
工具曲线救国。只能更换原来的镜像。
2、分模块构建,需要使用通用的 dockerfile
,即在gitlab-ci.yml
中对构建模块名进行判断,将此作为变量传入到dockerfile中。
docker build 命令提供了 --build-arg
的参数可以将变量传入dockerfile中。
3、明确CI文件 script
中的命令与 linux
终端命令细微的区别,避免出现标点的错误。
少年要不要来回试试,没有这些; \ \n &&
符号,可能会寸步难行。
4、选择正确的镜像,满足打包和构建的使用要求。
如果在 dind
镜像中没有git命令对模块判断进行 build
,不妨试试判断上一步,对产生变更的模块进行打包,是否有产物传给这一步骤,判断文件是否存在,比再安装一遍git省事多了。
5、纠正基础中的缓存地址。
配置文件
.gitlab-ci.yml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82
| variables: RELEASE_TAG: "0.0.1" JAR_HR: "module/module-hr/target/module-hr-exec.jar" JAR_MANAGE: "module/module-manage/target/module-manage-exec.jar" MAVEN_CLI_OPTS: "../../.m2/settings.xml --batch-mode -Dmaven.repo.local=$CI_PROJECT_DIR/.m2/repository"
cache: key: m2-repo paths: - .m2/repository/ - $CI_PROJECT_DIR/.m2/repository
stages: - package - release
package: image: labelinsight/java-maven:3.6-jdk-8 stage: package only: - dev tags: - docker before_script: - apt-get install -y git script: - if [[ -n $(git diff --name-only $CI_COMMIT_BEFORE_SHA $CI_COMMIT_SHA | grep '^module/module-hr/') ]]; then cd module/module-hr; mvn -s $MAVEN_CLI_OPTS -e package; cd ../../; fi; - if [[ -n $(git diff --name-only $CI_COMMIT_BEFORE_SHA $CI_COMMIT_SHA | grep '^module/module-manage/') ]]; then cd module/module-manage; mvn -s $MAVEN_CLI_OPTS -e package; cd ../../; fi; artifacts: paths: - module/module-hr/target/module-hr-exec.jar - module/module-manage/target/module-manage-exec.jar
expire_in: 1 hours
release: image: docker:20-dind stage: release only: - dev tags: - docker-slim before_script: - docker login --username=username -p $REPOS_PASSWORD docker.repos.cscec81.com:4433 script: - df -h - if [[ -f "module/module-hr/target/module-hr-exec.jar" ]]; then docker build -t test/test-hr:$RELEASE_TAG --build-arg BUILD_JAR_NAME=$JAR_HR .; docker push repos.test.com/test-image/test-hr:$RELEASE_TAG; fi; - if [[ -f "module/module-manage/target/module-manage-exec.jar" ]]; then docker build -t test/test-manage:$RELEASE_TAG --build-arg BUILD_JAR_NAME=$JAR_MANAGE .; docker push repos.test.com/test-image/test-manage:$RELEASE_TAG; fi;
|
dockerfile
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
| FROM openjdk:8-jdk
ARG BUILD_JAR_NAME
ENV BASE_DIR="/app" \ JAVA_HOME="/usr/local/openjdk-8/" \ JAVA="/usr/local/openjdk-8/bin/java" \ JVM_XMS="8g" \ JVM_XMX="8g" \ JVM_XMN="3g" \ JVM_MS="128m" \ JVM_MMS="320m" \ TZ="Asia/Shanghai" \ BUILD_JAR_NAME=$BUILD_JAR_NAME
WORKDIR $BASE_DIR
ENV MYSQL_HOST=127.0.0.1 \ MYSQL_PORT=3306 \ MYSQL_SERVICE_DB_NAME=root \ MYSQL_SERVICE_PASSWORD=123456
RUN rm -f /etc/localtime \ && ln -sv /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \ && echo "Asia/Shanghai" > /etc/timezone \ && echo "${BUILD_JAR_NAME}" \ && JAR_FILE_NAME=$(basename "${BUILD_JAR_NAME}") \ && echo "The jar file name is: ${JAR_FILE_NAME}"
COPY $BUILD_JAR_NAME ./startup.sh $BASE_DIR/
RUN chmod +x startup.sh
ENTRYPOINT ["sh","startup.sh"]
|
startup.sh
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| #!/bin/sh
JAR_FILE_NAME=$(basename "${BUILD_JAR_NAME}") echo "> JAR_FILE_NAME: ${JAR_FILE_NAME}"
JAVA_OPT="${JAVA_OPT} -server -Xms${JVM_XMS} -Xmx${JVM_XMX} -Xmn${JVM_XMN} -XX:MetaspaceSize=${JVM_MS} -XX:MaxMetaspaceSize=${JVM_MMS}"
if [ "${MODE_DEBUG}" = "y" ]; then JAVA_OPT="${JAVA_OPT} -Xdebug -Xrunjdwp:transport=dt_socket,address=12345,server=y,suspend=n" fi
JAVA_OPT="${JAVA_OPT} -XX:-OmitStackTraceInFastThrow -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=${BASE_DIR}/logs/java_heapdump.hprof" JAVA_OPT="${JAVA_OPT} -XX:-UseLargePages"
mkdir -p "${BASE_DIR}/logs" && touch "${BASE_DIR}/logs/gc.log" JAVA_OPT="${JAVA_OPT} -Xloggc:${BASE_DIR}/logs/gc.log -verbose:gc -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCTimeStamps -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=10 -XX:GCLogFileSize=100M"
JAVA_OPT="${JAVA_OPT} -Dfile.encoding=utf-8"
JAVA_OPT="${JAVA_OPT} -jar ${BASE_DIR}/${JAR_FILE_NAME}"
echo "This server is starting, you can docker logs your container"
echo ${JAVA_OPT}
exec $JAVA ${JAVA_OPT}
|