Files
wiki/研发型企业AI转型方案/报告/crmeb-deploy-plan.html
T

443 lines
15 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>研发型企业 CRMEB 自动发布方案 — Gitea CI/CD 流水线</title>
<style>
:root {
--color-primary: #1677FF; --color-primary-hover: #4096FF; --color-primary-active: #0958D9; --color-primary-bg: #E6F4FF;
--color-success: #52C41A; --color-success-bg: #F6FFED; --color-success-border: #B7EB8F;
--color-warning: #FAAD14; --color-warning-bg: #FFFBE6; --color-warning-border: #FFE58F;
--color-error: #FF4D4F; --color-error-bg: #FFF2F0; --color-error-border: #FFCCC7;
--bg: #F5F5F5; --bg-container: #FFFFFF; --bg-elevated: #FAFAFA;
--border: #D9D9D9; --border-light: #F0F0F0;
--text-primary: #141414; --text-secondary: #595959; --text-tertiary: #8C8C8C;
--radius-sm: 6px; --radius-md: 8px; --radius-lg: 12px;
--shadow-sm: 0 1px 2px rgba(0,0,0,0.03), 0 1px 6px -1px rgba(0,0,0,0.02);
--shadow-md: 0 2px 4px rgba(0,0,0,0.04), 0 4px 12px -2px rgba(0,0,0,0.04);
}
*{margin:0;padding:0;box-sizing:border-box;}
body{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,'PingFang SC','Hiragino Sans GB','Microsoft YaHei',sans-serif;background:var(--bg);color:var(--text-primary);line-height:1.57;font-size:14px;}
.header{position:sticky;top:0;z-index:100;height:64px;background:linear-gradient(135deg,#1677FF,#722ED1);display:flex;align-items:center;padding:0 2rem;box-shadow:0 2px 8px rgba(22,119,255,0.15);}
.header h1{font-size:18px;font-weight:700;background:linear-gradient(135deg,var(--color-primary),#722ED1);-webkit-background-clip:text;background-clip:text;-webkit-text-fill-color:transparent;color:transparent;
.header .back-link{margin-right:16px;font-size:13px;color:rgba(255,255,255,0.85);text-decoration:none;flex-shrink:0;}
.header .back-link:hover{color:#fff;text-decoration:underline;}
.container{max-width:1200px;margin:0 auto;padding:32px 40px 64px;}
section{margin:48px 0;}
section h2{font-size:24px;line-height:32px;padding-bottom:8px;border-bottom:1px solid var(--border);margin-bottom:20px;color:var(--color-primary);}
section h3{font-size:20px;line-height:28px;margin:24px 0 12px;color:#722ED1;}
section h4{font-size:15px;line-height:22px;margin:16px 0 8px;color:#444;font-weight:600;}
p{color:var(--text-secondary);font-size:14px;margin:10px 0;}
table{width:100%;border-collapse:collapse;font-size:13px;margin:14px 0;}
th,td{padding:10px 14px;border:1px solid var(--border);text-align:left;vertical-align:top;}
th{background:var(--bg-elevated);font-weight:700;color:var(--text-primary);white-space:nowrap;}
td{background:var(--bg-container);color:var(--text-secondary);}
tbody tr:hover td{background:var(--color-primary-bg);}
.code-block{background:#1E1E1E;color:#D4D4D4;border-radius:var(--radius-md);padding:16px 20px;margin:14px 0;font-family:'SF Mono',Monaco,monospace;font-size:13px;line-height:1.7;overflow-x:auto;white-space:pre;}
.code-block .comment{color:#6A9955;}
pre{margin:0;}
ul,ol{margin:8px 0 8px 20px;}
li{margin:4px 0;color:var(--text-secondary);font-size:14px;}
.tree{font-family:'SF Mono',Monaco,monospace;font-size:13px;color:var(--text-secondary);line-height:1.6;margin:14px 0;padding:12px 16px;background:var(--bg-elevated);border-radius:var(--radius-sm);border:1px solid var(--border-light);}
.footer{text-align:center;padding:28px 0;color:var(--text-tertiary);font-size:13px;border-top:1px solid var(--border-light);margin-top:40px;}
@media(max-width:768px){.container{padding:20px 16px 40px;}.header{padding:0 1rem;}}
</style>
</head>
<body>
<header class="header">
<a class="back-link" href="../../index.html">← 知识库</a>
<h1>CRMEB 自动发布方案</h1>
</header>
<div class="container">
<section>
<h2>一、整体架构</h2>
<div class="tree">
┌──────────────────────────────────────────────────────────┐
│ Gitea (47.115.231.200) │
│ 代码仓库: admin-api / front-api / admin-web │
│ Gitea Actions CI/CD │
├──────────────────────────────────────────────────────────┤
│ Runner (47.122.125.216) │
│ Maven 构建 → npm 构建 → 停服 → 替换 JAR → 启服 │
├──────────────────────────────────────────────────────────┤
│ 部署目标 (47.122.125.216) │
│ /opt/crmeb/admin/ ← admin-api JAR │
│ /opt/crmeb/front/ ← front-api JAR │
│ /opt/crmeb/web/dist/ ← admin-web 静态文件 │
└──────────────────────────────────────────────────────────┘
</div>
<p><strong>三台服务器分工</strong></p>
<table>
<tr><th>服务器</th><th>角色</th></tr>
<tr><td>47.115.231.200</td><td>Gitea 代码托管 + CI 调度</td></tr>
<tr><td>47.122.125.216</td><td>Runner(构建+部署)+ 生产运行</td></tr>
<tr><td>39.100.114.100</td><td>Nginx 入口(已有,不变)</td></tr>
</table>
</section>
<section>
<h2>二、Gitea 安装(47.115.231.200</h2>
<div class="code-block">ssh root@47.115.231.200
# Docker 已装,直接部署
docker run -d \
--name gitea \
--restart always \
-p 3000:3000 \
-p 2222:22 \
-v /data/gitea:/data \
-e GITEA__server__DOMAIN=gitea.ycbat.com \
-e GITEA__server__ROOT_URL=https://gitea.ycbat.com \
-e GITEA__actions__ENABLED=true \
gitea/gitea:latest
# DNS: gitea.ycbat.com → 47.115.231.200
# Nginx 反代在 39.100.114.100 上加一条</div>
<p><strong>Nginx 反代</strong>39.100.114.100 <code>/etc/nginx/conf.d/gitea.ycbat.com.conf</code>):</p>
<div class="code-block">server {
listen 80;
server_name gitea.ycbat.com;
client_max_body_size 100m;
location / {
proxy_pass http://47.115.231.200:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}</div>
</section>
<section>
<h2>三、NPM 私服(Verdaccio</h2>
<p>前端依赖统一走私有 NPM 仓库,加速安装并缓存上游包。</p>
<h3>3.1 架构</h3>
<table>
<tr><th></th><th>IP</th><th>角色</th><th>配置</th></tr>
<tr><td>Nginx 入口</td><td>39.100.114.100</td><td>反向代理</td><td><code>/etc/nginx/conf.d/npm.ycbat.com.conf</code></td></tr>
<tr><td>Verdaccio</td><td>47.115.231.200</td><td>私服</td><td>端口 4873<code>/data/verdaccio/config.yaml</code></td></tr>
</table>
<h3>3.2 Nginx 反代</h3>
<div class="code-block"># 39.100.114.100 — /etc/nginx/conf.d/npm.ycbat.com.conf
server {
listen 80;
server_name npm.ycbat.com;
client_max_body_size 100m;
location / {
proxy_pass http://47.115.231.200:4873;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}</div>
<h3>3.3 Verdaccio 配置</h3>
<div class="code-block"># 47.115.231.200 — /data/verdaccio/config.yaml
storage: /data/verdaccio/storage
uplinks:
npmjs:
url: https://registry.npmmirror.com/ # 阿里云镜像
packages:
'@mycompany/*':
access: $all
publish: $authenticated
'**':
access: $all
proxy: npmjs
logs: { type: stdout, format: pretty, level: info }</div>
<h3>3.4 客户端配置</h3>
<div class="code-block"># 项目根目录 .npmrc
registry=http://npm.ycbat.com/</div>
<h3>3.5 发布私有包</h3>
<div class="code-block"># 首次登录(只需一次)
npm login --registry=http://npm.ycbat.com/
# 发布 @mycompany 作用域包
npm publish --registry=http://npm.ycbat.com/</div>
<p>Verdaccio 进程通过 <code>pm2</code> 守护:<code>pm2 start verdaccio</code></p>
</section>
<section>
<h2>四、Runner 安装(47.122.125.216</h2>
<p>Runner 负责执行构建任务,装在<strong>生产服务器上</strong>,省去跨服务器传 JAR 的步骤。</p>
<div class="code-block">ssh root@47.122.125.216
# 1. 安装 Maven
apt install -y maven
# 2. 下载 Gitea Actions Runner
curl -L -o /usr/local/bin/act_runner \
https://gitea.com/gitea/act_runner/releases/download/v0.2.11/act_runner-0.2.11-linux-amd64
chmod +x /usr/local/bin/act_runner
# 3. 注册 Runner(先去 Gitea → Site Admin → Runners → 获取 token
act_runner register \
--instance https://gitea.ycbat.com \
--token &lt;RUNNER_TOKEN&gt; \
--name "prod-runner" \
--labels "prod,ubuntu,maven"
# 4. systemd 守护
cat &gt; /etc/systemd/system/gitea-runner.service &lt;&lt; 'EOF'
[Unit]
Description=Gitea Actions Runner
After=network.target
[Service]
Type=simple
User=root
ExecStart=/usr/local/bin/act_runner daemon
Restart=on-failure
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemctl enable gitea-runner
systemctl start gitea-runner</div>
</section>
<section>
<h2>五、代码仓库结构</h2>
<p>在 Gitea 上创建 3 个仓库,推送源码:</p>
<div class="tree">
gitea.ycbat.com/crmeb/
├── admin-api/ # 管理后台 APIJava
│ ├── src/
│ ├── pom.xml
│ ├── .gitea/workflows/deploy.yml
│ └── .gitea/settings.xml # Maven 私服配置
├── front-api/ # 小程序 APIJava
│ ├── src/
│ ├── pom.xml
│ └── .gitea/workflows/deploy.yml
└── admin-web/ # 管理后台前端(Vue.js)
├── src/
├── package.json
├── .npmrc # registry=http://npm.ycbat.com/
└── .gitea/workflows/deploy.yml
</div>
</section>
<section>
<h2>六、CI/CD 流水线配置</h2>
<h3>5.1 admin-apiJava 后端)</h3>
<div class="code-block"># .gitea/workflows/deploy.yml
name: Build &amp; Deploy Admin API
on:
push:
branches: [main]
jobs:
deploy:
runs-on: prod
steps:
- uses: actions/checkout@v4
- name: Build JAR
run: mvn clean package -DskipTests -s .gitea/settings.xml
- name: Stop Service
run: /opt/crmeb/admin/ctl.sh stop || true
- name: Deploy JAR
run: |
cp target/Crmeb-admin.jar /opt/crmeb/admin/
cp target/classes/application-prod.yml /opt/crmeb/admin/ 2&gt;/dev/null || true
- name: Start Service
run: /opt/crmeb/admin/ctl.sh start
- name: Health Check
run: |
sleep 10
curl -sf -o /dev/null https://adminapi.hblj.asia/ &amp;&amp; echo "OK" || echo "FAIL"</div>
<h3>5.2 front-apiJava 后端)</h3>
<div class="code-block"># .gitea/workflows/deploy.yml
name: Build &amp; Deploy Front API
on:
push:
branches: [main]
jobs:
deploy:
runs-on: prod
steps:
- uses: actions/checkout@v4
- name: Build JAR
run: mvn clean package -DskipTests -s .gitea/settings.xml
- name: Stop Service
run: /opt/crmeb/front/ctl.sh stop || true
- name: Deploy JAR
run: |
cp target/Crmeb-front.jar /opt/crmeb/front/
- name: Start Service
run: /opt/crmeb/front/ctl.sh start
- name: Health Check
run: |
sleep 10
curl -sf -o /dev/null https://miniappapi.hblj.asia/ &amp;&amp; echo "OK" || echo "FAIL"</div>
<h3>5.3 admin-webVue.js 前端)</h3>
<div class="code-block"># .gitea/workflows/deploy.yml
name: Build &amp; Deploy Admin Web
on:
push:
branches: [main]
jobs:
deploy:
runs-on: prod
steps:
- uses: actions/checkout@v4
- name: Install Dependencies
run: npm ci --registry=http://npm.ycbat.com/
- name: Build
run: npm run build:prod
- name: Deploy
run: |
rm -rf /opt/crmeb/web/dist/*
cp -r dist/* /opt/crmeb/web/dist/
- name: Health Check
run: curl -sf -o /dev/null https://admin.hblj.asia/ &amp;&amp; echo "OK"</div>
</section>
<section>
<h2>七、Gitea Secrets 配置</h2>
<p>仓库 → Settings → Secrets,添加:</p>
<table>
<tr><th>Secret 名</th><th></th><th>用途</th></tr>
<tr><td>(不需 secrets</td><td></td><td>Runner 在本机执行,直接读写本地文件</td></tr>
</table>
<p>因为 Runner 和部署目标在同一台机器,<strong>不需要 SCP/SSH 密码</strong>。构建产物直接 <code>cp</code> 到目标目录。</p>
</section>
<section>
<h2>八、Maven settings.xml(私服配置)</h2>
<div class="code-block">&lt;!-- .gitea/settings.xml — 仓库根目录 --&gt;
&lt;settings&gt;
&lt;mirrors&gt;
&lt;mirror&gt;
&lt;id&gt;aliyun&lt;/id&gt;
&lt;mirrorOf&gt;central&lt;/mirrorOf&gt;
&lt;name&gt;Aliyun Maven&lt;/name&gt;
&lt;url&gt;https://maven.aliyun.com/repository/public&lt;/url&gt;
&lt;/mirror&gt;
&lt;/mirrors&gt;
&lt;/settings&gt;</div>
</section>
<section>
<h2>九、实施步骤</h2>
<div class="tree">
Phase 1: 基础设施(1 小时)
├── 47.115.231.200 安装 Gitea
├── 39.100.114.100 配置 gitea.ycbat.com 反代
├── 47.122.125.216 安装 Maven + Runner
└── Gitea 创建组织 crmeb + 3 个仓库
Phase 2: 代码入库(2 小时)
├── 从生产服务器提取源码(反编译或从原始开发环境)
├── admin-api 源码 → git push
├── front-api 源码 → git push
├── admin-web 源码 → git push
└── 每个仓库配置 .gitea/workflows/deploy.yml
Phase 3: 验证(30 分钟)
├── 修改一个无害的改动(如版本号)
├── git push → 观察 Gitea Actions 自动构建
├── 确认服务自动重启
└── 确认 health check 通过
</div>
</section>
<section>
<h2>十、Gitea 分支保护</h2>
<p>每个仓库 Settings → Branches → 添加规则:</p>
<table>
<tr><th>规则</th><th></th></tr>
<tr><td>分支</td><td>main</td></tr>
<tr><td>禁止直接 push</td><td></td></tr>
<tr><td>PR 必须 Approve</td><td>1 人</td></tr>
<tr><td>PR 必须 CI 通过</td><td></td></tr>
</table>
<p>日常开发流程:</p>
<div class="tree">
feature 分支 → 开发 → git push → 创建 PR
→ Gitea Actions 自动测试(不部署)
→ Code Review
→ Merge to main
→ Gitea Actions 自动部署到生产
</div>
</section>
<section>
<h2>十一、回滚</h2>
<div class="code-block"># 在 47.122.125.216 上
cd /opt/crmeb/admin
cp Crmeb-admin.jar Crmeb-admin.jar.bak # 部署前 Runner 自动备份
# 回滚
cp Crmeb-admin.jar.bak Crmeb-admin.jar &amp;&amp; ./ctl.sh restart</div>
<p>在 deploy.yml 中加入自动备份:</p>
<div class="code-block">- name: Backup
run: cp /opt/crmeb/admin/Crmeb-admin.jar /opt/crmeb/admin/Crmeb-admin.jar.bak</div>
</section>
<div class="footer">CRMEB 自动发布方案 · <a href="../../index.html" style="color:var(--color-primary);">返回知识库</a></div>
</div>
</body>
</html>