GitLab Runner 是 GitLab CI/CD 自动化流水线的核心执行载体,是专门用来执行 GitLab 仓库中 CI/CD 任务的独立运行代理程序。
GitLab 本身仅负责流水线规则配置、任务调度、流程管理与版本代码托管,并不直接运行编译、打包、镜像构建、镜像推送、项目部署、自动化测试等实际作业;而 GitLab Runner 可部署在任意服务器、物理机、虚拟机或 Docker 容器中,主动向 GitLab 服务轮询待执行的流水线任务,按照预设的 .gitlab-ci.yml 脚本,自动完成代码拉取、项目编译、Docker 镜像构建、推送至 Harbor 私有仓库、应用容器化部署等全流程自动化工作。
它支持分布式部署、多运行器并行执行、多环境隔离,兼容 Shell、Docker、Kubernetes 等多种执行器模式,是打通 GitLab 代码提交到自动构建、自动打包、自动部署落地的关键基础设施,也是企业落地研发自动化、持续集成与持续交付的必备组件。
为了实现自动构建流水线,我们需要先将我们的项目构建成 Docker 镜像,需要编写 Dockerfile 文件

在项目根目录创建一个名为 devops 的目录,并创建两个配置文件
在 devops 目录下创建名为 Dockerfile 的文件
# ===================== 阶段 1:项目构建阶段(Maven 打包) =====================
# 基础镜像:Maven 3.9.15 + JDK21 环境(仅用于打包,最终不会打包进生产镜像)
# AS builder:给当前阶段命名,方便后续复制打包好的 jar 包
FROM maven:3.9.15-eclipse-temurin-21 AS builder
# 设置容器内的工作目录为 /app
# 后续所有复制、执行命令都基于这个目录,简化路径
WORKDIR /app
# 复制 Maven 私服配置文件
# 路径说明:构建上下文是项目根目录,所以文件路径为 devops/settings.xml
# 作用:让 Maven 从你的私有仓库 192.168.203.132 下载依赖
COPY devops/settings.xml /root/.m2/settings.xml
# 复制项目根目录下的所有文件
# 适配模块化项目:一次性复制所有子模块
COPY . .
# 执行 Maven 打包命令
# clean:清空旧的打包文件
# package:编译+打包项目
# -DskipTests:跳过单元测试(加速构建,避免测试报错)
# -Pprod:启用生产环境配置(加载 prod 环境参数)
RUN mvn clean package -DskipTests -Pprod
# ===================== 阶段 2:生产运行阶段(极小体积,仅含 JRE) =====================
# 基础镜像:eclipse-temurin-21-jre-alpine(轻量级生产运行环境,只有 JRE,无多余依赖)
# 多阶段构建核心优势:最终镜像只保留运行环境,体积减少 80% 以上
FROM eclipse-temurin:21-jre-alpine
# 容器工作目录,与构建阶段保持一致
WORKDIR /app
# 安全 + 权限核心配置(合并为一条 RUN,减少镜像层数)
# 1. addgroup -S app:创建系统用户组 app
# 2. adduser -S app -G app:创建系统用户 app 并加入用户组(禁止 root 运行,提升容器安全性)
# 3. mkdir -p /home/ruoyi/logs:手动创建框架默认的日志目录(解决日志目录不存在报错)
# 4. chown -R app:app /home/ruoyi:修改日志目录归属权(解决非 root 用户无权限写入日志)
RUN addgroup -S app && adduser -S app -G app && \
mkdir -p /home/ruoyi/logs && \
chown -R app:app /home/ruoyi
# 从构建阶段(builder)复制打包好的 jar 包到当前生产镜像
# 路径固定:启动模块为 ruoyi-admin/target/*.jar
COPY --from=builder /app/ruoyi-admin/target/*.jar app.jar
# 声明容器暴露的端口(Spring Boot 默认 8080,仅声明,不实际发布端口)
EXPOSE 8080
# 容器启动命令:固定格式运行 Spring Boot jar 包
ENTRYPOINT ["java", "-jar", "app.jar"]还需要创建 settings.xml 配置文件,用于构建时 Maven 连接私服
<settings>
<servers>
<server>
<id>maven-public</id>
<username>admin</username>
<password>12345678</password>
</server>
<server>
<id>maven-release</id>
<username>admin</username>
<password>12345678</password>
</server>
<server>
<id>maven-snapshots</id>
<username>admin</username>
<password>12345678</password>
</server>
</servers>
<mirrors>
<mirror>
<!-- 注意这里的 ID 需要匹配上面 Server 元素的 ID,用于配置 Nexus 的账号密码 -->
<id>maven-public</id>
<url>http://192.168.203.132:8081/repository/maven-public/</url>
<mirrorOf>*</mirrorOf>
</mirror>
</mirrors>
</settings>修改完成后提交代码,进入远程服务器的项目目录,使用 git pull 命令拉取最新代码
在项目根目录执行构建命令
# -t 192.168.203.133/library/myproject:latest 作用:构建后可直接推送到私有仓库
# -t:给镜像打标签(名字 + 版本)
# 192.168.203.133:你的 Harbor 私有仓库地址
# library/myproject:镜像名称
# latest:镜像版本(最新版)
docker build --network host -f devops/Dockerfile -t 192.168.203.133/library/myproject:latest .命令最后一个
.的作用
当前执行命令的目录(项目根目录)
告诉 Docker 从项目根目录读取代码
必须用根目录作为上下文
构建成功会看到如下内容

最后推送镜像到私服
第一次推送需要先信任私有仓库:vi /etc/docker/daemon.json
{
"insecure-registries": ["192.168.203.133"]
}配置完成后重启 Docker
systemctl daemon-reload
systemctl restart docker再执行以下操作
# 1. 登录 Harbor
docker login 192.168.203.133 -u admin -p bitnami
# 2. 推送镜像
docker push 192.168.203.133/library/myproject:latest
# 3. 退出登录(可选,生产环境建议退出)
docker logout 192.168.203.133
登录 Harbor 查看已推送的镜像

主要修改容器脚本的镜像
services:
myproject:
image: 192.168.203.133/library/myproject:latest
container_name: myproject
ports:
- "8080:8080"
environment:
- TZ=Asia/Shanghai
- REDIS_HOST=192.168.203.129
- REDIS_PORT=6379
- REDIS_PASSWORD=123456
- MYSQL_HOST=192.168.203.129
- MYSQL_PORT=3306
- MYSQL_DATABASE=ry-vue
- MYSQL_USERNAME=root
- MYSQL_PASSWORD=123456
restart: always
volumes:
# 映射日志目录
- ./logs:/home/ruoyi/logs
进入 ruoyi-ui 目前创建 Dockerfile 配置文件
# ===================== 阶段 1:前端构建阶段 =====================
# 基础镜像:Node 22 轻量版
FROM node:22-alpine AS builder
# 设置容器工作目录
WORKDIR /app
# ===================== 国内镜像加速 =====================
# Yarn 依赖镜像:阿里云
ENV YARN_REGISTRY=https://registry.npmmirror.com
# Node-Sass 二进制镜像:阿里云
ENV SASS_BINARY_SITE=https://npmmirror.com/mirrors/node-sass/
# 复制依赖文件
COPY package.json yarn.lock ./
# 安装项目依赖
RUN yarn install --frozen-lockfile
# 复制前端所有源代码
COPY . .
# 执行前端生产打包命令
RUN yarn build:prod
# ===================== 阶段 2:生产运行阶段 =====================
# 基础镜像:Nginx
FROM nginx:1.26.2-alpine
# 删除 Nginx 默认配置,避免冲突
RUN rm -rf /etc/nginx/conf.d/default.conf
# 复制构建好的前端静态资源(dist目录)到 Nginx 访问目录
COPY --from=builder /app/dist /usr/share/nginx/html
# 复制自定义 Nginx 配置
COPY nginx.conf /etc/nginx/conf.d/ui.conf
# 声明前端访问端口
EXPOSE 80
# 后台启动 Nginx
CMD ["nginx", "-g", "daemon off;"]创建 nginx.conf 配置,需要特别注意 location /prod-api/ 部分的配置
server {
listen 80;
server_name localhost;
root /usr/share/nginx/html;
index index.html;
# 若依前端路由模式:解决刷新 404 问题
location / {
try_files $uri $uri/ /index.html;
}
# 接口反向代理(根据后端地址配置)
location /prod-api/ {
# 注意:这里反代的是容器脚本里服务的名字
proxy_pass http://myproject:8080/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
# 静态资源缓存
location ~* \.(js|css|png|jpg|jpeg|gif|ico)$ {
expires 7d;
}
}修改完成后提交代码,进入远程服务器的项目目录,使用 git pull 命令拉取最新代码
在 ruoyi-ui 目录执行构建命令
docker build --network host -t 192.168.203.133/library/myproject-nginx:latest .# 1. 登录 Harbor
docker login 192.168.203.133 -u admin -p bitnami
# 2. 推送镜像
docker push 192.168.203.133/library/myproject-nginx:latest
# 3. 退出登录(可选,生产环境建议退出)
docker logout 192.168.203.133services:
myproject:
image: 192.168.203.133/library/myproject:latest
container_name: myproject
ports:
- "8080:8080"
environment:
- TZ=Asia/Shanghai
- REDIS_HOST=192.168.203.129
- REDIS_PORT=6379
- REDIS_PASSWORD=123456
- MYSQL_HOST=192.168.203.129
- MYSQL_PORT=3306
- MYSQL_DATABASE=ry-vue
- MYSQL_USERNAME=root
- MYSQL_PASSWORD=123456
restart: always
volumes:
# 映射日志目录
- ./logs:/home/ruoyi/logs
myproject-nginx:
image: 192.168.203.133/library/myproject-nginx:latest
container_name: myproject-nginx
ports:
- "80:80"
restart: always