当前位置: 首页 > news >正文

Spring Boot 项目 GitLab CI/CD 自动构建并推送到 Harbor 教程

创建一条稳定、可审计的流水线:提交即构建,分支/标签分别产出测试/生产镜像,缓存加速、凭据安全、日志清晰。下面给出一篇从零到一的完整教程,并提供可直接复制使用的 .gitlab-ci.yml


前提与准备

  • 环境组件:
    • GitLab: 14+(CE/EE 或 GitLab.com)
    • GitLab Runner: Docker executor,Runner 主机已安装 Docker 并允许作业访问宿主机 Docker(通过 DOCKER_HOST=unix:///var/run/docker.sock
    • Harbor: 2.5+,已启用 HTTPS,创建了项目(如 ayy-server
  • 凭据与变量(GitLab 项目或组级 CI/CD Variables):
    • HARBOR_USER: Harbor 用户或 Robot 账户(推荐机器人账号)
    • HARBOR_PASS: 对应密码或 token(Masked、Protected)
    • SSH_PRIVATE_KEY: 若需要后续 SSH 部署(可选,Masked)
  • Runner 节点证书(如 Harbor 使用自签名证书):
    • Harbor CA: 放到 Runner 节点 /etc/docker/certs.d/192.168.0.12:5080/ca.crt,并重启 Docker
  • Dockerfile(推荐多阶段构建 + 非 root 用户):
    • 使用你已有的多阶段 Dockerfile(Maven 构建 + 精简 JRE 运行),并确保端口、配置目录、日志目录、环境变量设置合理

流水线设计与策略

  • 分支/环境策略:
    • main 分支: 产出测试镜像,标签为 test-${CI_COMMIT_SHORT_SHA}test-latest
    • tag 发布: 产出生产镜像,标签为 vX.Y.Zprod-latest(强制校验版本格式)
  • 构建缓存:
    • 使用 BuildKit 内联缓存 + “缓存镜像”标签(test-cache/prod-cache)提升二次构建速度
  • 登录与推送:
    • 每个作业在 before_script 里登录 Harbor,推送成功后清理本地镜像,保持 Runner 干净
  • 凭据安全:
    • Harbor 凭据使用变量注入,不写入仓库;变量设为 Masked + Protected
  • 可审计性:
    • 构建阶段生成 build.env(dotenv artifacts),在后续阶段复用镜像标签与环境信息

完整 .gitlab-ci.yml(可复制使用)

stages:- build- pushvariables:DOCKER_HOST: unix:///var/run/docker.sockDOCKER_BUILDKIT: "1"REGISTRY: 192.168.0.12:5080PROJECT: ayy-serverIMAGE_NAME: ayy-server-java17GIT_LFS_SKIP_SMUDGE: "1"# ==================== 公共锚点 ====================
.docker-base: &docker-baseimage: docker:20.10.24before_script:# 验证 Docker 可用(使用宿主机 Docker)- echo "使用宿主机 Docker"- docker info- docker version# 登录 Harbor- echo "$HARBOR_PASS" | docker login -u "$HARBOR_USER" --password-stdin $REGISTRY.ssh-base: &ssh-baseimage: alpine:latestbefore_script:- apk add --no-cache openssh-client curl- eval $(ssh-agent -s)- echo "$SSH_PRIVATE_KEY" | tr -d '\r' | ssh-add -- mkdir -p ~/.ssh- chmod 700 ~/.ssh# Maven 缓存(加速依赖下载)
cache:key: maven-cachepaths:- .m2/repository# ==================== 测试环境(main 分支) ====================
build-test:<<: *docker-basestage: buildscript:- export IMAGE_TAG="test-${CI_COMMIT_SHORT_SHA}"- export CACHE_IMAGE="$REGISTRY/$PROJECT/$IMAGE_NAME:test-cache"- echo "开始构建测试镜像 $IMAGE_TAG"# 尝试拉取缓存镜像- docker pull $CACHE_IMAGE || echo "缓存镜像不存在,将从头构建"# 构建镜像- |docker build \--progress=plain \--cache-from $CACHE_IMAGE \--build-arg BUILDKIT_INLINE_CACHE=1 \--build-arg BUILD_TIME=$(date -u +'%Y-%m-%dT%H:%M:%SZ') \--build-arg GIT_COMMIT=$CI_COMMIT_SHORT_SHA \-t $REGISTRY/$PROJECT/$IMAGE_NAME:$IMAGE_TAG \-t $REGISTRY/$PROJECT/$IMAGE_NAME:test-latest \-t $CACHE_IMAGE \.- echo "✓ 镜像构建成功"- docker images | grep $IMAGE_NAME# 保存构建信息- echo "IMAGE_TAG=$IMAGE_TAG" > build.env- echo "ENVIRONMENT=test" >> build.envartifacts:reports:dotenv: build.envexpire_in: 1 dayonly:- maintags:- jdk17retry:max: 2when:- runner_system_failure- stuck_or_timeout_failurepush-test:<<: *docker-basestage: pushdependencies:- build-testscript:- echo "开始推送测试镜像 $IMAGE_TAG"- docker push $REGISTRY/$PROJECT/$IMAGE_NAME:$IMAGE_TAG- docker push $REGISTRY/$PROJECT/$IMAGE_NAME:test-latest- docker push $REGISTRY/$PROJECT/$IMAGE_NAME:test-cache- echo "✓ 镜像推送成功"# 显示推送的镜像信息- echo "推送的镜像:"- echo "  - $REGISTRY/$PROJECT/$IMAGE_NAME:$IMAGE_TAG"- echo "  - $REGISTRY/$PROJECT/$IMAGE_NAME:test-latest"after_script:# 清理本地镜像- docker rmi $REGISTRY/$PROJECT/$IMAGE_NAME:$IMAGE_TAG || true- docker rmi $REGISTRY/$PROJECT/$IMAGE_NAME:test-latest || true- docker system prune -f || trueonly:- maintags:- jdk17retry:max: 2when:- runner_system_failure# ==================== 生产环境(tag 发布) ====================
build-prod:<<: *docker-basestage: buildscript:- export IMAGE_TAG="${CI_COMMIT_TAG}"- export CACHE_IMAGE="$REGISTRY/$PROJECT/$IMAGE_NAME:prod-cache"- echo "开始构建生产镜像 $IMAGE_TAG"# 验证标签格式 (v1.0.0)- |if ! echo "$IMAGE_TAG" | grep -qE '^v[0-9]+\.[0-9]+\.[0-9]+$'; thenecho "❌ 错误: 标签格式必须为 vX.Y.Z (例如: v1.0.0)"echo "当前标签: $IMAGE_TAG"exit 1fi- echo "✓ 标签格式验证通过 $IMAGE_TAG"# 尝试拉取缓存镜像- docker pull $CACHE_IMAGE || echo "缓存镜像不存在,将从头构建"# 构建镜像- |docker build \--progress=plain \--cache-from $CACHE_IMAGE \--build-arg BUILDKIT_INLINE_CACHE=1 \--build-arg BUILD_TIME=$(date -u +'%Y-%m-%dT%H:%M:%SZ') \--build-arg GIT_TAG=$CI_COMMIT_TAG \-t $REGISTRY/$PROJECT/$IMAGE_NAME:$IMAGE_TAG \-t $REGISTRY/$PROJECT/$IMAGE_NAME:prod-latest \-t $CACHE_IMAGE \.- echo "✓ 镜像构建成功"- docker images | grep $IMAGE_NAME# 保存构建信息- echo "IMAGE_TAG=$IMAGE_TAG" > build.env- echo "ENVIRONMENT=production" >> build.envartifacts:reports:dotenv: build.envexpire_in: 30 daysonly:- tagstags:- jdk17retry:max: 2when:- runner_system_failure- stuck_or_timeout_failurepush-prod:<<: *docker-basestage: pushdependencies:- build-prodscript:- echo "开始推送生产镜像 $IMAGE_TAG"- docker push $REGISTRY/$PROJECT/$IMAGE_NAME:$IMAGE_TAG- docker push $REGISTRY/$PROJECT/$IMAGE_NAME:prod-latest- docker push $REGISTRY/$PROJECT/$IMAGE_NAME:prod-cache- echo "✓ 镜像推送成功"# 显示推送的镜像信息- echo "推送的镜像:"- echo "  - $REGISTRY/$PROJECT/$IMAGE_NAME:$IMAGE_TAG"- echo "  - $REGISTRY/$PROJECT/$IMAGE_NAME:prod-latest"after_script:# 清理本地镜像- docker rmi $REGISTRY/$PROJECT/$IMAGE_NAME:$IMAGE_TAG || true- docker rmi $REGISTRY/$PROJECT/$IMAGE_NAME:prod-latest || true- docker system prune -f || trueonly:- tagstags:- jdk17retry:max: 2when:- runner_system_failure

关键点讲解与常见坑

  • Docker 访问模式:
    • 说明: 该流水线采用“使用宿主机 Docker”的模式(非 DIND 服务),通过 DOCKER_HOST=unix:///var/run/docker.sock 直接访问 Runner 主机的 Docker。优点是不需要 privileged,性能和兼容性好;缺点是需确保 Runner 主机安全与权限隔离。
  • Harbor 登录与命名:
    • 仓库路径: $REGISTRY/$PROJECT/$IMAGE_NAME:<tag>(如 192.168.0.12:5080/ayy-server/ayy-server-java17:test-latest
    • 建议: 使用项目/应用分层命名;避免顶层 library;区分 test-*prod-* 标签。
  • 构建缓存:
    • 机制: --build-arg BUILDKIT_INLINE_CACHE=1 + --cache-from <cache image> 搭配指定的缓存镜像标签,提升二次构建速度。
    • 前提: 第一次构建没有缓存是正常的;后续才会生效。
  • 版本规范校验(生产):
    • 规则: vX.Y.Z(语义化版本);不符合直接失败,避免随意发布“生产”镜像。
  • 证书与私有仓库:
    • 自签名: Runner 主机需信任 Harbor CA;如果仍报 x509,确认端口与域名一致、证书链完整,必要时将证书也挂载到作业环境。
  • 清理策略:
    • after_script: 清理构建镜像与 dangling 层,防止 Runner 主机长期磁盘膨胀。

与 Dockerfile 的配合要点

  • 构建参数联动:
    • 建议: 在 Dockerfile(构建阶段)里接受 BUILD_TIME, GIT_COMMIT/GIT_TAG,打入镜像元信息;便于审计与追溯。
  • 端口与配置:
    • 暴露端口: 与应用实际端口一致(示例为 48087)。
    • 配置目录: /app/config 支持外部挂载;流水线构建阶段不需携带敏感配置,部署时再注入。
  • 非 root 与权限:
    • 用户: 使用非 root 用户运行;确保日志目录与配置目录权限正确(避免 logback 写入失败)。

下一步:部署联动与质量门禁(可选增强)

  • 质量门禁:
    • 漏洞扫描: 在 Harbor 开启 Trivy;推送后自动扫描,发现高危阻断发布。
    • SBOM: 构建后生成 SBOM(如 Syft),存档以提升可追溯性。
  • 部署联动:
    • Kubernetes: 推送成功后,触发 Helm/Argo CD 更新;镜像标签使用 commit_sha 实现幂等与回滚。
    • VM/主机: 使用 ssh-base 锚点执行远程拉取与滚动重启脚本(确保蓝绿或最小化停机)。
http://www.dtcms.com/a/573243.html

相关文章:

  • 彻底理解传统卷积,深度可分离卷积
  • 使用VSCode进行SSH远程连接时无法与xxx建立连接
  • 宁波建设工程报名网站陕西省住房与建设厅网站
  • Rust 练习册 6:生命周期与闭包
  • 公司网站开发的流程高端企业网站公司
  • 第二届中欧科学家论坛暨第七届人工智能与先进制造国际会议(AIAM 2025)在德国海德堡成功举办
  • 微硕WSF3085 MOSFET,汽车电动尾门升降强效驱动
  • 5 Prompt Engineering 高阶技巧:构建智能对话系统的核心技术
  • 汽车系统可靠性与技术融合:智能动力总成及机电一体化诊断
  • 网站建设对企业的重要性线上营销的优势和劣势
  • JavaScript 正则表达式全方位解析:从基础到实战
  • 工业相机成像核心参数解析,帧率与曝光时间的权衡关系
  • Kodiak Perps:Berachain 原生永续合约平台上线
  • 分布式版本控制系统Git的安装和使用
  • 用.echarts文件快速实现日历饼图
  • 影刀RPA一键生成竞品分析!AI智能监控,效率提升100倍[特殊字符]
  • 从卡顿到秒查:Java 项目引入 Elasticsearch 实现亿级地址数据的复杂查询实战
  • 国外可以做推广的网站有哪些广州品牌形象设计
  • 【MySQL】SQL语法详细总结
  • 宿迁华夏建设集团网站下列什么软件不能用于设计网页
  • vue笔记(第一天)
  • cursor和传统idea的区别是什么?
  • SSM--MyBatis框架SQL映射文件获取一对一或者一对多关系值
  • 网站开发实验报告总结阿里云是不是做网站的
  • 1000元级投影选哪款?大眼橙C3D实测体验闭眼入
  • 第一章 函数与极限 2.数列的极限
  • 用ps网站首页怎么做做a免费网站有哪些
  • 多因子量化模型预警:美元强势因子压制金价失守4000关口,ADP数据能否重构黄金趋势?
  • Mac 安装 Xcode 及qt 环境安装
  • AS2协议的实时性:重构制造业供应链协同效率