全栈容器化应用的环境变量管理
全栈容器化应用的环境变量管理
理解一个复杂程序的运行逻辑,一个方式是找到它的 Main 函数,观察各个对象的生命周期。这能让我们把握程序的运行途径,而不是迷失在散落各处的类文件中。理解一个系统的配置管理,我们也可以采用类似的视角。当我们构建一个前后端分离项目,并希望通过 Docker 进行容器化部署时,如何管理配置?以 FastAPI + Vue/TypeScript + PostgreSQL 为例,整理一下环境变量管理方案。
核心原则:配置与代码分离
无论是在前端、后端还是数据库层,都要遵循一个核心原则:代码中定义配置的结构,而由环境变量注入具体的值。配置管理的物理载体通常是项目根目录下的 .env 文件。
大多数现代工具库和 Docker 都遵循一套标准的优先级逻辑:
- 系统级环境变量(最高优先级):通常由 CI/CD 流水线或服务器配置直接注入。
.env文件(默认配置):本地开发时的配置来源。
这意味着在本地开发时,我们可以依赖 .env 文件快速启动;而在部署生产环境时,直接在服务器或容器编排工具中设置同名变量即可覆盖默认配置,无需修改任何代码。
后端管理:Pydantic 的类型安全
对于 Python 后端(尤其是 FastAPI),目前的行业标准方案是使用 pydantic-settings。不再手动解析 os.environ,而是创建一个 config.py 文件,定义一个继承自 BaseSettings 的类。这个类充当了配置的“单一事实来源”。
1 | # config.py |
在项目的其他地方,无论是在数据库连接模块还是路由逻辑中,我们只需导入这个 settings 对象即可使用配置。它自动处理了环境变量的映射,还提供了类型检查和验证功能。
前端管理:构建时与运行时
前端的配置管理比后端更为复杂,因为我们需要区分两个环境:
- 构建环境(Build Time):代码被 Vite/Webpack 编译打包的过程,运行在 Node.js 环境中。
- 运行环境(Runtime):用户打开网页后的环境,运行在浏览器的沙盒中。
构建工具的角色(Vite)
在构建阶段,vite.config.ts 负责定义项目如何打包(例如端口设置、路径别名)。由于它运行在 Node.js 中,它可以直接读取 process.env 或使用 Vite 的 loadEnv 方法来获取环境变量,从而改变构建行为。
浏览器中的环境变量
然而,浏览器完全不知道 process 是什么,我们也无法在 Vue 组件中直接访问服务器的环境变量。
为了解决这个问题,Vite 利用了现代浏览器的 import.meta 特性。它会自动读取 .env 文件,并将特定的变量注入到 import.meta.env 对象中,供前端代码在浏览器中使用。为了防止后端密钥(如 AWS Secret)意外泄露到前端代码中,Vite 实施了严格的过滤:只有以 VITE_ 开头的变量(例如 VITE_API_URL)才会被暴露给前端代码。
在 Vue 组件中,我们无需引入额外的配置类,直接使用即可:
1 | // api.ts |
容器编排:Docker Compose 的胶水作用
docker-compose.yml 是连接宿主机环境变量与容器内部环境的桥梁。
在 docker-compose.yml 中,我们可以使用 ${VARIABLE:-default} 的语法。它的意思是尝试读取宿主机的环境变量 VARIABLE,如果未设置,则使用 default 作为默认值。
当然,这个变量目前只提取到了 docker-compose.yml 中,需要通过 environment 字段显式注入到服务容器中,这样后端的 Python 代码或数据库进程才能读取到它们。
1 | version: '3.8' |