事件背景#
部门内同时有多项业务的存在,为了便于访问和管理,整个系统采用乾坤架构,每个业务开发自己的子应用,然后统一挂载到基座应用使用。其大致结构如下:
➜ Project tree
.
├── ASCM
│ └── index.html
├── OSCM
│ └── index.html
├── PSCM
│ └── index.html
├── TMS
│ └── index.html
├── VSCM
│ └── index.html
├── assets
│ ├── dist.css
│ └── dist.js
└── index.html
7 directories, 8 files
在过去相当长的一段时间里,我们的全部应用都是在编译机器上编译打包后上传,然后 Nginx 中直接指定静态文件目录来访问。配置如下:
server {
listen 80;
server_name xxx.test.demo.local;
client_max_body_size 15M;
access_log logs/halley.access.log log_access; # 日志输出目录
gzip on;
gzip_min_length 1k;
location ^~ / {
root /mnt/work/h5/project-dist/;
index index.html index.htm;
try_files $uri $uri/ /index.html;
}
}
本来这是很普通常用的方案。但是由于内部运维平台自身的一些问题,在把新的主应用部署到生产环境的时候(测试和预发没有问题),会直接清空掉整个 Project 文件夹的内容再释放新资源,而不是单纯的覆盖。这就意味着每次更新都会清空掉内部的子应用,使得基座发版 === 重新发布全部应用
虽然发版频率并不高(一个月两次左右),但是随着子应用的数目增加,这依旧成了一项很重的负担。更不论某些和工厂相关的应用白天不能中断,只能放到半夜一起更新,遂萌生了彻底解决问题的念头。
然而,在和运维沟通后,得知现在使用的运维平台几乎无人维护,有需求要自行迁移到另一套系统。
迁移过程#
发布原理#
在中台上使用容器作为构建环境,读取仓库内用户自行编写的 build.sh 进行构建,构建后将 dist 目录下的产物推送到 oss/s3 上,然后通过内部路由将 url 解析到 index.html 的 oss/s3 地址上。
项目更新#
编写脚本#
在项目下新增 build.sh,内容为
#! /bin/sh
. ~/.profile
yarn install --registry http://npm.xxxx.local:7001 --ignore-engines
export CICD_STATIC_PATH=$(echo $CICD_STATIC_PATH) && yarn build
构建系统会把本次构建内容的 oss 地址存储为 CICD_STATIC_PATH
变量,在脚本中自行获取后传递给 webpack 用以构建资源。
更新 Webpack#
修正 webpack.config.js 中相关资源路径
const publicPath = {
dev: `http://${process.env.HOST}:${process.env.PORT}/`,
production: process.env.CICD_STATIC_PATH
};
{
path: __dirname + '/dist/', // 将打包好的文件放在此路径下,dev 模式中,只会在内存中存在,不会真正的打包到此路径
publicPath: publicPath[process.env.NODE_ENV], // 文件解析路径,index.html 中引用的路径会被设置为相对于此路径
filename: process.env.NODE_ENV === 'dev' ? 'bundle.js' : 'bundle-[contenthash].js' // 编译后的文件名字
}
更新 Nginx 配置#
server {
listen 80;
server_name xxx.test.demo.local;
client_max_body_size 15M;
access_log /var/log/nginx/halley.access.log ; # 日志输出目录
gzip on;
gzip_min_length 1k;
location ^~ / {
proxy_set_header X-Scheme $scheme; # 传递协议
proxy_set_header Host apisix-area.test.demo.com; # 传递域名
proxy_set_header X-Real-IP $remote_addr; # 传递 ip
proxy_set_header REMOTE-HOST $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
add_header X-Rewrite-Result $uri;
proxy_intercept_errors on;
error_page 400 403 404 500 = 200 /index.html;
proxy_pass http://apisix-area.test.demo.com/xxx/xxx-project/;
}
}
其中 http://apisix-area.test.demo.com
由运维统一提供,静态资源路径在构建时由 shell 脚本从 CICD_STATIC_PATH
变量读取。
更新后不再使用静态资源,而是完全通过 proxy_pass 代理到远程 oss 上的资源进行访问。由于项目是 React 构建,拥有自己的前端路由,并且 js/css 等静态资源会被自动上传到 CICD_STATIC_PATH
这个域名下,所以此处只需要把访问失败的请求全都代理到 oss 上的 index.html 即可。
题外话#
配置 Nginx 的时候自行在本地用 docker 起一个服务来做测试会方便一点,免得更新服务端配置又要没完地扯皮。感觉其中很多时间都浪费在了找人和走流程上面,蛮不愉快的。