# 配置和运行环境

在使用Egg框架进行多环境部署时,配置很大程度上决定了运行环境,当然使用什么的运行环境,框架也合并配置进行处理;

# 运行环境

一个 Web 应用本身应该是无状态的,并拥有根据运行环境设置自身的能力(很明确的为多环境部署提供有效方案)

框架提供两种指定实际运行环境的而方式:

  • 通过 config/env 文件指定,该文件的内容就是运行环境,如 prod。一般通过构建工具来生成这个文件。
## config/env
## prod环境,一般指上线正式环境
config.prod.js 

  • 通过 EGG_SERVER_ENV 环境变量指定运行环境更加方便,比如在生产环境启动应用
## 启动指定里添加EGG_SERVER_ENV=prod

EGG_SERVER_ENV=prod npm start


# 获取方式

项目里,可以很容易的通过app.cifng.env来确定应用的当前环境

# EGG_SERVER_ENV和NODE_ENV的比较

很多 Node.js 应用会使用 NODE_ENV 来区分运行环境,但 EGG_SERVER_ENV 区分得更加精细。一般的项目开发流程包括:

  • 本地开发环境
  • 测试环境
  • 生产环境

除了本地开发环境和测试环境外,其他环境可统称为服务器环境,服务器环境的 NODE_ENV 应该为 production

框架默认支持的运行环境及映射关系(如果未指定 EGG_SERVER_ENV 会根据 NODE_ENV 来匹配)

当 NODE_ENV 为 production 而 EGG_SERVER_ENV 未指定时,框架会将 EGG_SERVER_ENV 设置成 prod。

NODE_ENV EGG_SERVER_ENV 说明
- local 本地开发环境
test unittest 单元测试
production prod 生产环境

npm 也会使用这个变量,在应用部署的时候一般不会安装 devDependencies,所以这个值也应该为 production。

# 自定义启动环境

常规开发流程可能不仅仅只有以上几种环境,Egg 支持自定义环境来适应自己的开发流程。

例如,要为开发流程增加集成测试环境 SIT。将 EGG_SERVER_ENV 设置成 sit(并建议设置 NODE_ENV = production),启动时会加载 config/config.sit.js,运行环境变量 app.config.env 会被设置成 sit。

## 自定义sit环境
config/config.sit.js

  • 在 Koa 中我们通过 app.env 来进行环境判断,app.env 默认的值是 process.env.NODE_ENV
  • 在 Egg(和基于 Egg 的框架)中,配置统一都放置在 app.config 对象上,需要通过 app.config.env 来区分环境,app.env 不再使用(实际使用会有废弃报告)

注意:process对象node.js中提供的内置对象,可以从中获取很多系统信息,用途极大!

# Config配置

框架提供了强大且可扩展的配置功能,可以自动合并应用、插件、框架的配置,按顺序覆盖,且可以根据环境维护不同的配置。合并后的配置可直接从 app.config 获取。

配置的管理的常见方案:

  • 使用平台管理配置,应用构建时将当前环境的配置放入包内,启动时指定该配置。但应用就无法一次构建多次部署,而且本地开发环境想使用配置会变的很麻烦。
  • 使用平台管理配置,在启动时将当前环境的配置通过环境变量传入,这是比较优雅的方式,但框架对运维的要求会比较高,需要部署平台支持,同时开发环境也有相同痛点。
  • 使用代码管理配置,在代码中添加多个环境的配置,在启动时传入当前环境的参数即可。但无法全局配置,必须修改代码。

最后一种配置方案,配置即代码,配置的变更也应该经过 review 后才能发布。应用包本身是可以部署在多个环境的,只需要指定运行环境即可。

# 多环境配置

框架支持根据环境来加载配置,定义多个环境的配置文件

config
|- config.default.js ## 开发环境
|- config.prod.js   ## 生产环境
|- config.unittest.js ## 测试环境
|- config.local.js  ## 本地环境

config.default.js 为默认的配置文件,所有环境都会加载这个配置文件,一般也会作为开发环境的默认配置文件。

当指定 env 时会同时加载默认配置和对应的配置(具名配置)文件,具名配置和默认配置将合并(使用extend2深拷贝)成最终配置,具名配置项会覆盖默认配置文件的同名配置

例如:

  • prod 环境会加载 config.prod.jsconfig.default.js 文件,config.prod.js会覆盖 config.default.js 的同名配置。

  • test 环境会加载 config.test.jsconfig.default.js 文件,config.test.js会覆盖 config.default.js 的同名配置。

# 配置的写法

配置文件返回的是一个 object 对象,可以覆盖框架的一些配置,应用也可以将自己业务的配置放到这里方便管理。

// 配置 logger 文件的目录,logger 默认配置由框架提供
module.exports = {
  logger: {
    dir: '/home/admin/logs/demoapp',
  },
};

了解node的exports用法的应该直到,还可以这样写:

// 配置文件也可以简化的写成 exports.key = value 形式
exports.keys = 'my-cookie-secret-key';
exports.logger = {
  level: 'DEBUG',
};

配置文件也可以返回一个 function,可以接受 appInfo 参数

const path = require('path');

module.exports = appInfo => {
  return {
    logger: {
      // 将 logger 目录放到代码目录下
      dir: path.join(appInfo.baseDir, 'logs'),
    },
  };
};

// 注意,内置的appInfo对象的属性有:

// - pkg   package.json信息
// - name  应用名,和pkg.name的值一致
// - baseDir 项目代码的目录
// - HOME  用户目录,如 root 账户为 /home/root
// - root  应用根目录,只有在 local 和 unittest 环境下为 baseDir,其他都为 HOME

appInfo.root 是一个优雅的适配,比如在服务器环境我们会使用 /home/root/logs 作为日志目录,而本地开发时又不想污染用户目录,这样的适配就很好解决这个问题。

# 加载顺序

在应用、插件、框架都可以定义这些配置,而且目录结构都是一致的,但存在优先级(应用 > 框架 > 插件),相对于此运行环境的优先级会更高。

比如在 prod 环境加载一个配置的加载顺序如下,后加载的会覆盖前面的同名配置。

-> 插件 config.default.js
-> 框架 config.default.js
-> 应用 config.default.js
-> 插件 config.prod.js
-> 框架 config.prod.js
-> 应用 config.prod.js


插件之间也会有加载顺序,但大致顺序类似,

# 合并规则

框架直接覆盖数组而不是进行合并,例如:

const a = {
  arr: [ 1, 2 ],
};
const b = {
  arr: [ 3 ],
};
extend(true, a, b);
// => { arr: [ 3 ] }

配置的合并使用 extend2 模块进行深度拷贝,处理数组时会存在差异。

# 配置结果

框架在启动时会把合并后的最终配置 dump 到 run/application_config.json(worker 进程)和 run/agent_config.json(agent 进程)中,可以用来分析问题。

配置文件中会隐藏一些字段,主要包括两类:

  • 如密码、密钥等安全字段,这里可以通过 config.dump.ignore 配置,必须是 Set 类型,查看默认配置。

  • 如函数、Buffer 等类型,JSON.stringify 后的内容特别大

还会生成 run/application_config_meta.json(worker 进程)和 run/agent_config_meta.json(agent 进程)文件,用来排查属性的来源,如:

{
  "logger": {
    "dir": "/path/to/config/config.default.js"
  }
}

最近更新: 1/19/2021, 11:03:12 PM