是什么

环境变量(Environment Variables):操作系统提供给进程的键值对,进程可以在运行时读取。

特点:

  • 由父进程传给子进程(继承);
  • 进程可以读取,通常不应修改(修改只影响自身和后续子进程);
  • 在 Unix/Linux/macOS 和 Windows 上都支持。

常见用途

  • PATH:可执行文件搜索路径;
  • HOME / USERPROFILE:用户主目录;
  • LANG / LC_ALL:语言和区域设置(影响字符编码默认值的推断);
  • JAVA_HOME / GOPATH 等:工具链路径;
  • 应用程序的自定义配置。

为什么配置喜欢用它

一、与代码分离

十二要素应用(The Twelve-Factor App)方法论建议:把配置存储在环境中。

理由:

  • 同一份代码可以在不同环境(开发、测试、生产)用不同配置运行;
  • 不需要为不同环境打不同的包;
  • 配置变更无需重新构建。

二、与部署环境天然契合

容器(Docker)和云原生平台(Kubernetes)都原生支持环境变量:

docker run -e DATABASE_URL=... myapp
env:
  - name: DATABASE_URL
    valueFrom:
      secretKeyRef: ...

这比挂载配置文件更轻量、更容易在编排层面管理。

三、语言无关

所有编程语言都能读取环境变量——不需要统一的配置文件格式。

局限与风险

一、只适合小段文本

环境变量适合简单的键值对。复杂的嵌套配置(YAML/JSON 结构)不适合塞进环境变量。

二、不是"隐藏"的安全措施

一个常见误解:把密钥放在环境变量里就安全了。

实际上:

  • 环境变量对进程可见(在 Linux 上可以通过 /proc/<pid>/environ 读取,如果权限允许);
  • 子进程会继承环境变量——如果你的应用启动了子进程,密钥就传递过去了;
  • 很多错误上报工具、日志框架会在崩溃时转储环境变量——导致密钥泄露;
  • 在容器环境中,docker inspect 可以看到环境变量。

结论:环境变量是"方便",不是"安全"。

敏感配置的正确做法:使用专门的密钥管理服务(Vault、云厂商的 KMS/Secrets Manager、Kubernetes Secrets 配合加密),并在运行时注入。

三、类型都是字符串

环境变量的值都是字符串。需要自己做类型转换和校验。

四、修改需要重启

进程在启动时读取环境变量,运行中修改通常不生效(除非应用主动重新读取)。

五、优先级容易混乱

配置来源可能有:默认值、配置文件、环境变量、命令行参数、远程配置中心。

优先级必须明确并在文档中说明,否则排查"这个配置到底从哪来的"会很痛苦。

实践建议

  • 明确优先级:通常 命令行参数 > 环境变量 > 配置文件 > 默认值;
  • 所有环境变量都要有校验——缺失时给出清晰的错误信息,而不是运行时崩溃;
  • 提供 .env.example,列出所有必需和可选项(但不要提交包含真实密钥的 .env);
  • .env 文件要加入 .gitignore;
  • 不要在日志或错误信息中打印环境变量的值;
  • 敏感信息用密钥管理服务,环境变量只作为传递通道。

一个实用模式

# .env.example(提交到仓库)
DATABASE_URL=postgres://user:password@localhost:5432/dbname
REDIS_URL=redis://localhost:6379
LOG_LEVEL=info

开发者复制为 .env 并填入自己的值。.env 不提交。

说明:本文为配置管理的知识整理。