前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【随手记】GitLab-CI?拿来吧你!

【随手记】GitLab-CI?拿来吧你!

作者头像
客怎眠qvq
发布2024-03-28 09:57:44
970
发布2024-03-28 09:57:44
举报
文章被收录于专栏:某菜鸟の小屋某菜鸟の小屋

前言

书接【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

代码语言:javascript
复制
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} # cache键值对 减少mvn下载jar包的时间 key指向当前项目分支
  paths:
    - ~/.m2/repository/ # 缓存地址 镜像根目录下的 .m2/repository/ 文件夹
    - target/

# CI构建两步
stages:
  - package
  - release

# 在maven镜像中构建jar包
package:
  image: maven:3.6.1-jdk-8-alpine
  stage: package
  only:
    - master # 触发构建的分支
  tags:
    - docker
  script:
    - cd test-common # 进入common模块打包
    - mvn -s $MAVEN_CLI_OPTS -e package install # 打包 并将打包后生成的jar下载至 镜像根目录.m2/repository/路径下(本地仓库)
    - cd ../test-app # 切出common 打包其他模块
    - mvn -s $MAVEN_CLI_OPTS -e package
  artifacts: # 构建好的jar文件上传 并设置过期时间
    paths:
      - test-app/target/test-app-application-exec.jar
    expire_in: 1 hours

release: # docker in docker 在docker中构建jar为docker镜像
  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镜像标签
    - docker push test.com/test-image/test-app:$RELEASE_TAG # 推送

进阶

问题描述

目前的业务需求是,在原maven项目的基础上,根目录增加了同级的模块,需要分模块构建,并且每次提交代码只对产生变更的模块进行打包

文件夹树如下:

代码语言:javascript
复制
|---.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

代码语言:javascript
复制
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"
  # .m2文件夹在代码的根目录 模块在 下两层 比如 moudle/hr moudle/manage 所以需要跳出两次
  MAVEN_CLI_OPTS: "../../.m2/settings.xml --batch-mode -Dmaven.repo.local=$CI_PROJECT_DIR/.m2/repository"

#cache:
#  key: ${CI_COMMIT_REF_SLUG}
#  paths:
#    这是第一次的缓存配置 路径错误 因为已经指明了maven 安装jar包的地址 
#    为 maven.repo.local=$CI_PROJECT_DIR/.m2/repository
#    - ~/.m2/repository/
#    - target/
#    - /usr/share/maven
#    - /root/.m2/repository
cache:
  key: m2-repo
  paths:
    # 这两个地址是等效的 都指向服务器的 /builds/username/projectName/.m2/repository
    - .m2/repository/
    - $CI_PROJECT_DIR/.m2/repository

stages:
  - package
  - release

package:
  # 单纯maven不行 我用java带maven很合理吧 java镜像有apt-get 这很河狸吧
  image: labelinsight/java-maven:3.6-jdk-8
  stage: package
  only:
    - dev
  tags:
    - docker
  before_script:
    - apt-get install -y git
  script:
    # git diff 命令判断模块是否发生变更 并判断是否发生在对应的 hr manage 模块下
    - 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:
    # - apk add git 判断文件是否存在 不用装git了
    # $REPOS_PASSWORD 为管理员提前设置好的系统变量
    - docker login --username=username -p $REPOS_PASSWORD docker.repos.cscec81.com:4433
  script:
    - df -h
    # 打标签 --build-arg 传变量 变量名为 BUILD_JAR_NAME  对应值是开始在 variables部分 设定好的
    # 推送至 私有的docker镜像仓库
    - 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;

# 如果有更多模块 按照 加变量 -> 加git diff -> 加产物 -> 加判断推送 的流程,ctrl c v 就行了

dockerfile

代码语言:javascript
复制
#FROM openjdk:8-jre
FROM openjdk:8-jdk

# docker build 时传入的变量
ARG BUILD_JAR_NAME

# 配置JVM参数
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

# 测试环境配置 部署时注释掉 从rancher配置
# 如果使用 请换成你自己的ip 和 密码
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}"
# 注意 RUN命令的运行结果变量JAR_FILE_NAME 是局部变量 到下一层读取的话是 null
# 所以我直接将 docker build 传入的 BUILD_JAR_NAME 变量作为环境变量,在启动脚本 startup.sh 中处理了


# 拷贝jar包 及 脚本
COPY $BUILD_JAR_NAME ./startup.sh $BASE_DIR/

RUN chmod +x startup.sh

ENTRYPOINT ["sh","startup.sh"]

startup.sh

代码语言:javascript
复制
#!/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}"
# debug 模式下参数配置(传输、端口号、调试服务器、不在 JVM 启动时暂停,而是等待调试器连接后再开始执行。)
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"

# 配置文件编码 Redis等ip和密码 启动jar包
JAVA_OPT="${JAVA_OPT} -Dfile.encoding=utf-8"
#JAVA_OPT="${JAVA_OPT} -DMYSQL_HOST=${MYSQL_HOST} -DMYSQL_PORT=${MYSQL_PORT} -DMYSQL_SERVICE_DB_NAME=${MYSQL_SERVICE_DB_NAME} -DMYSQL_SERVICE_PASSWORD=${MYSQL_SERVICE_PASSWORD}"
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}

本文参与?腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2024-03-27,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客?前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与?腾讯云自媒体分享计划? ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 基础(可跳过)
    • 问题描述
      • 解决方案
      • 进阶
        • 问题描述
          • 解决方案
            • 配置文件
            相关产品与服务
            容器服务
            腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
            http://www.vxiaotou.com