完善架构,修改很多地方

This commit is contained in:
编码猿
2025-10-04 00:08:33 +08:00
parent 3c66faf9a7
commit ff925d458a
32 changed files with 576 additions and 1602 deletions

View File

@@ -0,0 +1,14 @@
node_modules
dist
.git
.DS_Store
*.log
docker/ # 排除 docker 配置文件夹本身
.editorconfig
.eslintrc.js
.prettierrc
.vscode
.idea
*.swp
*.swo

View File

@@ -1,7 +1,7 @@
# 请求协议 http or https建议线上配置证书后使用https
VITE_PREFIX=http://
# Nacos 配置中心 ip:端口 | 域名
# 内网 中的 Nacos 配置中心 ip:端口 | 域名
#VITE_NACOS_ADDRESS=cluster.nacos.com
VITE_NACOS_ADDRESS=192.168.139.84:8848

View File

@@ -1,16 +1,17 @@
# 请求协议 http or https建议线上配置证书后使用https
VITE_PREFIX=http://
# Nacos 配置中心 ip:端口 | 域名
# 内网 中的 Nacos 配置中心 ip:端口 | 域名
#VITE_NACOS_ADDRESS=cluster.nacos.com
VITE_NACOS_ADDRESS=192.168.139.84:8848
# 注册到 Nacos 的服务名称(微前端模块名称
VITE_SERVER_NAME=app-product
# 注册到 Nacos 的端口,也是前端运行的端口
VITE_SERVER_PORT=1301
#
# 说明:项目要调用哪些 微前端 模块
# 格式VITE_MODEL_XXXX_NAME=微前端模块名称(模块 的 开发者提供)
@@ -19,3 +20,4 @@ VITE_SERVER_PORT=1301
# shared 共享资源模块
VITE_MODEL_SHARED_NAME=app-shared

View File

@@ -1,10 +1,63 @@
npm install
npm run build
npm run serve
## app-product 商品模块(微前端模块)
从项目中拆分出来,用于演示的微前端模块,主要实现 商品相关功能。本案例演示中提供:
- 调用 微前端 app-shared 模块
- 调接口,获取商品首页的数据和展示
- 调接口,点击商品列表进入商品详情页
构建与部署:
## 运行
- 在构建生产环境时,先构建主模块,并将其产出(特别是 remoteEntry.js 和对应的资产文件)部署到服务器,并获取其 URL。
- 然后,在子模块的 vite.config.ts 中,将 remotes 的 URL 更新为生产环境主模块 remoteEntry.js 的绝对 URL。
- 最后再构建子模块。
下面文档分为**开发**和**上线**两部分进行说明!
### 开发
```bash
# 安装依赖
npm install
# 开发阶段 运行 项目
# PS注意此命令运行的项目【无法】被其他 微前端模块 使用,仅用于本地独立开发,独立测试
npm run dev
# 启动 实时打包 & 实时预览
# PS注意此命令运行的项目【可以】被其他 微前端模块 调用,可用于本地开发和微前端联合开发
npm run dep
```
### 上线
**docker/ 文件夹说明**
- `app-product.yml` - Dcoker Swarm 集群部署配置
- `deploy-swarm.sh` - 自动化部署脚本
- `docker-compose.yml` - 开发阶段容器编排
- `Dockerfile` - 打包构建前端代码为镜像
- `nginx.conf` - 镜像内前端被访问的Nginx配置
前端工作:
- 1: 编辑 前端 .env.development 和 .env.production 环境变量(只需修改一次)
- 2: 确认或编辑 docker/Dockerfiledocker/nginx.conf
- 3: 编辑 docker/deploy-swarm.sh
还有很多细节未展开,后面再详细说,大致确认无误后。
在前端集群的管理机上进入项目根目录,执行下面命令部署:
```bash
# 运行自动化集群部署脚本
./docker/deploy-swarm.sh
# --- 其他命令 ---
# 删除之前的部署(可选)
docker stack rm app-product
# 查看 app-product 集群运行情况
docker stack ps app-product
# 持续观察服务副本数是否达到预期
watch docker stack services app-product
```

View File

@@ -0,0 +1,21 @@
FROM node:24-alpine AS builder
WORKDIR /app
COPY package.json ./
# 直接使用 npm install 并解决依赖问题
RUN npm install --no-audit --no-fund --legacy-peer-deps
# 拷贝源码并构建
COPY . .
# 【前端修改】如果要以子路径 /app-product/ 部署,请用 base 指定前缀,同 .env中VITE_SERVER_NAME
RUN npx vite build --base=/app-product/
FROM nginx:alpine
# 构建产物放到 /usr/share/nginx/html/app-product
COPY --from=builder /app/dist /usr/share/nginx/html/app-product
# 覆盖 Nginx 配置,支持 SPA 子路径
COPY docker/nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

View File

@@ -0,0 +1,39 @@
version: "3.8" # Docker Compose 文件版本3.8 支持 Swarm 模式的所有功能
services:
app-product:
image: app-product:latest
ports:
- target: 80 # 容器内部端口
published: 1301 # 宿主机对外暴露端口
protocol: tcp # 协议类型
mode: ingress # 模式:使用路由网格
deploy:
replicas: 3 # 副本数量,在集群中运行 3 个容器实例
placement:
max_replicas_per_node: 1 # 每个 Swarm 节点最多运行 1 个副本,确保高可用性
restart_policy:
condition: any # 重启条件:任何情况下容器退出都重启
delay: 5s # 重启延迟 5 秒
max_attempts: 3 # 最大重启尝试次数
update_config: # 滚动更新配置
parallelism: 1 # 并行更新数量:一次只更新 1 个容器
delay: 10s # 更新间隔:每个容器更新后等待 10 秒再更新下一个
failure_action: rollback # 更新失败时自动回滚到上一版本
order: start-first # 更新顺序:先启动新容器,确认健康后再停止旧容器
rollback_config: # 回滚配置
parallelism: 1 # 回滚时并行数量
delay: 5s # 回滚延迟
resources: # 资源限制
limits: # 资源上限
cpus: "0.50" # 最多使用 0.5 个 CPU 核心
memory: "256M" # 最多使用 256MB 内存
reservations: # 资源预留
cpus: "0.25" # 预留 0.25 个 CPU 核心
memory: "128M" # 预留 128MB 内存
networks:
- frontend # 连接到 frontend 网络
networks:
frontend: # 定义 frontend 网络
driver: overlay # 使用 overlay 网络驱动,支持跨主机通信

View File

@@ -0,0 +1,100 @@
#!/bin/bash
# deploy-swarm.sh
set -e
# 仓库用户名
USER_NAME="bmy"
# 仓库密码
USER_PASSWORD="lb714500."
# 仓库地址
REGISTRY="registry.bmycode.help"
# 镜像名称
IMAGE_NAME="${REGISTRY}/app-product"
# tag 标签
TAG="v$(date +%Y%m%d-%H%M%S)"
# 完整路径
FULL_IMAGE="${IMAGE_NAME}:${TAG}"
# 工作服务器列表(多个服务器)
WORKER_HOSTS=("192.168.139.120" "192.168.139.242")
WORKER_USER="root"
WORKER_PASSWORD="lb714500."
echo "=== 1 登录私有镜像仓库 ==="
if ! echo "${USER_PASSWORD}" | docker login ${REGISTRY} -u ${USER_NAME} --password-stdin; then
echo "错误: 无法登录到私有仓库 ${REGISTRY}"
exit 1
fi
echo "=== 2 构建 app-product 镜像 ==="
docker build \
-f docker/Dockerfile \
-t ${FULL_IMAGE} \
-t ${IMAGE_NAME}:latest \
.
echo "=== 3 推送镜像到私有仓库 ==="
docker push ${FULL_IMAGE}
docker push ${IMAGE_NAME}:latest
echo "=== 4 在工作服务器上拉取最新镜像 ==="
for WORKER_HOST in "${WORKER_HOSTS[@]}"; do
echo ""
echo "正在连接到工作服务器: ${WORKER_HOST}"
if sshpass -p "${WORKER_PASSWORD}" ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null ${WORKER_USER}@${WORKER_HOST} "
echo '在工作服务器 ${WORKER_HOST} 上登录私有仓库...'
if echo '${USER_PASSWORD}' | docker login ${REGISTRY} -u ${USER_NAME} --password-stdin; then
echo '拉取最新镜像...'
docker pull ${FULL_IMAGE}
docker pull ${IMAGE_NAME}:latest
echo '镜像拉取完成'
echo '清理旧的 app-product 镜像...'
# 删除除了本次 FULL_IMAGE 和 latest 之外的所有 app-product 镜像
docker images ${IMAGE_NAME} --format 'table {{.Repository}}:{{.Tag}}' | \
grep -v '${FULL_IMAGE}' | \
grep -v '${IMAGE_NAME}:latest' | \
grep '${IMAGE_NAME}' | \
xargs -r docker rmi -f || true
else
echo '错误: 无法在工作服务器上登录私有仓库'
exit 1
fi
"; then
echo "✓ 服务器 ${WORKER_HOST} 镜像拉取成功"
else
echo "✗ 服务器 ${WORKER_HOST} 镜像拉取失败"
exit 1
fi
done
echo "=== 5 更新 docker-compose 文件中的镜像标签 ==="
sed "s|image: app-product:latest|image: ${FULL_IMAGE}|g" docker/app-product.yml > docker/app-product-deploy.yml
echo "=== 6 部署到 Swarm 集群 ==="
docker stack deploy -c docker/app-product-deploy.yml app-product
echo "=== 7 恢复原始配置文件 ==="
rm -f docker/app-product-deploy.yml
echo "=== 8 清理本地多余镜像 ==="
# 清理本地:删除除了本次 FULL_IMAGE 和 latest 之外的所有 app-product 镜像
echo "清理本地旧的 app-product 镜像..."
docker images ${IMAGE_NAME} --format 'table {{.Repository}}:{{.Tag}}' | \
grep -v "${FULL_IMAGE}" | \
grep -v "${IMAGE_NAME}:latest" | \
grep "${IMAGE_NAME}" | \
xargs -r docker rmi -f || true
# 清理悬空镜像
docker image prune -f
echo "=== 9 验证部署状态 ==="
docker stack ps app-product
echo "=== 部署完成 ==="

View File

@@ -0,0 +1,13 @@
version: "3.8"
services:
app-product:
build:
context: ..
dockerfile: docker/Dockerfile
image: app-product:1.0.0
container_name: app-product
ports:
- "1301:80"
restart: unless-stopped

View File

@@ -0,0 +1,13 @@
server {
listen 80;
server_name *.ddd.com;
location /app-product/ {
alias /usr/share/nginx/html/app-product/;
try_files $uri $uri/ /app-product/index.html;
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
}
}

View File

@@ -8,31 +8,32 @@
},
"scripts": {
"dev": "vite",
"dep": "concurrently \"npm run build\" \"npm run preview\"",
"dep": "concurrently \"vite build --watch\" \"sleep 5 && npm run preview\"",
"preview": "vite preview --port 1301 --strictPort",
"build": "vite build --watch",
"build": "vite build",
"type-check": "vue-tsc --build"
},
"dependencies": {
"less": "^4.4.1",
"pinia": "^3.0.3",
"vite-plugin-nacos": "link:../vite-plugin-nacos",
"vue": "^3.5.21",
"vite-plugin-nacos": "^1.1.3",
"vue": "^3.5.22",
"vue-router": "^4.5.1"
},
"devDependencies": {
"@element-plus/icons-vue": "^2.3.2",
"@originjs/vite-plugin-federation": "^1.4.1",
"@tsconfig/node22": "^22.0.2",
"@types/node": "^22.18.6",
"@types/node": "^24.6.1",
"@vitejs/plugin-vue": "^6.0.1",
"@vitejs/plugin-vue-jsx": "^5.1.1",
"@vue/tsconfig": "^0.7.0",
"element-plus": "^2.11.3",
"@vue/tsconfig": "^0.8.1",
"element-plus": "^2.11.4",
"npm-run-all2": "^8.0.4",
"rollup-plugin-visualizer": "^6.0.3",
"typescript": "~5.8.3",
"vite": "^7.1.6",
"typescript": "~5.9.3",
"vite": "^7.1.7",
"vite-federation": "^3.4.4",
"vite-plugin-vue-devtools": "^8.0.2",
"vue-tsc": "^3.0.7"
"vue-tsc": "^3.1.0"
}
}

View File

@@ -17,7 +17,7 @@ export default defineComponent({
<h2></h2>
<ul>
<li>1</li>
<li>2</li>
<li>2</li>
</ul>
<p></p>
</div>

View File

@@ -2,7 +2,7 @@ import { defineConfig, loadEnv } from 'vite';
import vue from '@vitejs/plugin-vue';
import vueJsx from '@vitejs/plugin-vue-jsx'
import vueDevTools from 'vite-plugin-vue-devtools'
import federation from '@originjs/vite-plugin-federation';
import federation from 'vite-federation';
import { fileURLToPath, URL } from "node:url";
import { visualizer } from 'rollup-plugin-visualizer';
import { reg, init } from 'vite-plugin-nacos';
@@ -10,9 +10,13 @@ import { reg, init } from 'vite-plugin-nacos';
export default defineConfig(async ({ mode }) => {
const env = loadEnv(mode, process.cwd());
const { VITE_MODEL_SHARED_URL } = await init(env)
// console.log("VITE_MODEL_SHARED_URL: ", VITE_MODEL_SHARED_URL);
return {
plugins: [
reg(),
federation({
name: env.VITE_SERVER_NAME,
remotes: {