惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

V
V2EX - 技术
D
DataBreaches.Net
阮一峰的网络日志
阮一峰的网络日志
Recent Announcements
Recent Announcements
V
V2EX
Hugging Face - Blog
Hugging Face - Blog
T
The Exploit Database - CXSecurity.com
Simon Willison's Weblog
Simon Willison's Weblog
Cisco Talos Blog
Cisco Talos Blog
Microsoft Security Blog
Microsoft Security Blog
C
Cyber Attacks, Cyber Crime and Cyber Security
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
K
Kaspersky official blog
F
Fortinet All Blogs
GbyAI
GbyAI
Forbes - Security
Forbes - Security
The Cloudflare Blog
博客园 - 司徒正美
博客园_首页
量子位
Schneier on Security
Schneier on Security
G
GRAHAM CLULEY
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
P
Proofpoint News Feed
N
News | PayPal Newsroom
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
博客园 - 聂微东
T
Tor Project blog
V
Vulnerabilities – Threatpost
Y
Y Combinator Blog
Jina AI
Jina AI
Help Net Security
Help Net Security
T
Threat Research - Cisco Blogs
Recent Commits to openclaw:main
Recent Commits to openclaw:main
C
Cybersecurity and Infrastructure Security Agency CISA
Project Zero
Project Zero
N
News and Events Feed by Topic
I
Intezer
B
Blog
美团技术团队
C
CERT Recently Published Vulnerability Notes
NISL@THU
NISL@THU
L
LINUX DO - 最新话题
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
Blog — PlanetScale
Blog — PlanetScale
AWS News Blog
AWS News Blog
T
Tailwind CSS Blog
The Last Watchdog
The Last Watchdog
雷峰网
雷峰网
有赞技术团队
有赞技术团队

windsong

从画图纸到捏泥巴:从后端到 JavaScript 清华校园网认证笔记 摆脱“被动焦虑”的终极解药:一个尼采主义者的自我救赎与“强力意志”觉醒 windsong Vue 组件通信 词法作用域与动态作用域 全栈架构:三套 Schema Pinia Store :前端的 MVVM 解耦 前后端交互的桥梁:Axios 早抛晚捕:异常处理 股票市场常识 大噜村的债务:过去和未来 大噜村的发展故事 重读设计模式:从理论到实践的反思(二) Transformer 个人入门 Go Viper:设计哲学与最佳实践 简单的 Go WebSocket 服务器 最简单的 Go HTTP 服务器 Go 语言核心机制:命名类型与接口
全栈容器化应用的环境变量管理
xxxx · 2026-01-10 · via windsong

全栈容器化应用的环境变量管理

理解一个复杂程序的运行逻辑,一个方式是找到它的 Main 函数,观察各个对象的生命周期。这能让我们把握程序的运行途径,而不是迷失在散落各处的类文件中。理解一个系统的配置管理,我们也可以采用类似的视角。当我们构建一个前后端分离项目,并希望通过 Docker 进行容器化部署时,如何管理配置?以 FastAPI + Vue/TypeScript + PostgreSQL 为例,整理一下环境变量管理方案。

核心原则:配置与代码分离

无论是在前端、后端还是数据库层,都要遵循一个核心原则:代码中定义配置的结构,而由环境变量注入具体的值。配置管理的物理载体通常是项目根目录下的 .env 文件。

大多数现代工具库和 Docker 都遵循一套标准的优先级逻辑:

  1. 系统级环境变量(最高优先级):通常由 CI/CD 流水线或服务器配置直接注入。
  2. .env 文件(默认配置):本地开发时的配置来源。

这意味着在本地开发时,我们可以依赖 .env 文件快速启动;而在部署生产环境时,直接在服务器或容器编排工具中设置同名变量即可覆盖默认配置,无需修改任何代码。

后端管理:Pydantic 的类型安全

对于 Python 后端(尤其是 FastAPI),目前的行业标准方案是使用 pydantic-settings。不再手动解析 os.environ,而是创建一个 config.py 文件,定义一个继承自 BaseSettings 的类。这个类充当了配置的“单一事实来源”。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

from pydantic_settings import BaseSettings, SettingsConfigDict

class Settings(BaseSettings):

POSTGRES_USER: str = "postgres"
POSTGRES_PASSWORD: str
POSTGRES_DB: str = "app_db"
POSTGRES_HOST: str = "localhost"


model_config = SettingsConfigDict(env_file=".env", env_file_encoding="utf-8")


settings = Settings()

在项目的其他地方,无论是在数据库连接模块还是路由逻辑中,我们只需导入这个 settings 对象即可使用配置。它自动处理了环境变量的映射,还提供了类型检查和验证功能。

前端管理:构建时与运行时

前端的配置管理比后端更为复杂,因为我们需要区分两个环境:

  1. 构建环境(Build Time):代码被 Vite/Webpack 编译打包的过程,运行在 Node.js 环境中。
  2. 运行环境(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
2

const apiUrl = import.meta.env.VITE_API_URL;

容器编排:Docker Compose 的胶水作用

docker-compose.yml 是连接宿主机环境变量与容器内部环境的桥梁。

docker-compose.yml 中,我们可以使用 ${VARIABLE:-default} 的语法。它的意思是尝试读取宿主机的环境变量 VARIABLE,如果未设置,则使用 default 作为默认值。

当然,这个变量目前只提取到了 docker-compose.yml 中,需要通过 environment 字段显式注入到服务容器中,这样后端的 Python 代码或数据库进程才能读取到它们。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
version: '3.8'

services:
backend:
build: ./backend
environment:

- DATABASE_URL=postgresql://${POSTGRES_USER:-dalu}:${POSTGRES_PASSWORD:-dalu_password}@db:5432/${POSTGRES_DB:-dalu_farm}

- POSTGRES_USER=${POSTGRES_USER:-dalu}
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD:-dalu_password}
- POSTGRES_HOST=db

db:
image: postgres:15
environment:
- POSTGRES_USER=${POSTGRES_USER:-dalu}
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD:-dalu_password}
- POSTGRES_DB=${POSTGRES_DB:-dalu_farm}
volumes:
- postgres_data:/var/lib/postgresql/data

volumes:
postgres_data: