一、背景
nodejs应用程序,不同于java语言使用分布式配置,当部署于不同的环境里,因为环境的差异,配置项的值也不尽相同。
最常见的差异就是数据库的连接信息,而代码是一份,不能把生产环境的信息暴露在非生产环境。
所以,我们需要把差异值写在不同的配置文件里,比如我们本文要说的项目,它就有以下配置文件。
-rw-r--r-- 1 root root 2474 Nov 1 2022 config.default.js
-rw-r--r-- 1 root root 872 Jan 14 2019 config.local.js
-rw-r--r-- 1 root root 245 Aug 30 2022 config.prod.js
-rw-r--r-- 1 root root 72 Jan 14 2019 config.test.js
这是通过js配置文件的方式。
还有一类配置,通过环境变量的方式。比如很多语言的配置文件都是.env文件。
二、配置环境变量
这种方式比较常见,也比较简单。
docker run -it --name=webplay -p 5175:5174 -e "ALERT_LOG_LEVEL=info" -v /home/xxx/Documents/code/webPlayer/log:/root/logs xxx/webplay:1.0.0
这里的-e “ALERT_LOG_LEVEL=info”,把变量变量ALERT_LOG_LEVEL赋值为info。
如果是k8s,deployment.yaml文件,见下:
apiVersion: apps/v1
kind: Deployment
metadata:name: webplaynamespace: web-service
spec:template:metadata:labels:app: webplayspec:containers:- image: xxx/webplay:1.0.1imagePullPolicy: Alwaysname: webplaycommand:- npm- startenv:- name: TZvalue: Asia/Shanghai- name: ALERT_LOG_LEVELvalue: "info"# 后文略
三、ConfigMap持久化配置文件
接着上文所说,config.prod.js是生产环境的配置文件,其数据库连接地址是生产环境的,不能被暴露于开发环境。所以在构建docker image镜像的时候,该文件是不存在的,或者空的。
所以我们必须把config.prod.js的赋值放在生产,这就是代码和配置分离的原则。
怎么放呢?
这里采用了configMap,如果是docker或者docker-compose,使用-v映射即可。
1、新建configMap
apiVersion: v1
kind: ConfigMap
metadata:name: webplay-conf
data:config.prod.js: |/*** 生产环境配置** 最终生效的配置为 prod + default(前者覆盖后者)*/module.exports = app => {const exports = {};exports.mongoose = {client: {url: 'mongodb://{用户名}:{密码}@{host}:3717/webplay',options: {},},};exports.static = {maxAge: 0 // maxAge 缓存,默认 1 年};return exports;};
2、k8s deployment.yaml
添加一个卷(volume)来引用ConfigMap,并在容器的卷挂载(volume mount)部分指定挂载路径。
spec:selector:matchLabels:app: webplaytemplate:metadata:labels:app: webplayspec:containers:- command:- npm- startenv:- name: TZvalue: Asia/Shanghaiimage: >-xxx/webplay:1.0.1imagePullPolicy: Alwaysname: webplayvolumeMounts:- mountPath: /etc/localtimename: volume-localtime- mountPath: /opt/configname: configmap-volumevolumes:- hostPath:path: /etc/localtimetype: ''name: volume-localtime- configMap:defaultMode: 420items:- key: config.prod.jspath: config.prod.jsname: webplay-confname: configmap-volume
3、进入容器查看config.prod.js
如果你想只对config.prod.js进行差异配置,关于volume修改如下:
# 修改前volumeMounts:- mountPath: /opt/configname: configmap-volume
# 修改后volumeMounts:- mountPath: /opt/config/config.prod.jsname: configmap-volumesubPath: config.prod.js
对比修改前,/opt/config目录下的挂载有差异。修改前,config目录下只有configmap配置了的才挂载;而修改后,按需挂载文件,只有config.prod.js挂载,其他保持容器里的配置不变。
四、总结
因为涉及环境的差异,如何部署的时候指定不同的配置,是有状态部署必然需要解决的问题。
这里使用了环境变量和configmap两种方式,当然还可以使用分布式配置的方式。