[存档]前端部署流程概述

# 背景信息

前端代码,早期托管在内部SVN仓储中,地址 http://■■■■/svn 。后期托管在内部Git仓储中,地址 http://git.■■■■/ 。
部署环境有三套,分别为“开发(dev)”、“测试(test)”和“生产(test)”。测试环境域名为 https://static.■■■■/ ,生产域名为 https://static.■■■■/ 。
前端开发环境在不同语境下有所不同,现在语境或一般语境下即为开发人员本机,早期语境或开发服务器语境下是指IP为 ■■■■ 的服务器。
测试环境的Nginx只有一套,不区分“对内(内网)”和“对外(外网)”。生产环境的Nginx有两套,区分“对内(内网)”和“对外(外网)”,内外网之间有网络隔离,一般无法相互访问。

# 基于 Jenkins 和 SVN 的部署流程

早期的■■前端时代,统称为■■3.9版本,代码托管在SVN中,大概在2016年,■■4.0版本发布,代码更换了SVN目录。
此时的前端部署,并没有编译支持,更不存在环境相关配置,只是采用文件复制方式部署项目。在部署至不同环境前,前端开发需要手动修改环境相关的代码,或通过域名与URL参数等方式猜测当前运行环境。
概要流程如下:
1. 在相应版本的本地SVN目录中,提交代码至远程SVN服务器。■■3.9版本仓储在 http://■■■■/svn/style 中,■■4.0版本仓储在 http://■■■■/svn/■■4.0 中。
2. 远程SVN服务器自动触发Jenkins平台相应的Job流程。■■3.9版本触发 http://■■■■/job/UI_rsync_static/ 流程,■■4.0版本触发 http://■■■■/job/UI4.0_rsync_static/ 流程。
3. 被触发的Job流程,复制被变更的文件至多处。一个是开发服务器(即为SVN仓储所在的机器),一个是测试环境Nginx下的相应目录,一个是一台跳板下的相应目录。测试环境Nginx下的相应目录,此时已可通过测试环境域名 https://static.■■■■/ 访问。
4. 进入运维平台 http://■■■■/execute/minions_salt_get.html 的CDN管理菜单。
5. 定位至“静态资源同步”功能。在“文件或目录”文本域中按照要求填入,待同步的文件或目录路径,支持使用英文逗号分割的多个路径。选中“资源环境”中的“生产PROD”单选框。点击“同步”按钮就会将跳板机下相应目录内的文件,复制至生产环境的外网Nginx下相应目录。此时已可通过生产环境域名 https://static.■■■■/ 访问。如未能同步,请检查下方输出的操作日志。
6. 定位至“输入URL刷新CDN”功能。在“文件URL地址”文本域中按照要求填入,待刷新的文件或目录路径,支持使用英文逗号分割的多个路径。根据需要选中“文件类型”中的相应单选框。点击“提交”按钮就会将生产环境的外网Nginx下相应目录,同步至阿里CDN集群。此时已可通过CDN域名 https://static[1-4].■■■■/ 访问。如未能刷新,请检查下方输出的操作日志。

# 基于 Jenkins 和 Git 的部署流程

前端代码托管环境迁移到Git后,大部分项目增加了编译(构建)步骤,可传入相应的环境参数,构建产出的文件即为对应环境的版本。
Jenkins操作步骤:拉取Git仓储->构建指定分支代码->部署构建产出文件->在指定分支上打标签->推送回Git仓储。
详细流程请查看此处: 基于 Jenkins 和 Git 实现服务器构建和发布

[存档]活动项目构建方案

# 项目说明

H5活动项目,构建方案。
活动的特点是高频率,低技术要求,短生命周期,会产生大量废弃项目。
针对这些特点,该方案只处理有效项目,不限定每个项目的技术选型,只需按照约定放置构建脚本和输出文件即可。
项目需要放置于 projects/ 目录中,可使用 projects/.buildignore 忽略指定项目目录。
若项目不需要 npm 和 gulp 处理,则可直接将文件放置于 projects/XXX/ 目录中。构建后该目录中文件(夹)将被复制到 dist/XXX/ 目录。
若项目需要 npm 和 gulp 处理,则必须存在 projects/XXX/gulpfile.js 和 projects/XXX/package.json 文件。构建后 projects/XXX/dist/ 中文件(夹),将被复制到 dist/XXX/ 目录

# 目录结构

dist/ [多]项目构建根目录。
dist/XXX/ [单]项目构建目录。
projects/ [多]项目源文件根目录。
projects/.buildignore 明确过滤不参与构建的项目。
gulpfile.js [多]项目 gulp 配置文件。
package.json [多]项目 npm 配置文件。
projects/XXX/ [单]项目源文件目录。
projects/XXX/dist/ [单]项目构建目录。
projects/XXX/gulpfile.js [单]项目 gulp 配置文件。
projects/XXX/package.json [单]项目 npm 配置文件。

# 常用命令

建议以 package.json 文件的 scripts 节点作为命令行入口。
npm run clean 清理[多]项目构建根目录和[单]项目构建目录。
npm run state 检查可参与构建的有效项目列表。
npm run build:dev 构建项目(开发环境)。
npm run build:test 构建项目(测试环境)。
npm run build:prod 构建项目(生产环境)。

# 构建流程

1. 检查环境参数 –env 的值,准备传递给有效项目的构建脚本。
2. 解析 projects/.buildignore 文件,获取不参与构建的项目列表。
3. 获取 projects/ 目录下的子目录列表,作为全部项目列表。
4. 在全部项目列表中排除被忽略的项目,得到过滤后的项目列表。
5. 遍历过滤后的项目列表,检查该项目目录在最近几天的 Git 日志,有记录才认为有效,得到有效项目列表。
6. 遍历有效项目列表,检查是否存在 projects/XXX/gulpfile.js 和 projects/XXX/package.json 文件。
7. 如果不存在,直接复制 projects/XXX/ 中文件(夹),至 dist/XXX/ 目录。
8. 如果存在,在该项目目录先执行 npm install 安装 npm 依赖,再执行 gulp build –env=<dev|test|prod> 调用构建任务,最后复制 projects/XXX/dist/ 中文件(夹),至 dist/XXX/ 目录。
9. 重复每个有效项目的构建流程,直至全部结束。

[存档]基于 Jenkins 和 Git 实现服务器构建和发布

# 准备工作

## Git Repository

1. 待发布的 Git 仓储,如 git@git.■■■■:group/project.git 仓储。
2. 待发布的 Git 分支,如 dev-v1.0.0 分支。
3. 仓储根下 /dist/ 目录,如 /dist/1.0.0/home.index.html 文件。
4. [可选]仓储根下 /package.json 文件,含有 dependencies 或 devDependencies 节点。
5. [可选]仓储根下 /gulpfile.js 文件,含有 build 任务。

## Jenkins Job

1. 向配置管理员(■■■) 申请创建各个环境的 Job 配置。
2. 提供项目的 Git 仓储地址和默认发布的 Git 分支名。
3. 告知是否存在 /package.json 文件,即是否需要安装项目依赖。
4. 告知是否存在 /gulpfile.js 文件,即是否需要执行构建任务。
5. 申请为 Job 分配相应的管理人员和操作权限。

# 构建发布

## 环境配置

1. node v6.9.2
2. npm 3.10.9
3. cnpm 4.4.2
4. gulp 3.9.1

##平台流程

1. Jenkins 平台为每个 Job 分配相应的工作目录,可手工或自动清理该目录。
2. 找到相应 Job 后,触发 Build 或 Build with Parameters 操作。
3. 填写需要发布的 Git 分支名,生产环境固定为 master 分支。
4. 拉取指定的 Git 仓储和分支,放置于相应的工作目录。
5. [可选]执行 cnpm install 命令,查找 /package.json 文件,安装 npm 依赖。
6. [可选]执行 gulp build –env=<dev|test|prod> 命令,查找 /gulpfile.js 文件,调用 build 任务。
7. 增量复制 /dist/ 目录下哈希值变更的文件,至 nginx 服务器指定目录下,如 /usr/■■■■/group/project/ 目录。
8. 生产环境发布后,平台会自动刷新当前目录在 CDN 中的缓存,刷新功能有每日次数限制。
9. 生产环境发布后,平台会在当前分支自动创建标签,格式为 release_yyyy-MM-DD_${BUILD_NUMBER} 标准。
10. 可通过域名访问,检查是否部署成功,如测试地址 https://static.■■■■/■■■■/group/project/1.0.0/home.index.html 或生产地址 https://static.■■■■/■■■■/group/project/1.0.0/home.index.html 路径。

[可选]使用业务域名访问入口页面

上述流程结束后,入口页面需要使用 static.■■■■ 或 static.■■■■ 域名访问,并携带长长的 /■■■■/group/project/1.0.0/home.index.html 路径。
如果希望使用自定义的业务域名访问,如 xxx.■■■■/1.0.0/home.index.html 或 xxx.■■■■/1.0.0/home.index.html 方式,需要运维对Nginx进行配置。
测试环境的Nginx只有一套,不区分“对内(内网)”和“对外(外网)”。生产环境的Nginx有两套,区分“对内(内网)”和“对外(外网)”,内外网之间有网络隔离,一般无法相互访问。
运维在相应环境(生产环境一般是对外)的Nginx中,将 xxx.■■■■ 或 xxx.■■■■ 映射至 /usr/■■■■/group/project/ 目录。即拦截该域名下的所有请求至前端部署目录。
如果后端接口在同一个域名下,如 xxx.■■■■/path/file.json 接口,就需要运维识别并转发(非重定向)部分请求至后端服务器。
我们约定运维拦截以 api 目录开头的路径,并将后续的路径(不含 api 目录)转发至后端服务器。此时前端需要在原接口请求的路径中加入 api 目录。
如:前端发出接口请求 xxx.■■■■/api/path/file.json 被Nginx拦截并转发后,后端接收到的请求路径为 /path/file.json 并不知道上层路径结构。
注意:此方案将拦截全部非 api 目录的请求,即意味着无法处理同步 404 和 500 等网络请求错误。且如需使用第三方支付系统回调通知校验等业务场景,就需要在 api 目录中指定相应处理路径。

互联网基础设施的稳定性

昨天(2017-08-21)下午微信故障,由于影响到大量普通用户使用,故障被迅速传播广而告之。
当时同事正在开发微信分享相关功能,发现分享失败后与我讨论。推测是由于被人举报遭到封禁,准备去联系公司微信帐号的运营人员,确认是否被封禁。
好在还没出发就收到微信故障相关的消息,避免了一场无用之功。

感慨科技的进步和社交网络的繁荣,让我这个刻意远离社交的“边缘人”也能享受它带来便利,虽然也带来了不少的烦恼。
更感慨随着网络的触角深入到社会的各个角落,互联网基础设施的稳定性,已经极大的影响了工作和生活。至少在大陆,微信已经算得上基础设施了。
虚拟和现实的界限更加模糊了。

联想到几年前的一次“基础设施”BUG,作为(有可能是第一梯队的)亲历者。
现在看来,与这次微信故障,有些挺有意思的共同点。

2013-09-12 接到客户反馈,前几天上线的文件上传功能中文件名出现乱码。上传功能是SWFUpload做的。
在那个年代,HTML5还没定稿,XP自带的IE6还占据不少市场,各种双核浏览器满天飞,兼容性参差不齐。作为竞争者的Silverlight停止开发,而Flash刚显出没落迹象。基于Flash的SWFUpload上传控件,虽然已多年未更新,但却是当时最合适的解决方案。

跟之后的“基础设施”BUG一样,首先被怀疑的是刚上线的代码。这似乎是一个合格程序猿的标准流程,从业务代码开始逐步深入底层系统,先自我否定 🙂
毕竟业务错误是高频的,而基础设施错误相对低频多了,但也更加致命。
尤其是一个被私人公司掌控的“基础设施”,一旦出现错误只能等待所属公司的修复。这应该也是Flash没落的一个原因吧,毕竟社区的才是大家的。

经过一上午的自查和检索,却没有任何收获。终于在下午有了线索,iteye有人发出了类似的疑问。看到问题的一瞬间,我马上意识到,这不是业务代码和SWFUpload的BUG,而是Flash的BUG。
思路转变后,一切就顺利成章了,最简单的解决方案就是回滚至旧版本,等待Adobe公司更新。
但不可能让所有用户回滚至旧版本,也没有人知道Adobe公司什么时候(现在知道是2013-09-19)才能修复BUG,在此之前只能尝试自己解决。

从SWFUpload暴露的API入手,找到了临时解决方案。又梳理SWFUpload源码(感谢开源社区)的调用逻辑,找到关键点提出修复方案。可惜由于环境问题,未能编译成功。好在社区中有其他人成功编译,算是提供了相对完美的解决方案。
这应该算是我第一次真正参与社区事件,事后竟有一丝弱弱的自豪感。哈哈

参考链接:
关于SWFUpload文件名乱码
Flash11.8更新后SWFUpload出现乱码问题
SWFUpload源码(官网已失效,找到的替代资源)
Adobe的BUG反馈(链接已失效)
Release Notes | Flash Player® 11.8 AIR® 3.8

截张图留念一下