Bläddra i källkod

dev环境配置.

dujian 1 dag sedan
förälder
incheckning
6a853b95ce

+ 387 - 0
docs/devops/dev/Introduction.md

@@ -0,0 +1,387 @@
+# 开发环境(deve)运维说明
+
+本文档描述与 **测试环境(sit/test)** 并行运行的 **开发环境** 的设计、部署与日常运维。配置脚本位于仓库 `docs/devops/dev/`。
+
+---
+
+## 1. 环境与目标
+
+| 环境 | Git 分支 | Spring Profile | 宿主机 Java 目录 | 说明 |
+|------|----------|----------------|------------------|------|
+| 测试 sit | `sit` | `test` | `/docker/java` | 现有联调 / 测试 |
+| **开发 deve** | **`deve`** | **`dev`** | **`/deve/java`** | 本环境 |
+
+开发环境目标:
+
+- 与 test **共用中间件**(MySQL、Nacos、RocketMQ、xxl-job-admin、Jenkins),节省资源
+- Java 服务、Redis、业务库、Nacos 命名空间 **隔离**,避免 dev 污染 test
+- Jenkins **按需构建**微服务,默认 `gateway + store + second`
+- 开发者可用 IDEA 直连 dev 中间件,或在服务器跑 `java-dev` 容器联调
+
+---
+
+## 2. 架构概览
+
+```mermaid
+flowchart TB
+  subgraph host["测试机 120.26.186.130"]
+    subgraph mw["/docker/middleware 共用"]
+      MySQL[(MySQL 30001)]
+      Nacos[Nacos 8848]
+      RMQ[RocketMQ]
+      XXL[xxl-job-admin 30019]
+      RedisTest[redis 30002]
+      Jenkins[Jenkins 30003]
+      Nginx[Nginx 80/443]
+    end
+
+    subgraph mwdev["/docker/middleware-dev 增补"]
+      RedisDev[redis-dev 20022]
+    end
+
+    subgraph test["/docker/java 测试"]
+      GWt[gateway :8000 profile=test]
+    end
+
+    subgraph dev["/deve/java 开发"]
+      GWd[gateway-dev :28000 profile=dev]
+    end
+  end
+
+  GWt --> Nacos
+  GWd --> Nacos
+  GWt --> RedisTest
+  GWd --> RedisDev
+  GWt --> MySQL
+  GWd --> MySQL
+  Jenkins --> dev
+  Nginx --> GWt
+  Nginx --> GWd
+```
+
+---
+
+## 3. 隔离矩阵
+
+| 资源 | 测试 | 开发 | 隔离方式 |
+|------|------|------|----------|
+| MySQL 实例 | 共用 `mysql:3306` | 共用 | **不同 database**(dev 库) |
+| Nacos | namespace `acd615de-…` | **public / dev 命名空间** | `bootstrap-test.yml` vs `bootstrap-dev.yml` |
+| Redis | `redis-6.0.8` `30002` | **`redis-dev` `20022`** | 独立实例 + 独立数据目录 |
+| RocketMQ | 共用 | 共用 | consumer group / topic 前缀在 Nacos 区分 |
+| xxl-job-admin | 共用 `30019` | 共用 | **执行器 appname + 回调端口** 区分 |
+| Java 容器 | `gateway`… | `gateway-dev`… | 独立 compose、端口 `28xxx` |
+| 日志 | `/docker/java/logs` | `/deve/java/logs` | 独立目录 |
+
+---
+
+## 4. 服务器目录与仓库对应
+
+### 4.1 宿主机路径
+
+```text
+/docker/middleware/              # 测试中间件(已有)
+/docker/middleware-dev/          # 开发增补中间件(redis-dev)
+/docker/java/                    # 测试 Java 服务
+/deve/java/                      # 开发 Java 服务(compose + jar + logs)
+```
+
+首次部署建议从仓库复制:
+
+```bash
+# 开发 Java
+mkdir -p /deve/java
+cp docs/devops/dev/java/docker-compose.yml /deve/java/
+mkdir -p /deve/java/gateway /deve/java/store /deve/java/second \
+         /deve/java/store-platform /deve/java/lawyer /deve/java/job /deve/java/dining \
+         /deve/java/logs/gateway /deve/java/logs/store ...
+
+# 开发 Redis
+mkdir -p /docker/middleware-dev
+cp -r docs/devops/dev/middleware/* /docker/middleware-dev/
+```
+
+### 4.2 仓库文件索引
+
+| 路径 | 说明 |
+|------|------|
+| `docs/devops/dev/Introduction.md` | 本文档 |
+| `docs/devops/dev/java/docker-compose.yml` | 7 个 Java 微服务 compose |
+| `docs/devops/dev/java/Jenkinsfile` | Jenkins 流水线(Pipeline from SCM) |
+| `docs/devops/dev/middleware/docker-compose.yml` | redis-dev |
+| `docs/devops/dev/middleware/redis-dev/conf/redis.conf` | dev Redis 配置 |
+
+---
+
+## 5. 端口一览
+
+### 5.1 Java 服务(宿主机 → 容器)
+
+| 服务 | 容器名 | compose 服务名 | 宿主机端口 | 容器端口 | Profile |
+|------|--------|----------------|------------|----------|---------|
+| gateway | `gateway-dev` | `gateway` | **28000** | 8000 | dev |
+| store | `store-dev` | `store` | **28004** | 30004 | dev |
+| second | `second-dev` | `second` | **28005** | 30005 | dev |
+| store-platform | `store-platform-dev` | `store-platform` | **28006** | 30006 | dev |
+| lawyer | `lawyer-dev` | `lawyer` | **28007** | 30007 | dev |
+| job | `job-dev` | `job` | **28008** / **28018** | 30008 / 9999 | dev |
+| dining | `dining-dev` | `dining` | **28014** | 30014 | dev |
+
+对比测试环境:gateway `8000`,store `30004`,job 回调 `30018`。
+
+### 5.2 中间件(开发相关)
+
+| 组件 | 宿主机端口 | 容器内访问(app-network) |
+|------|------------|---------------------------|
+| redis-dev | **20022** | `redis-dev:6379` |
+| MySQL(共用) | 30001 | `mysql:3306` |
+| Nacos(共用) | 8848 | `nacos-2.5.2:8848` |
+| xxl-job-admin(共用) | 30019 | `xxl-job-admin:8080` |
+
+---
+
+## 6. 部署步骤
+
+### 6.1 前置条件
+
+```bash
+docker network inspect app-network   # 须已存在(middleware 创建)
+```
+
+### 6.2 启动 redis-dev
+
+```bash
+cd /docker/middleware-dev
+docker compose up -d
+docker exec redis-dev redis-cli -a Alien123456 ping
+```
+
+### 6.3 启动 Java 服务
+
+日常最小集(约 2~2.5GB 额外内存):
+
+```bash
+cd /deve/java
+docker compose up -d gateway store second
+```
+
+全量:
+
+```bash
+cd /deve/java
+docker compose up -d
+```
+
+### 6.4 Jenkins 容器挂载(必配)
+
+在 `/docker/middleware/docker-compose.yml` 的 `jenkins` 服务中增加:
+
+```yaml
+volumes:
+  - /deve/java:/deve/java          # dev 部署目录
+  # 已有:../java:/app_deploy、docker.sock 等
+```
+
+---
+
+## 7. Nacos 配置(dev 命名空间)
+
+`spring.profiles.active=dev` 读取 `bootstrap-dev.yml`(默认 **public** 命名空间,与 test 的 `acd615de-…` 分离)。
+
+在 dev 命名空间 `common.yml`(及 `alien-job` 等)中确认:
+
+```yaml
+spring:
+  datasource:
+    url: jdbc:mysql://mysql:3306/<dev库名>?...
+  redis:
+    host: redis-dev
+    port: 6379
+    password: Alien123456
+
+xxl:
+  job:
+    admin:
+      addresses: http://xxl-job-admin:8080/xxl-job-admin
+    accessToken: default_token
+    executor:
+      appname: alien-job-dev          # 与 test 的 alien-job 区分
+      ip: 120.26.186.130
+      port: 28018                     # 宿主机映射端口(非容器内 9999)
+      logpath: /app/logs
+```
+
+RocketMQ:为 dev 配置独立 `consumer.group` 前缀,避免与 test 抢消费。
+
+---
+
+## 8. xxl-job 共用 Admin 的隔离
+
+共用 **一个** `xxl-job-admin`(`30019`),通过 **执行器** 隔离:
+
+| 项 | test (`job`) | dev (`job-dev`) |
+|----|--------------|-----------------|
+| executor.appname | `alien-job` | **`alien-job-dev`** |
+| 回调地址 | `120.26.186.130:30018` | **`120.26.186.130:28018`** |
+| 业务库 | test 库 | dev 库(profile=dev) |
+
+控制台操作:
+
+1. 「执行器管理」中应看到两组:`alien-job` 与 `alien-job-dev` 均 **在线**
+2. dev 定时任务绑定 **`alien-job-dev`** 执行器;test 任务绑定 `alien-job`
+3. dev 任务默认可 **停止**,联调时再启用
+
+验证:
+
+```bash
+curl -s -o /dev/null -w "%{http_code}" http://127.0.0.1:28018/
+curl -s -o /dev/null -w "%{http_code}" http://127.0.0.1:30018/
+```
+
+---
+
+## 9. Jenkins 流水线
+
+### 9.1 Job 配置
+
+| 项 | 值 |
+|----|-----|
+| 类型 | Pipeline script from SCM |
+| 仓库 | `http://8.152.195.41:3000/alien/alien_cloud` |
+| 默认分支 | `*/deve` |
+| Script Path | **`docs/devops/dev/java/Jenkinsfile`** |
+
+保存后执行一次构建以注册参数。
+
+### 9.2 构建参数
+
+| 参数 | 默认 | 说明 |
+|------|------|------|
+| `GIT_BRANCH` | `deve` | 可改分支 |
+| `STOP_ALL` | `false` | 为 true 时先 `docker compose stop` 全部 dev 服务 |
+| `DEPLOY_gateway` | **true** | |
+| `DEPLOY_store` | **true** | |
+| `DEPLOY_second` | **true** | |
+| `DEPLOY_store_platform` | false | |
+| `DEPLOY_lawyer` | false | |
+| `DEPLOY_job` | false | |
+| `DEPLOY_dining` | false | |
+
+规则:
+
+- 至少勾选一个微服务
+- `STOP_ALL=true` 时 **必须勾选 gateway**
+- 流水线:`Checkout → [Stop All] → Maven(-pl 勾选模块 -am) → 拷贝 jar 到 /deve/java → compose up -d + restart`
+
+### 9.3 与 sit 任务对比
+
+| sit | deve |
+|-----|------|
+| 脚本写在 Job 内 | SCM `Jenkinsfile` |
+| 分支 `sit` | 参数 `GIT_BRANCH`,默认 `deve` |
+| 全量构建部署 | 按需模块 |
+| `/app_deploy` + `docker restart` | `/deve/java` + `docker compose` |
+
+---
+
+## 10. 内存与资源建议
+
+基于测试机 `docker stats`(7 个 test Java 合计约 5.6GB RSS,宿主机约 10GB 可用):
+
+| 策略 | 服务 | 大约额外内存 |
+|------|------|--------------|
+| **日常推荐** | gateway + store + second | ~2~2.5 GB |
+| 全链路 | 7 个 Java | ~4.5~5.5 GB |
+
+dev compose 默认:`mem_limit` 800M(store 700M),`-Xmx384m`。`store-dev` 为最重模块,若 OOM 可适当提高 `mem_limit` 或 `-Xmx`。
+
+---
+
+## 11. 日常运维命令
+
+```bash
+# 查看 dev 容器状态
+cd /deve/java && docker compose ps
+
+# 查看内存
+docker stats --no-stream gateway-dev store-dev job-dev --format "table {{.Name}}\t{{.MemUsage}}\t{{.MemPerc}}"
+
+# 重启单个服务
+cd /deve/java && docker compose restart store
+
+# 停止全部 dev Java(不影响 test)
+cd /deve/java && docker compose stop
+
+# 日志
+tail -f /deve/java/logs/store/alien-store/*.log
+docker logs -f store-dev --tail 200
+
+# 健康检查
+curl -s http://127.0.0.1:28000/actuator/health
+```
+
+### 日志备份示例
+
+```bash
+tar -czf /tmp/alien-store-logs-$(date +%Y%m%d-%H%M%S).tar.gz \
+  -C /deve/java/logs/store alien-store
+```
+
+---
+
+## 12. 本地 IDEA 直连
+
+不启动服务器 Java 容器时,可本地起单个服务并连 dev 中间件:
+
+| 配置项 | 值 |
+|--------|-----|
+| `spring.profiles.active` | `dev` |
+| MySQL | `120.26.186.130:30001`,dev 库 |
+| Redis | `120.26.186.130:20022`,密码 `Alien123456` |
+| Nacos | `120.26.186.130:8848`,dev 命名空间 |
+
+**勿**使用 test 的 Nacos namespace,避免注册到 test 服务发现。
+
+---
+
+## 13. Nginx(待配置)
+
+在现有 `nginx-1.28` 的 `conf.d` 中增加 dev 入口(示例):
+
+```nginx
+upstream dev_gateway { server 127.0.0.1:28000; }
+
+server {
+    listen 443 ssl;
+    server_name dev.ailien.shop;
+    location / {
+        proxy_pass http://dev_gateway;
+    }
+}
+```
+
+静态资源建议独立目录,例如 `/docker/middleware/nginx/html-dev`。
+
+---
+
+## 14. 常见问题
+
+| 现象 | 可能原因 | 处理 |
+|------|----------|------|
+| dev 请求打到 test 服务 | Profile 仍为 `test` 或 Nacos namespace 错误 | 确认 `-Dspring.profiles.active=dev` |
+| Redis 认证失败 | Nacos 未配 password | `common.yml` 补 `Alien123456` |
+| xxl-job 回调失败 | executor.port 写成 9999 | 宿主机侧应为 **28018** |
+| Jenkins 部署 jar 失败 | 未挂载 `/deve/java` | 检查 jenkins volumes |
+| 新 jar 不生效 | 仅 `up -d` 未 restart | 流水线已 `up -d` + `restart`;手工同理 |
+| `STOP_ALL` 后网关不通 | 未勾选 gateway | 勾选 `DEPLOY_gateway` |
+| 构建参数无复选框 | Job 有旧的手动参数冲突 | 删除 Job 内重复参数,重新保存 Job |
+
+---
+
+## 15. 变更记录
+
+| 日期 | 说明 |
+|------|------|
+| 2026-06 | 初版:dev Java compose、redis-dev、Jenkinsfile、本文档 |
+
+配置变更请同步更新仓库 `docs/devops/dev/` 下对应文件,再部署到服务器。

+ 244 - 0
docs/devops/dev/java/Jenkinsfile

@@ -0,0 +1,244 @@
+/**
+ * 开发环境(deve):Checkout -> Maven(按需模块)-> 拷贝 jar -> docker compose 启停
+ *
+ * Jenkins Job 配置:
+ *   - Pipeline script from SCM
+ *   - Repository: http://8.152.195.41:3000/alien/alien_cloud
+ *   - Script Path: docs/devops/dev/java/Jenkinsfile
+ *   - 分支默认 deve(构建参数 GIT_BRANCH 可覆盖)
+ *
+ * 宿主机目录:/deve/java(docker-compose.yml 与 gateway/store/... 子目录)
+ * Jenkins 容器须能访问该路径(建议挂载 /deve/java:/deve/java)及 docker.sock
+ *
+ * 容器名:gateway-dev、store-dev…(compose 内 services 键仍为 gateway、store…)
+ */
+
+def getServiceDefinitions() {
+    return [
+            [module: 'alien-gateway',        dir: 'gateway',        composeService: 'gateway',        container: 'gateway-dev',        withLib: false],
+            [module: 'alien-store',          dir: 'store',          composeService: 'store',          container: 'store-dev',          withLib: true],
+            [module: 'alien-second',         dir: 'second',         composeService: 'second',         container: 'second-dev',         withLib: false],
+            [module: 'alien-store-platform', dir: 'store-platform', composeService: 'store-platform', container: 'store-platform-dev', withLib: false],
+            [module: 'alien-lawyer',         dir: 'lawyer',         composeService: 'lawyer',         container: 'lawyer-dev',         withLib: false],
+            [module: 'alien-job',            dir: 'job',            composeService: 'job',            container: 'job-dev',            withLib: false],
+            [module: 'alien-dining',         dir: 'dining',         composeService: 'dining',         container: 'dining-dev',         withLib: true],
+    ]
+}
+
+def deployParamName(String composeService) {
+    return 'DEPLOY_' + composeService.replace('-', '_')
+}
+
+def collectSelectedServices(Map buildParams) {
+    def selected = []
+    getServiceDefinitions().each { svc ->
+        def paramName = deployParamName(svc.composeService)
+        if (buildParams[paramName]) {
+            selected.add(svc)
+        }
+    }
+    return selected
+}
+
+def deployOneService(String workspace, String deployRoot, Map svc) {
+    def sourceJar = "${workspace}/${svc.module}/target/${svc.module}-1.0.0.jar"
+    def sourceLib = "${workspace}/${svc.module}/target/lib"
+    def targetDir = "${deployRoot}/${svc.dir}"
+    sh """
+        set -e
+        echo ">>> Deploy module: ${svc.module} -> ${targetDir}"
+        if [ ! -f "${sourceJar}" ]; then
+            echo ">>> [${svc.dir}] jar missing, skip copy"
+            exit 0
+        fi
+        mkdir -p "${targetDir}"
+        if [ "${svc.withLib}" = "true" ] && [ -d "${sourceLib}" ]; then
+            rm -rf "${targetDir}/lib"
+            cp -rf "${sourceLib}" "${targetDir}/lib"
+        fi
+        cp -f "${sourceJar}" "${targetDir}/"
+        echo ">>> [${svc.dir}] jar copied"
+    """
+}
+
+def composeStop(String deployRoot, List composeServices) {
+    if (composeServices == null || composeServices.isEmpty()) {
+        return
+    }
+    def svcList = composeServices.join(' ')
+    sh """
+        set -e
+        cd "${deployRoot}"
+        test -f docker-compose.yml
+        echo ">>> docker compose stop ${svcList}"
+        docker compose stop ${svcList}
+    """
+}
+
+def startOrRestartServices(String deployRoot, List composeServices) {
+    if (composeServices == null || composeServices.isEmpty()) {
+        return
+    }
+    def svcList = composeServices.join(' ')
+    sh """
+        set -e
+        cd "${deployRoot}"
+        test -f docker-compose.yml
+        echo ">>> docker compose up -d ${svcList}"
+        docker compose up -d ${svcList}
+        echo ">>> docker compose restart ${svcList}"
+        docker compose restart ${svcList}
+    """
+}
+
+pipeline {
+    agent any
+
+    options {
+        buildDiscarder(logRotator(numToKeepStr: '2', artifactNumToKeepStr: '2'))
+        disableConcurrentBuilds()
+        timestamps()
+        timeout(time: 60, unit: 'MINUTES')
+    }
+
+    parameters {
+        string(
+                name: 'GIT_BRANCH',
+                defaultValue: 'deve',
+                trim: true,
+                description: '构建分支,默认 deve,可在「Build with Parameters」中修改'
+        )
+        booleanParam(
+                name: 'STOP_ALL',
+                defaultValue: false,
+                description: '为 true 时:先停止全部 dev 微服务,再按下方勾选部署;此时 gateway 必须勾选'
+        )
+        // 多选复选框(Declarative 须逐项声明,不可用 each 动态生成)
+        booleanParam(name: 'DEPLOY_gateway', defaultValue: true, description: 'alien-gateway -> gateway-dev')
+        booleanParam(name: 'DEPLOY_store', defaultValue: true, description: 'alien-store -> store-dev')
+        booleanParam(name: 'DEPLOY_second', defaultValue: true, description: 'alien-second -> second-dev')
+        booleanParam(name: 'DEPLOY_store_platform', defaultValue: false, description: 'alien-store-platform -> store-platform-dev')
+        booleanParam(name: 'DEPLOY_lawyer', defaultValue: false, description: 'alien-lawyer -> lawyer-dev')
+        booleanParam(name: 'DEPLOY_job', defaultValue: false, description: 'alien-job -> job-dev')
+        booleanParam(name: 'DEPLOY_dining', defaultValue: false, description: 'alien-dining -> dining-dev')
+    }
+
+    environment {
+        MAVEN_HOME = tool '3.6.3'
+        PATH = "${MAVEN_HOME}/bin:${env.PATH}"
+        GIT_URL = 'http://8.152.195.41:3000/alien/alien_cloud'
+        GIT_CREDENTIALS = '5e058e17-8089-45e0-a802-596d91758b4d'
+        DEPLOY_ROOT = '/deve/java'
+        MAVEN_LOCAL_REPO = '/var/jenkins_home/.m2/repository'
+    }
+
+    stages {
+        stage('Validate') {
+            steps {
+                script {
+                    def selected = collectSelectedServices(params)
+                    if (selected.isEmpty()) {
+                        error('请至少勾选一个微服务')
+                    }
+                    if (params.STOP_ALL && !params.DEPLOY_gateway) {
+                        error('STOP_ALL=true 时 gateway 必须勾选')
+                    }
+                    env.SELECTED_COMPOSE_SERVICES = selected.collect { it.composeService }.join(' ')
+                    env.SELECTED_MAVEN_MODULES = selected.collect { it.module }.join(',')
+                    echo ">>> Branch: ${params.GIT_BRANCH}"
+                    echo ">>> STOP_ALL: ${params.STOP_ALL}"
+                    echo ">>> Selected compose services: ${env.SELECTED_COMPOSE_SERVICES}"
+                }
+            }
+        }
+
+        stage('Checkout') {
+            steps {
+                script {
+                    def branch = (params.GIT_BRANCH ?: 'deve').trim()
+                    if (!branch) {
+                        error('GIT_BRANCH is required')
+                    }
+                    env.GIT_BRANCH = branch
+                    echo ">>> Checkout branch: ${env.GIT_BRANCH}"
+                    git branch: "${env.GIT_BRANCH}",
+                            credentialsId: "${env.GIT_CREDENTIALS}",
+                            url: "${env.GIT_URL}"
+                    sh """
+                        set -e
+                        git fetch origin
+                        git reset --hard origin/${env.GIT_BRANCH}
+                        git log -1 --oneline
+                    """
+                }
+            }
+        }
+
+        stage('Stop All Dev Services') {
+            when {
+                expression { return params.STOP_ALL }
+            }
+            steps {
+                script {
+                    def allServices = getServiceDefinitions().collect { it.composeService }
+                    composeStop(env.DEPLOY_ROOT, allServices)
+                }
+            }
+        }
+
+        stage('Maven Build') {
+            steps {
+                sh """
+                    set -e
+                    cat > settings.xml <<'EOF'
+<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
+          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+          xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 https://maven.apache.org/xsd/settings-1.0.0.xsd">
+  <mirrors>
+    <mirror>
+      <id>aliyunmaven</id>
+      <mirrorOf>*</mirrorOf>
+      <name>Aliyun Maven</name>
+      <url>https://maven.aliyun.com/repository/public</url>
+    </mirror>
+  </mirrors>
+</settings>
+EOF
+                    echo ">>> Maven modules: ${SELECTED_MAVEN_MODULES}"
+                    mvn clean package -DskipTests -s settings.xml -pl ${SELECTED_MAVEN_MODULES} -am
+                """
+            }
+        }
+
+        stage('Deploy Services') {
+            steps {
+                script {
+                    def selected = collectSelectedServices(params)
+                    selected.each { svc ->
+                        deployOneService(env.WORKSPACE, env.DEPLOY_ROOT, svc)
+                    }
+                }
+            }
+        }
+
+        stage('Start Dev Services') {
+            steps {
+                script {
+                    def selected = collectSelectedServices(params)
+                    def composeServices = selected.collect { it.composeService }
+                    startOrRestartServices(env.DEPLOY_ROOT, composeServices)
+                }
+            }
+        }
+    }
+
+    post {
+        always {
+            sh 'rm -f settings.xml || true'
+            echo '>>> 开发环境构建结束'
+        }
+        failure {
+            echo '>>> 构建失败,已部署的 jar 不会自动回滚,请检查日志'
+        }
+    }
+}

+ 133 - 0
docs/devops/dev/java/docker-compose.yml

@@ -0,0 +1,133 @@
+# 1. 基础环境变量(所有服务通用)
+x-java-env: &java-env
+  TZ: Asia/Shanghai
+  JASYPT_ENCRYPTOR_PASSWORD: alien_salt
+  LOGGING_PATH: /app/logs
+# 2. 代理环境变量(在基础版之上增加代理)
+x-proxy-env: &proxy-env
+  <<: *java-env
+
+# 3. 容器基础配置模板
+x-java-common: &java-common
+  restart: unless-stopped
+  working_dir: /app
+  networks:
+    - app-network
+  mem_limit: 800M
+  mem_reservation: 256M
+
+services:
+  gateway:
+    <<: *java-common
+    image: my-openjdk8-ffmpeg:v1
+    container_name: gateway-dev
+    environment:
+      <<: *java-env # 仅引用基础环境变量
+    volumes:
+      - ./gateway:/app
+      - ./logs/gateway:/app/logs
+    ports:
+      - "28000:8000"
+    command: |
+      sh -c 'exec java -Dspring.profiles.active=dev -Dfile.encoding=UTF-8 -Xms384m -Xmx384m -jar /app/alien-gateway-1.0.0.jar'
+
+  store:
+    <<: *java-common
+    image: my-openjdk8-ffmpeg:v1
+    container_name: store-dev
+    mem_limit: 700M         # 对齐 test 用量比例,留 15~20% 余量
+    mem_reservation: 384M   # 软性内存限制
+    environment:
+      <<: *proxy-env # 引用带代理的环境变量
+    volumes:
+      - ./store:/app
+      - ./store/alien/aliPayCert:/usr/local/alien/aliPayCert
+      - /cert/wechat/:/cert/wechat/
+      - ./logs/store:/app/logs
+    ports:
+      - "28004:30004"
+    command: |
+      sh -c 'exec java -Dspring.profiles.active=dev -Dfile.encoding=UTF-8 -Xms384m -Xmx384m -Dloader.path=/app/lib -jar /app/alien-store-1.0.0.jar'
+
+  second:
+    <<: *java-common
+    image: my-openjdk8-ffmpeg:v1
+    container_name: second-dev
+    environment:
+      <<: *proxy-env
+    volumes:
+      - ./second:/app
+      - ./second/alien/aliPayCert:/usr/local/alien/aliPayCert
+      - ./logs/second:/app/logs
+    ports:
+      - "28005:30005"
+    command: |
+      sh -c 'exec java -Dspring.profiles.active=dev -Dfile.encoding=UTF-8 -Xms384m -Xmx384m -jar /app/alien-second-1.0.0.jar'
+
+  store-platform:
+    <<: *java-common
+    image: my-openjdk8-ffmpeg:v1
+    container_name: store-platform-dev
+    environment:
+      <<: *proxy-env
+    volumes:
+      - ./store-platform:/app
+      - ./store-platform/alien/aliPayCert:/usr/local/alien/aliPayCert
+      - ./logs/store-platform:/app/logs
+    ports:
+      - "28006:30006"
+    command: |
+      sh -c 'exec java -Dspring.profiles.active=dev -Dfile.encoding=UTF-8 -Xms384m -Xmx384m -jar /app/alien-store-platform-1.0.0.jar'
+
+  lawyer:
+    <<: *java-common
+    image: my-openjdk8-ffmpeg:v1
+    container_name: lawyer-dev
+    environment:
+      <<: *proxy-env
+    volumes:
+      - ./lawyer:/app
+      - ./lawyer/alien/aliPayCert:/usr/local/alien/aliPayCert
+      - ./logs/lawyer:/app/logs
+    ports:
+      - "28007:30007"
+    command: |
+      sh -c 'exec java -Dspring.profiles.active=dev -Dfile.encoding=UTF-8 -Xms384m -Xmx384m -jar /app/alien-lawyer-1.0.0.jar'
+
+  job:
+    <<: *java-common
+    image: my-openjdk8-ffmpeg:v1
+    container_name: job-dev
+    environment:
+      <<: *proxy-env
+    volumes:
+      - ./job:/app
+      - ./job/alien/aliPayCert:/usr/local/alien/aliPayCert
+      - ./logs/job:/app/logs
+    ports:
+      - "28008:30008"
+      - "28018:9999"
+    command: |
+      sh -c 'exec java -Dspring.profiles.active=dev -Dfile.encoding=UTF-8 -Xms384m -Xmx384m -jar /app/alien-job-1.0.0.jar'
+
+  dining:
+    <<: *java-common
+    image: my-openjdk8-ffmpeg:v1
+    container_name: dining-dev
+    environment:
+      <<: *proxy-env # 引用带代理的环境变量
+    volumes:
+      - ./dining:/app
+      - ./dining/alien/aliPayCert:/usr/local/alien/aliPayCert
+      - /cert/wechat/:/cert/wechat/
+      - ./logs/dining:/app/logs
+    ports:
+      - "28014:30014"
+    command: |
+      sh -c 'exec java -Dspring.profiles.active=dev -Dfile.encoding=UTF-8 -Xms384m -Xmx384m -Dloader.path=/app/lib -jar /app/alien-dining-1.0.0.jar'
+
+
+networks:
+  app-network:
+    external: true        # 使用同一个外部网络
+    name: app-network

+ 69 - 0
docs/devops/dev/middleware/docker-compose.yml

@@ -0,0 +1,69 @@
+# =============================================================================
+# 开发环境 — 增补中间件(与 /docker/middleware 并行,共用 app-network)
+# =============================================================================
+#
+# 【设计原则】
+#   共用(不重复部署):MySQL、Nacos、RocketMQ、xxl-job-admin、Jenkins、ES
+#   隔离(本文件新增):redis-dev(避免 dev/test session/缓存/限流互相污染)
+#
+# 【服务器部署路径建议】
+#   /docker/middleware-dev/   或复制本目录内容到服务器
+#
+# 【启动】
+#   cd /docker/middleware-dev
+#   docker compose up -d
+#
+# 【或叠加到现有 middleware 目录】
+#   cd /docker/middleware
+#   docker compose -f docker-compose.yml -f /docker/middleware-dev/docker-compose.yml up -d redis-dev
+#
+# 【Nacos dev 命名空间 common.yml 需配置】
+#   spring.redis.host: redis-dev
+#   spring.redis.port: 6379
+#   spring.redis.password: Alien123456
+#   (容器内通过服务名访问,勿写 120.26.186.130:30022)
+#
+# 【宿主机 / 本地 IDEA 直连】
+#   host: 120.26.186.130  port: 30022
+#
+# =============================================================================
+
+x-logging: &default-logging
+  driver: "json-file"
+  options:
+    max-size: "50m"
+    max-file: "3"
+
+services:
+  # ---------------------------------------------------------------------------
+  # redis-dev — 开发环境专用 Redis
+  # 配置与 test redis 一致(requirepass/maxmemory 256mb);mem_limit 对齐 test 512M
+  # ---------------------------------------------------------------------------
+  redis-dev:
+    image: redis:6.0.8
+    container_name: redis-dev
+    restart: unless-stopped
+    logging: *default-logging
+    environment:
+      - TZ=Asia/Shanghai
+    volumes:
+      - ./redis-dev/data:/data
+      - ./redis-dev/conf/redis.conf:/usr/local/etc/redis/redis.conf:ro
+    ports:
+      - "20022:6379"
+    networks:
+      - app-network
+    command: redis-server /usr/local/etc/redis/redis.conf
+    mem_limit: 512M
+    mem_reservation: 256M
+    healthcheck:
+      test: ["CMD", "redis-cli", "-a", "Alien123456", "ping"]
+      interval: 30s
+      timeout: 5s
+      retries: 3
+      start_period: 10s
+
+networks:
+  app-network:
+    external: true
+    name: app-network

+ 13 - 0
docs/devops/dev/middleware/redis-dev/conf/redis.conf

@@ -0,0 +1,13 @@
+# 开发环境 Redis(redis-dev)
+# 容器内 6379,宿主机 30022;配置与 test redis 对齐,仅实例隔离
+# Nacos dev common.yml: host=redis-dev, port=6379, password=Alien123456
+
+bind 0.0.0.0
+port 6379
+requirepass Alien123456
+appendonly yes
+appendfsync everysec
+maxmemory 256mb
+maxmemory-policy allkeys-lru
+timeout 300
+tcp-keepalive 60