1、前言
為了盡可能地輕量化前端鏡像(非node承載),將前端編譯成靜態資源通過nginx承載。
與后端程序不同的是,當使用靜態資源方式時頁面是直接加載到瀏覽器進行渲染,無法讀取服務端機器中 env
的環境變量。
當有部署多個環境(dev、uat、pro)需求時,就無法像后端程序一樣滿足生成一個鏡像部署不同環境。
如果你有同樣的需求請往下看。
2、使用ngx_http_js_module
njs是JavaScript語言的子集,它允許擴展nginx功能。njs的創建符合 ECMAScript 5.1 (嚴格模式)以及某些 ECMAScript 6 和更高版本的擴展。合規性還在不斷發展。
default.conf
主要關注 location /env { js_content getenv; }
部分內容,getenv 是一個 JavaScript function 函數。
server {
listen 80;
# listen 443;
# ssl on;
# ssl_certificate /etc/nginx/ssl/server.crt;
# ssl_certificate_key /etc/nginx/ssl/server.key;
server_name localhost;
#charset koi8-r;
#access_log /var/log/nginx/host.access.log main;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
try_files $uri $uri/ /index.html;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
location /env {
js_content getenv;
}
#error_page 404 /404.html;
# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
nginx.conf
主要關注 js_include env.js;
部分內容,引入js。
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
load_module modules/ngx_http_js_module.so;
events {
worker_connections 1024;
}
http {
js_include env.js;
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
#tcp_nopush on;
keepalive_timeout 65;
#gzip on;
include /etc/nginx/conf.d/*.conf;
}
env.js
對應 default.conf 中使用的方法。
function getenv(r) {
var strEnv = '{"Shortsha": "'+ process.env.SHORTSHA +'","UI_ENVIRONMENT": "'+ process.env.UI_ENVIRONMENT +'"}';
r.headersOut['Content-Type'] = "application/json; charset=utf-8";
r.return(200, strEnv);
}
- 效果示意
3、前端部分(以angular為例)
文件夾 /assets
中預先配置多個環境的配置文件 appconfig.dev.json 、appconfig.uat.json 、appconfig.pro.json
是不是和 .net core 中后端程序配置很像,啟動配置的環境變量 "ASPNETCORE_ENVIRONMENT": "Development"
配置文件 appsettings.json、appsettings.Development.json ...
同樣的道理只要在渲染生命周期比較開始的位置獲上文在 nginx 中配置的 env 地址中拿到環境配置在賦值到 AppConsts.remoteServiceBaseUrl
全局變量中。
private static getApplicationConfig(injector: Injector,httpClient: HttpClient,callback: () => void
) {
//能滿足ng build --|dev|uat|pro 編譯時指定不同環境變量
let envName = '';
if (environment.production) {
envName = 'pro';
} else {
envName = 'dev';
}
//nginx容器中環境變量
const envUrl = window.location.protocol + '//' + window.location.host + "/env";
httpClient.get(envUrl).subscribe(
(result: any) => {
envName = result.UI_ENVIRONMENT;
callback();
},
error => {
alert(`獲取環境變量出錯,信息:\n\n${error.message}`);
}
);
//assets 文件夾存放不同環境配置文件
const url = '/assets/appconfig.' + envName + '.json';
httpClient.get(url).subscribe(
(result: any) => {
//后端服務地址
AppConsts.remoteServiceBaseUrl = result.remoteServiceBaseUrl;
callback();
},
error => {
alert(`初始化配置出錯,信息:\n\n${error.message}`);
}
);
}
4、鏡像、部署
Dockerfile
在 ci\cd 流水線 build 拿到產出的 /dist 靜態資源打包Docker鏡像。
FROM nginx:1.17.3-alpine as base
EXPOSE 80
WORKDIR /usr/share/nginx/html
COPY /_nginx/nginx.conf /etc/nginx/nginx.conf
COPY /_nginx/env.js /etc/nginx/env.js
COPY /_nginx/default.conf /etc/nginx/conf.d/default.conf
COPY /dist /usr/share/nginx/html
CMD ["nginx", "-g", "daemon off;"]
部署的yaml中配置
value 中的值均通過流水線變量獲取,文中使用具體值示意。
env:
- name: UI_ENVIRONMENT
value: "uat" #流水線中不同分支對應不同環境
- name: SHORTSHA
value: "v1.0" #源碼倉庫的簽名
5、總結
水平有限,難免有所紕漏,歡迎批評指正。本文純屬拋轉引玉,大家有更好思路歡迎留言評論。