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

gitlab+portainer 实现Ruoyi Vue后端CI/CD

1. 场景

最近整了一个Ruoyi Vue 项目,需要实现CICD,经过一番坎坷,最终达成,现将技术要点和踩坑呈现。
项目结构如下:
在这里插入图片描述

2. 项目配置

项目中需要配置两个文件:.gitlab-ci.yml,Dockerfile,都放在项目的根目录下,
注意: REGISTRY_URL: “harbor.xxxx.com/ics” 指向具体的仓库中的地址.

2.1 .gitlab-ci.yml

内容如下

stages:- build- packagevariables:# 镜像名称和标签(根据需求修改)IMAGE_NAME: "ics-java"IMAGE_TAG: "$CI_COMMIT_SHORT_SHA"  # 使用 Git 提交哈希作为标签# 目标仓库地址(示例为 GitLab 内置仓库,私有仓库需替换)REGISTRY_URL: "harbor.xxxx.com/ics"# 缓存 Maven 依赖加速构建
cache:paths:- .m2/repository# 阶段 1:Maven 打包和测试
build:stage: buildscript:- mvn packageartifacts:paths:- ics-server/target/*.jar  # 传递 JAR 文件到后续阶段# 阶段 2:构建和推送 Docker 镜像
docker-build:stage: package# image: docker:20.10# services:#   - docker:20.10-dind  # 启用 Docker-in-Dockerscript:# 1. 登录镜像仓库(支持 GitLab 内置仓库或第三方仓库)# 服务器的 docker 始终是登录状态,下面一行就不需要了# - echo "$DOCKER_PASSWORD" | docker login --username "$DOCKER_USERNAME" --password-stdin "$DOCKER_REGISTRY"# 2. 构建镜像(使用多阶段 Dockerfile)- docker build -t "$REGISTRY_URL/$IMAGE_NAME:$IMAGE_TAG" .# 3. 推送镜像- docker push "$REGISTRY_URL/$IMAGE_NAME:$IMAGE_TAG"# 可选:额外推送 latest 标签- docker tag "$REGISTRY_URL/$IMAGE_NAME:$IMAGE_TAG" "$REGISTRY_URL/$IMAGE_NAME:latest"- docker push "$REGISTRY_URL/$IMAGE_NAME:latest"# 仅 main 分支或标签触发rules:- if: $CI_COMMIT_BRANCH == "master"
2.2 Dockerfile 内容

这里一定不要在Dockerfile 中对项目进行打包操作,Docker 会让你手动配置 COPY结构化的依赖pom.xml,Ruoyi 后端恰好是个多模块的树状结构,这很难,后续可能还有其他问题,请勿踩坑。
在.gitlab-ci.yml 中配置项目打包即可。

# 运行时阶段/这里有改动
FROM eclipse-temurin:8-jre
WORKDIR /app
COPY ics-server/target/*.jar ics-java.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "ics-java.jar"]

3. gitlab 仓库端

3.1 在这里配置 .gitlab-ci.yml 中的变量,变量可以继承。

在这里插入图片描述

3.2 构建成后的效果图

在这里插入图片描述

4. harbor.com 镜像仓库端

需要先新建一个项目:
在这里插入图片描述
推送成功效果和命令
在这里插入图片描述

5. Portainer 端

5.1 stack 配置 docker-compose

在这里插入图片描述

5.2 拉取镜像

注意镜像地址:
在这里插入图片描述

5.3 启动镜像,运行容器

具体的镜像与容器的操作在下面这个页面
在这里插入图片描述
如果 restart 没有反应,可以先 stop再remove,再去stack 中点击 update 按钮即可:
在这里插入图片描述

http://www.xdnf.cn/news/6472.html

相关文章:

  • Trae 插件 Builder 模式:从 0 到 1 开发天气查询小程序,解锁 AI 编程新体验
  • 全面掌握JSR303校验:从入门到实战
  • 安全牛报告解读《低空经济发展白皮书(3.0)安全体系》
  • React事件机制
  • antd mobile 点击 TabBar 切换页面
  • 工业4.0神经嫁接术:ethernet ip转profinet协议通信步骤图解
  • 【数据挖掘笔记】兴趣度度量Interest of an association rule
  • AI大模型学习二十四、实践QEMU-KVM 虚拟化:ubuntu server 25.04 下云镜像创建Ubuntu 虚拟机
  • [6-8] 编码器接口测速 江协科技学习笔记(7个知识点)
  • ES常识8:ES8.X如何实现热词统计
  • 微服务概述
  • 量子隧穿:PROFINET到Ethernet ip的无损耗协议转换方案转
  • 【寻找Linux的奥秘】第五章:认识进程
  • salesforce如何导出所有字段
  • SQL注入---05--跨站注入
  • 解决Mongoose “Cannot overwrite model once compiled“ 错误的完整指南
  • pytest多种断言类型封装为自动化断言规则库
  • 宝元LNC数控数据采集方式、跨平台采集通讯方案介绍
  • 每日算法-250515
  • 联合建模组织学和分子标记用于癌症分类|文献速递-深度学习医疗AI最新文献
  • Kafka快速安装与使用
  • 2900. 最长相邻不相等子序列 I
  • 【鸿蒙开发】性能优化
  • GPT-4o 遇强敌?英伟达 Eagle 2.5 视觉 AI 王者登场
  • Python中常用的数据类型
  • 特种设备事故背后,叉车智能监控系统如何筑牢安全防线
  • DeepSeek 赋能物联网:从连接到智能的跨越之路
  • Python类的力量:第五篇:魔法方法与协议——让类拥有Python的“超能力”
  • 【C语言】初阶数据结构相关习题(二)
  • 判断数据的所有属性是否都是基本类型