docker流水线

docker流水线

  • 1、安装docker
  • 2、安装docker-compose
  • 3、编写docker-compose.yml
    • [3.1 基础服务、中间件docker-compose.yml](#3.1 基础服务、中间件docker-compose.yml)
    • [3.2 应用服务docker-compose-app.yml](#3.2 应用服务docker-compose-app.yml)
  • [4、准备代码(以 RuoYi-Vue-Plus 为例)](#4、准备代码(以 RuoYi-Vue-Plus 为例))
      • [方法一:Git 命令行标准流程(推荐)](#方法一:Git 命令行标准流程(推荐))
        • [步骤 1:查看并添加原作者的仓库为 `upstream`](#步骤 1:查看并添加原作者的仓库为 upstream)
        • [步骤 2:确保你本地的修改都已经提交](#步骤 2:确保你本地的修改都已经提交)
        • [步骤 3:拉取原作者的最新代码](#步骤 3:拉取原作者的最新代码)
        • [步骤 4:合并原作者的代码到你的本地分支](#步骤 4:合并原作者的代码到你的本地分支)
        • [步骤 5:将合并后的完整结果推送到你自己的 Gitee 仓库](#步骤 5:将合并后的完整结果推送到你自己的 Gitee 仓库)
      • [方法二:在 IntelliJ IDEA 中可视化操作(最方便解冲突)](#方法二:在 IntelliJ IDEA 中可视化操作(最方便解冲突))
      • [💡 后续开发建议(最佳实践)](#💡 后续开发建议(最佳实践))
  • 5、编辑阿里云效流水线
  • 6、部署前端
  • 7、nginx配置

1、安装docker

bash 复制代码
# 移除旧版本docker
sudo yum remove docker \
                  docker-client \
                  docker-client-latest \
                  docker-common \
                  docker-latest \
                  docker-latest-logrotate \
                  docker-logrotate \
                  docker-engine
 
# 配置docker yum源。
sudo yum install -y yum-utils
sudo yum-config-manager \
--add-repo \
http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
 
 
# 安装 最新 docker
sudo yum install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
 
# 启动& 开机启动docker; enable + start 二合一
systemctl enable docker --now
 
# 配置加速
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
  "registry-mirrors": [
    "https://docker.m.daocloud.io",
    "https://dockerproxy.cn",
    "https://docker.1panel.live",
    "https://hub.rat.dev"
  ]
}
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker

2、安装docker-compose

bash 复制代码
sudo curl -L https://github.com/docker/compose/releases/download/1.24.1/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose

由于网络问题,常常安装不上,换成国内的

bash 复制代码
sudo curl -L "https://get.daocloud.io/docker/compose/releases/download/1.24.1/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose

添加可执行权限

bash 复制代码
sudo chmod +x /usr/local/bin/docker-compose

测试安装结果

bash 复制代码
docker-compose -v

3、编写docker-compose.yml

3.1 基础服务、中间件docker-compose.yml

bash 复制代码
services:
  # ==========================================
  # 1. 关系型数据库 MySQL 8.0
  # ==========================================
  mysql:
    image: mysql:8.0.42
    container_name: mysql
    restart: unless-stopped
    environment:
      TZ: Asia/Shanghai
      MYSQL_ROOT_PASSWORD: "123456"
    ports:
      - "3306:3306"
    volumes:
      - /docker/mysql/data:/var/lib/mysql
      - /docker/mysql/conf:/etc/mysql/conf.d
      - /etc/localtime:/etc/localtime:ro
    command:
      --default-authentication-plugin=mysql_native_password
      --character-set-server=utf8mb4
      --collation-server=utf8mb4_general_ci
      --explicit_defaults_for_timestamp=true
      --lower_case_table_names=1
    networks:
      - jl-net

  # ==========================================
  # 2. 高性能缓存 Redis
  # ==========================================
  redis:
    image: redis:7.2.8
    container_name: redis
    restart: unless-stopped
    environment:
      TZ: Asia/Shanghai
    ports:
      - "6379:6379"
    volumes:
      - /docker/redis/data:/data
      - /etc/localtime:/etc/localtime:ro
    command: redis-server --requirepass "123456" --appendonly yes
    networks:
      - jl-net

  # ==========================================
  # 3. 反向代理与 Web 服务 Nginx
  # ==========================================
  nginx:
    image: nginx:1.23.4
    container_name: nginx
    restart: unless-stopped
    environment:
      TZ: Asia/Shanghai
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - /docker/nginx/conf.d:/etc/nginx/conf.d
      - /docker/nginx/html:/usr/share/nginx/html
      - /docker/nginx/log:/var/log/nginx
      - /docker/nginx/webroot:/var/www/certbot:ro
      - /docker/certbot/conf:/etc/letsencrypt:ro
      - /etc/localtime:/etc/localtime:ro
    networks:
      - jl-net

  # ==========================================
  # 4. 免费 SSL 证书管理工具 Certbot
  # ==========================================
  certbot:
    image: certbot/certbot
    container_name: certbot
    volumes:
      - /docker/certbot/conf:/etc/letsencrypt
      - /docker/nginx/webroot:/var/www/certbot
    profiles:
      - tools

  # ==========================================
  # 5. 对象存储服务 MinIO
  # ==========================================
  minio:
    image: minio/minio:RELEASE.2025-04-22T22-12-26Z
    container_name: minio
    restart: unless-stopped
    environment:
      TZ: Asia/Shanghai
      MINIO_ROOT_USER: admin
      MINIO_ROOT_PASSWORD: "admin123" # 必须 >= 8 位
      MINIO_COMPRESS: "off"
      MINIO_COMPRESS_EXTENSIONS: ""
      MINIO_COMPRESS_MIME_TYPES: ""
    ports:
      - "9000:9000"  # API 端口
      - "9001:9001"  # 控制台后台端口
    volumes:
      - /docker/minio/data:/data
      - /docker/minio/config:/root/.minio
      - /etc/localtime:/etc/localtime:ro
    command: server --address ':9000' --console-address ':9001' /data
    networks:
      - jl-net

  # ==========================================
  # 6. 分布式键值存储 etcd (v3.5)
  # ==========================================
  etcd:
    image: quay.io/coreos/etcd:v3.5.15
    container_name: etcd
    restart: unless-stopped
    environment:
      TZ: Asia/Shanghai
      ETCD_NAME: etcd01
      ETCD_DATA_DIR: /etcd-data
      # 允许无鉴权访问(如需密码后续可通过 etcdctl 配置)
      ALLOW_NONE_AUTHENTICATION: "yes"
      ETCD_LISTEN_CLIENT_URLS: http://0.0.0.0:2379
      ETCD_ADVERTISE_CLIENT_URLS: http://etcd:2379
      ETCD_LISTEN_PEER_URLS: http://0.0.0.0:2380
      ETCD_INITIAL_ADVERTISE_PEER_URLS: http://etcd:2380
      ETCD_INITIAL_CLUSTER: etcd01=http://etcd:2380
      ETCD_INITIAL_CLUSTER_TOKEN: etcd-cluster-token
      ETCD_INITIAL_CLUSTER_STATE: new
    ports:
      # 客户端通信端口
      - "2379:2379"
      # 集群节点间通信端口(单节点可不映射到宿主机,仅容器内可见)
      - "2380:2380"
    volumes:
      - /docker/etcd/data:/etcd-data
      - /etc/localtime:/etc/localtime:ro
    networks:
      - jl-net

  # ==========================================
  # 7. 消息队列 Kafka (KRaft模式,无需Zookeeper)
  # ==========================================
  kafka:
    image: apache/kafka:3.8.0
    container_name: kafka
    restart: unless-stopped
    environment:
      TZ: Asia/Shanghai
      KAFKA_NODE_ID: 1
      KAFKA_PROCESS_ROLES: broker,controller
      # 控制节点仲裁者
      KAFKA_CONTROLLER_QUORUM_VOTERS: 1@kafka:9093
      # 监听器定义:内部容器用 9092,控制器用 9093,宿主机外部用 9094
      KAFKA_LISTENERS: PLAINTEXT://0.0.0.0:9092,CONTROLLER://0.0.0.0:9093,EXTERNAL://0.0.0.0:9094
      KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://kafka:9092,EXTERNAL://120.26.247.53:9094
      KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: CONTROLLER:PLAINTEXT,PLAINTEXT:PLAINTEXT,EXTERNAL:PLAINTEXT
      KAFKA_CONTROLLER_LISTENER_NAMES: CONTROLLER
      KAFKA_INTER_BROKER_LISTENER_NAME: PLAINTEXT
      # 单节点副本因子必须设置为 1
      KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1
      KAFKA_TRANSACTION_STATE_LOG_REPLICATION_FACTOR: 1
      KAFKA_TRANSACTION_STATE_LOG_MIN_ISR: 1
      KAFKA_GROUP_INITIAL_REBALANCE_DELAY_MS: 0
      KAFKA_NUM_PARTITIONS: 3
    ports:
      # 容器间走 9092,宿主机/开发工具走 9094
      - "9092:9092"
      - "9094:9094"
    volumes:
      - /docker/kafka/data:/var/lib/kafka/data
      - /etc/localtime:/etc/localtime:ro
    networks:
      - jl-net

# ==========================================
# 共享桥接网络定义
# ==========================================
networks:
  jl-net:
    # 强制将 Docker 内部网络名命名为 jl-net(防止被加上目录前缀)
    name: jl-net
    driver: bridge

Nginx 官方镜像的机制是:主配置文件 nginx.conf 内部会自动引入 /etc/nginx/conf.d/*.conf 下的所有子配置。后续想配置反向代理(比如代理若依后台),随时在宿主机的 /docker/nginx/conf.d/ 目录下丢一个 ruoyi.conf 进去,执行 docker exec nginx-web nginx -s reload 即可生效。

3.2 应用服务docker-compose-app.yml

bash 复制代码
services:  
  ruoyi-admin:
    image: ruoyi-admin:latest
    container_name: ruoyi-admin
    restart: unless-stopped
    environment:
      TZ: Asia/Shanghai
      SERVER_PORT: 8080
      SNAIL_JOB_PORT: 28080
      SNAIL_AI_PORT: 38080
    volumes:
      - /docker/ruoyi/server/logs/:/apps/logs/
      - /etc/localtime:/etc/localtime:ro
    networks:
      - jl-net

networks:
  jl-net:
    external: true

4、准备代码(以 RuoYi-Vue-Plus 为例)

https://gitee.com/dromara/RuoYi-Vue-Plus fork到自己的仓库,然后clone到本地。

在 Git 中,这种场景的标准做法是配置 upstream(上游仓库) 并进行 合并(Merge)

Git 的合并算法会把原作者的提交和你自己的修改智能融合在一起,绝不会无故覆盖你的代码

切记 :千万不要 在 Gitee 网页端直接点击仓库名旁边的 "强制同步" 按钮!

Gitee 的网页强制同步相当于 git reset --hard,会直接抹掉你自己修改的代码!必须在本地通过 Git 命令或 IDEA 进行合并。


方法一:Git 命令行标准流程(推荐)

在你的本地项目根目录下打开终端(Git Bash 或 PowerShell),按以下 5 步操作:

步骤 1:查看并添加原作者的仓库为 upstream

先查看你现有的远程仓库源:

bash 复制代码
git remote -v

此时通常只有 origin(指向你自己的 Gitee 仓库)。

原作者的项目地址 添加为上游源(命名为 upstream):

bash 复制代码
git remote add upstream https://gitee.com/原作者用户名/项目名.git

再次执行 git remote -v,确认能看到 origin(你的)和 upstream(原作者的)。


步骤 2:确保你本地的修改都已经提交

在拉取前,必须保证你本地改动的代码已经 commit(不能处于未提交的脏工作区):

bash 复制代码
git status
# 如果有未提交的文件,先暂存并提交:
git add .
git commit -m "保存我本地的修改"

步骤 3:拉取原作者的最新代码

切到你的工作分支(比如 mastermain):

bash 复制代码
git checkout master

拉取原作者仓库的更新(仅下载更新,不会影响你当前的文件):

bash 复制代码
git fetch upstream

步骤 4:合并原作者的代码到你的本地分支

把原作者最新的代码合并到你当前的分支:

bash 复制代码
git merge upstream/master
# 如果原作者的主分支叫 main,则执行:git merge upstream/main

此时会出现以下两种情况之一:

  • 情况 A(无冲突,最常见)
    如果你们修改的不是同一行代码,Git 会自动完成合并,并提示 Merge made by the 'ort' strategy,你的改动与作者的更新已经完美共存。
  • 情况 B(有冲突)
    如果你们修改了同一个文件的同一行代码 ,Git 会暂停并标记冲突文件(CONFLICT (content): Merge conflict in ...)。
    • 打开冲突文件,会看到 <<<<<<< HEAD(你的代码)和 >>>>>>> upstream/master(原作者的代码)。

    • 手工选择保留哪部分,删掉标记符号。

    • 解决后执行:

      bash 复制代码
      git add .
      git commit -m "合并上游代码并解决冲突"

步骤 5:将合并后的完整结果推送到你自己的 Gitee 仓库

合并完成后,把最新的代码推送到你自己 Gitee 的远程分支:

bash 复制代码
git push origin master

此时,你的本地仓库和你的 Gitee 远程仓库都同步到了原作者的最新版本,同时完整保留了你之前的所有代码。


方法二:在 IntelliJ IDEA 中可视化操作(最方便解冲突)

如果你更喜欢在 IDEA 中操作,IDEA 提供了非常直观的三栏(3-way)合并界面:

  1. 添加 Upstream 源
    • 顶部菜单:Git -> Manage Remotes...
    • 点击 + 号:
      • Name :填 upstream
      • URL :填原作者的 Gitee 仓库地址 -> 点击 OK
  2. 抓取更新
    • 顶部菜单:Git -> Fetch
  3. 合并代码
    • 打开右下角的分支管理器(Git Branches)。
    • Remote 下找到 upstream/master (或 upstream/main)。
    • 点击它,选择 Merge 'upstream/master' into 'master'
  4. 处理冲突(如果有)
    • 如果遇到冲突,IDEA 会弹出一个 Conflicts 对话框,点击 Merge...
    • 左边是你的代码,右边是原作者的代码,中间是合并结果。你可以点击箭头决定保留哪边,或者两边都保留。
  5. 推送到 Gitee
    • 合并完成后,按快捷键 Ctrl + Shift + K(Mac 为 Cmd + Shift + K)直接 Push 到你自己的 origin

💡 后续开发建议(最佳实践)

为了避免后续频繁遇到冲突:

  • 建议将原作者的 master 分支保持纯净,仅用于同步。

  • 自己的业务修改可以拉一个新分支开发:

    bash 复制代码
    git checkout -b my-dev

    每次原作者更新后:

    1. 切到 mastergit merge upstream/master(直接快进同步,永无冲突)。
    2. 切回 my-devgit merge master 把新特性合进自己的开发分支。

修改 application-prod.yml 然后推送到远程仓库

5、编辑阿里云效流水线

Java 构建上传 -> 执行命令

mvn clean install -Dmaven.test.skip=true

构建物上传 -> 打包路径

ruoyi-admin/target/*.jar

主机部署 -> 下载路径

/home/admin/app/ruoyi-admin/package.tgz

部署脚本

bash 复制代码
set -e
DEPLOY_DIR="/home/admin/app/ruoyi-admin"
cd ${DEPLOY_DIR} && rm -rf classes generated-sources maven-* *.original *.jar && tar zxvf ./package.tgz && rm -rf classes generated-sources maven-* *.original
cat > Dockerfile << 'EOF'
FROM bellsoft/liberica-openjdk-rocky:21.0.12-cds
ENV SERVER_PORT=8080 SNAIL_JOB_PORT=28080 SNAIL_AI_PORT=38080 LANG=C.UTF-8 LC_ALL=C.UTF-8 JAVA_OPTS="" APP_PATH=/apps PARAMS="--spring.profiles.active=prod"
WORKDIR $APP_PATH
ADD *.jar $APP_PATH/app.jar
EXPOSE ${SERVER_PORT} ${SNAIL_JOB_PORT} ${SNAIL_AI_PORT}
SHELL ["/bin/bash", "-c"]
ENTRYPOINT exec java -Djava.security.egd=file:/dev/./urandom -Dserver.port=${SERVER_PORT} -Dsnail-job.port=${SNAIL_JOB_PORT} -Dsnail-ai.port=${SNAIL_AI_PORT} -XX:+HeapDumpOnOutOfMemoryError -XX:+UseZGC ${JAVA_OPTS} -jar app.jar ${PARAMS}
EOF
docker build -t ruoyi-admin .
docker compose -f /docker/docker-compose-app.yml up -d ruoyi-admin
docker image prune -f && rm -rf ${DEPLOY_DIR}/*

服务启动成功,但是容器里面没有日志文件?

出现这种情况,通常是因为日志其实已经生成了,但没有写到 /ruoyi/server/logs 这个路径下 ,最常见的原因是相对路径问题。

你可以通过以下 2 步快速排查并解决:


第一步:排查日志实际写到了哪里

请直接在当前容器内的终端(或者重新 docker exec -it ruoyi-admin bash)执行以下命令查找 .log 文件:

bash 复制代码
# 全盘搜索 .log 结尾的文件
find / -name "*.log" 2>/dev/null

或者直接看 /apps 下面:

bash 复制代码
ls -la /apps/logs
为什么会这样?

你在 Dockerfile 中设置了:

dockerfile 复制代码
WORKDIR /apps

而若依(RuoYi)或 Spring Boot 默认的 logback.xml 中通常配置的是相对路径

xml 复制代码
<property name="log.path" value="./logs"/>  <!-- 或者 value="logs" -->

在 Linux/Java 中,相对路径是以**当前工作目录(WORKDIR)**为基准的。

因此日志实际上被写到了 /apps/logs 目录下,而不是根目录的 /ruoyi/server/logs


第二步:如何修复?(2 种方案选其一)

方案 A:直接修改 docker-compose-app.yml 的挂载路径(最简单)

把容器内的挂载路径直接改成实际生成的 /apps/logs/

yaml 复制代码
    volumes:
      - /docker/ruoyi/server/logs/:/apps/logs/
      - /etc/localtime:/etc/localtime:ro

修改后执行 docker compose -f /docker/docker-compose-app.yml up -d ruoyi-admin 重启即可。宿主机就能立即看到日志文件了。


方案 B:通过参数指定日志写入到 /ruoyi/server/logs

如果你希望保持 /ruoyi/server/logs 这个规范路径,只需在 docker-compose-app.ymlenvironment 里告诉 Spring Boot 日志输出目录:

yaml 复制代码
    environment:
      TZ: Asia/Shanghai
      SERVER_PORT: 8080
      LOG_PATH: /ruoyi/server/logs
      LOGGING_FILE_PATH: /ruoyi/server/logs

(若依会优先读取系统环境变量 LOG_PATH 作为日志输出目录)


补充检查:确认服务是否真的输出了文件日志

在宿主机执行一下:

bash 复制代码
docker logs --tail 50 ruoyi-admin

如果终端打印了 Spring Boot 启动 Banner 和文字日志,说明服务正常跑起来了。只要按照上述方案改一下挂载路径,宿主机就能同步看到所有的 .log 文件了。

6、部署前端

Node.js 构建 -> 执行脚本

npm install --registry=https://registry.npmmirror.com

npm run build:prod

主机部署 -> 下载路径

/home/admin/app/ruoyi-ui/package.tgz

部署脚本

bash 复制代码
set -e
DEPLOY_DIR="/home/admin/app/ruoyi-ui"
cd ${DEPLOY_DIR}
rm -rf html && mkdir -p html && tar zxvf ./package.tgz -C html/
[ -d "html/dist" ] && mv html/dist/* html/ && rm -rf html/dist
cat > Dockerfile << 'EOF'
FROM nginx:1.23.4-alpine
COPY html/ /usr/share/nginx/html/
RUN echo 'server { listen 80; location / { root /usr/share/nginx/html; try_files $uri $uri/ /index.html; index index.html; } }' > /etc/nginx/conf.d/default.conf
EXPOSE 80
EOF
docker build -t ruoyi-ui .
docker compose -f /docker/docker-compose-app.yml up -d ruoyi-ui
docker image prune -f && rm -rf ${DEPLOY_DIR}/*

7、nginx配置

/docker/nginx/conf.d新建default.conf

bash 复制代码
server {
    listen 80;
    server_name jlstu.vip www.jlstu.vip;

    location / {
        proxy_pass http://ruoyi-ui:80;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }

    location /prod-api/ {
        proxy_pass http://ruoyi-admin:8080/;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}

热重载外层 Nginx

bash 复制代码
docker exec -it nginx-web nginx -t && docker exec -it nginx-web nginx -s reload

如果不配置ssl证书,到此就完成了

相关推荐
十二同学啊1 小时前
Drools规则引擎:让复杂业务规则从代码中解耦
java·后端·开源
周先生FullStack2 小时前
Mac + 容器本地 MySQL/Redis 环境搭建与网络原理实战
java·spring boot·微服务·容器·架构·个人开发
吠品2 小时前
Nginx负载均衡配置与线上故障排查的一些经验
java·开发语言·数据库
边境悍匪2 小时前
蜗牛学苑 Java 智能体学习 Day44|Vue 前端项目搭建 思维导图复盘
java·开发语言·spring boot·学习·阿里云
万年咸鱼2 小时前
public class 和 class 的区别详解
java
焦虑的说说2 小时前
redis知识汇总
java·redis
Wang's Blog2 小时前
Java 接入Redis: 密码认证与远程连接配置
java·服务器·redis
SunnyDays10112 小时前
Java 拆分 Word 文档教程:按页、分页符和分节符拆分
java·word·分页·拆分