|
增加配置覆盖功能
上面的 webserver 设计还是简单了一些,因为平时我们配置服务的时候,经常会有一系列通用的配置,而每个环境里面可能各有一些少量特殊的配置。
为了解决这个问题,我们在前面的方案基础之上,开发了一个简单的配置覆盖功能。我们是这么做的:
在 config 文件夹当中提供一个 defaul.yml 配置文件,在这个文件当中去保存通用的配置数据
假设,现在要访问 dev 环境的配置,webserver 就把 dev.yml 和 default.yml 配置文件都读取出来,将 dev.yml 和 default.yml 重合的部分 merge 到一起,这块我们使用的一个叫做 deepmerge 的模块来实现的
现在举一个实际的例子,假设生产(prod)和开发环境(dev)就数据库的名称不同,没有增加配置覆盖功能之前,配置文件是这样的:
# prod.yml
mysql:
host: localhost
port: 3306
username: root
password: root
database: prod
# dev.yml
mysql:
host: localhost
port: 3306
username: root
password: root
database: de
|
增加了配置覆盖的功能之后,配置文件变成了下面这个样子:
# default.yml
mysql:
host: localhost
port: 3306
usrename: root
password: root
# prod.yml
mysql:
database: prod
# dev.yml
mysql:
database: dev
|
在实际的项目当中,增加配置覆盖的一个最大好处是,有新的同事加入项目时,他需要增加的配置内容就会少很多,而不需要全量的 copy 一份别人的配置文件,主体的配置都可以放到 default.yml 文件中。
安全问题
这个方案现在还有一些明显的安全问题:
接口访问没有增加鉴权
有些数据就是不希望写到代码当中去,该怎么办
关于接口鉴权,我们的解决方案是提供一个 token 列表,token 是常量的 UUID 或者随机字符串即可。另外强制要求使用 https 来访问接口,不要直接在前端读取配置。
如果有些数据就是不希望写到代码当中去,改怎么办?
我们建议增加一个环境变量注入的 feature,比如配置文件改写成这样:
mysql:
password: ${MYSQL_PASSWORD}
|
接口在返回数据之前,增加一道工序,将上面的 ${MYSQL_PASSWORD} 这类的表达式解析出来,然后将环境变量注入进去。我们目前是使用正则表达式简单粗暴的处理的,大概就是这样:
const traverse = require('traverse');
const delimeter = /\$\{(.+?)\}/g;
function enjectEnv(config) {
return traverse(config).map(value => {
value.replace(delimeter, (match, p1) => {
return process.env[p1] || "";
})
})
}
|
通过这种方式,你就可以通过环境变量去配置一些敏感信息了。
总结
总结一下,这样一个方案,主要的工作:
基于 git 和 CI/CD 搭建配置服务
提供统一的客户端 library
扩展功能,增加配置覆盖机制
提供简单的接口鉴权和环境变量注入
这样一个方案,其实在产品初期阶段应该足够好用了。这种方案的好处就是快速占坑,将配置管理机制固化下来。整套方案充分使用了 git 和 CI/CD,整个服务也很轻,推荐大家尝试一下~
|
|