优化前端部署服务
现状描述
按不同环境编译
每个环境都要编译一次
# 测试环境
npm run build:test1
npm run build:test2
npm run build:test3
# 预生产环境
npm run build:pre
# 生产环境
npm run build:prod
项目测试 test, pre, prod 每个环境都编译一次,会有不确定性
优点
简单,针对某一个环境单独编译部署
缺点
- 比较耗时,每个环境都需要独立编译一次。
- 不同环境都需要变更,预览环境无法达到预览的效果。
- 制品库比较重
一次编译多次部署
# 项目构建
npm run build
一次编译,通过不同环境变量对环境进行区分。
优点:稳定性
缺点:相比多次编译会复杂些
- 区分编译与部署
- 编译时的环境变量,迁移到项目上外部由Nginx维护
- 制品库轻量化
收益
- 提高全流程部署效率。
- 稳定性,预览环境与生产环境部署的代码是完全一样的。
- 统一前端全局env变量。
使用示例
环境配置 config
const envConfig = {
'test1': {
'api': 'https://test1-api.xxxxx.com'
},
'test2': {
'api': 'https://test2-api.xxxxx.com'
},
'pre': {
'api': 'https://pre-api.xxxxx.com'
},
'prod': {
'api': 'https://api.xxxxx.com'
},
}
取得配置
const html = document.getElementsByTagName('html')[0]
const env = html.getAttribute('env')
const currentConfig = envConfig[env]
const api = currentConfig['api']
// 取得不同环境下的api前缀
DevOps相关
nginx配置&输出
test测试环境
sub_filter '<html>' '<html env="test" lang="zh-cmn-Hans">';
sub_filter_types text/html;
sub_filter_once on;
输出HTML
<!DOCTYPE html>
<html env="test" lang="zh-cmn-Hans">
... ...
</html>
预生产环境
sub_filter '<html>' '<html env="pre" lang="zh-cmn-Hans">';
sub_filter_types text/html;
sub_filter_once on;
输出HTML
<!DOCTYPE html>
<html env="pre" lang="zh-cmn-Hans">
... ...
</html>
生产环境
sub_filter '<html>' '<html env="prod" lang="zh-cmn-Hans">';
sub_filter_types text/html;
sub_filter_once on;
输出HTML
<!DOCTYPE html>
<html env="prod" lang="zh-cmn-Hans">
... ...
</html>
注入环境变量
顶层nginx.conf
http {
# test.xxxx.com
server {
listen 80;
server_name test.xxxx.com;
location / {
sub_filter '<html>' '<html env="test" lang="zh-cmn-Hans">';
sub_filter_types text/html;
sub_filter_once on;
root html;
index index.html index.htm;
try_files / /index.html;
}
}
# pre.xxxx.com
server {
listen 80;
server_name pre.xxxx.com;
location / {
sub_filter '<html>' '<html env="pre" lang="zh-cmn-Hans">';
sub_filter_types text/html;
sub_filter_once on;
root html;
index index.html index.htm;
try_files / /index.html;
}
}
# www.xxxx.com
server {
listen 80;
server_name www.xxxx.com;
location / {
sub_filter '<html>' '<html env="prod" lang="zh-cmn-Hans">';
sub_filter_types text/html;
sub_filter_once on;
root html;
index index.html index.htm;
try_files / /index.html;
}
}
}
docker服务注入
服务启动时执行一条命令,将当前的参数注入到nginx.conf文件中
default.conf.template
http {
# test.xxxx.com
server {
listen ${NGINX_PORT};
server_name ${NGINX_HOST};
location / {
sub_filter '<html>' '<html env="${NGINX_ENV}" lang="zh-cmn-Hans">';
sub_filter_types text/html;
sub_filter_once on;
root html;
index index.html index.htm;
try_files / /index.html;
}
}
docker file
web:
image: nginx
volumes:
- ./templates:/etc/nginx/templates
ports:
- "8080:80"
environment:
# - NGINX_HOST=foobar.com
# - NGINX_PORT=80
# - NGINX_ENV
启动服务命令
test 环境
docker run -d --name nginx -e NGINX_PORT=80 -e NGINX_ENV=test nginx:latest
pre 环境
docker run -d --name nginx -e NGINX_PORT=80 -e NGINX_ENV=pre nginx:latest
prod 环境
docker run -d --name nginx -e NGINX_PORT=80 -e NGINX_ENV=prod nginx:latest
Nginx文档: https://hub.docker.com/_/nginx
K8S 部署
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: xxxx-market
spec:
replicas: 1
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge:
maxUnavailable: 0
minReadySeconds: 5
revisionHistoryLimit: 10
template:
metadata:
labels:
app: xxxx-market
spec:
containers:
- name: xxx-market
image: 192.168.100.33:1179/xxxx-market:test-1.0.0-41529e
imagePullPolicy: Always
ports:
- containerPort: 80
environment:
# - NGINX_HOST=xxxx.com
# - NGINX_PORT=80
- NGINX_ENV=pre
readinessProbe:
httpGet:
path: /
port: 80
重新加载SVC
$ kubectl --kubeconfig=/kubectl_config_test --namespace=test apply -f svc.yml --record
滚动部署 deploy
$ kubectl --kubeconfig=/kubectl_config_test --namespace=test apply -f deploy.yml --record