一、背景
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: webplay
namespace: web-service
spec:
template:
metadata:
labels:
app: webplay
spec:
containers:
- image: xxx/webplay:1.0.1
imagePullPolicy: Always
name: webplay
command:
- npm
- start
env:
- name: TZ
value: Asia/Shanghai
- name: ALERT_LOG_LEVEL
value: "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: webplay
template:
metadata:
labels:
app: webplay
spec:
containers:
- command:
- npm
- start
env:
- name: TZ
value: Asia/Shanghai
image: >-
xxx/webplay:1.0.1
imagePullPolicy: Always
name: webplay
volumeMounts:
- mountPath: /etc/localtime
name: volume-localtime
- mountPath: /opt/config
name: configmap-volume
volumes:
- hostPath:
path: /etc/localtime
type: ''
name: volume-localtime
- configMap:
defaultMode: 420
items:
- key: config.prod.js
path: config.prod.js
name: webplay-conf
name: configmap-volume
3、进入容器查看config.prod.js
如果你想只对config.prod.js进行差异配置,关于volume修改如下:
# 修改前
volumeMounts:
- mountPath: /opt/config
name: configmap-volume
# 修改后
volumeMounts:
- mountPath: /opt/config/config.prod.js
name: configmap-volume
subPath: config.prod.js
对比修改前,/opt/config目录下的挂载有差异。修改前,config目录下只有configmap配置了的才挂载;而修改后,按需挂载文件,只有config.prod.js挂载,其他保持容器里的配置不变。
四、总结
因为涉及环境的差异,如何部署的时候指定不同的配置,是有状态部署必然需要解决的问题。
这里使用了环境变量和configmap两种方式,当然还可以使用分布式配置的方式。