文章目录

Elixir 配置:config.exs 与环境变量

发布于 2026-04-13 03:26:48 · 浏览 39 次 · 评论 0 条

Elixir 配置:config.exs 与环境变量

Elixir 应用的配置管理是构建健壮软件的基础,区分静态配置与敏感数据(如数据库密码、API 密钥)至关重要。正确处理环境变量不仅能保证安全性,还能让同一套代码在不同环境(开发、测试、生产)中灵活运行。


理解配置加载的生命周期

Elixir 应用在启动时会加载配置,理解其加载顺序是正确使用环境变量的前提。配置主要分为两个阶段:编译时和运行时。

graph LR subgraph BuildTime ["构建阶段"] A["编译代码"] --> B["读取 config/config.exs"] B --> C["读取 config/dev.exs 等环境文件"] end subgraph RunTime ["运行阶段"] D["系统启动"] --> E["读取 config/runtime.exs"] E --> F["解析系统环境变量"] end BuildTime -->|构建完成| RunTime

大多数初学者容易犯的错误是将所有配置都写在 config.exsdev.exs 中。这导致配置在编译时就被“固化”到了 BEAM 虚拟机字节码中,无法在运行时动态读取服务器上的环境变量。

核心原则:静态配置(如日志级别、服务端口)放在 config.exs;动态或敏感配置(如数据库密码、外部 API 地址)必须放在 config/runtime.exs 中。


第一步:准备本地环境变量

在代码读取环境变量之前,你需要先在系统中定义它们。在本地开发时,通常不希望在 shell 中手动 export 每一个变量。

  1. 创建 一个名为 .env 的文件,放在项目根目录下(与 mix.exs 同级)。
  2. 编辑 .env 文件,添加 你的配置项,每行一个,格式为 KEY=VALUE

例如:

DATABASE_URL=postgres://user:pass@localhost/my_app_dev
SECRET_KEY_BASE=super_secret_random_string
API_ENDPOINT=https://api.example.com
  1. 打开 .gitignore 文件,确保 .env 被添加到忽略列表中,防止敏感信息被提交到代码仓库。
# .gitignore
...
.env
  1. 安装 dotenvy 库。虽然 Elixir 标准库不自带 .env 解析,但这是社区标准做法。打开 mix.exs,在 defp deps do添加 依赖:
defp deps do
  [
    {:dotenvy, "~> 0.8.0"}
  ]
end
  1. 运行 mix deps.get 安装 依赖。

第二步:配置 runtime.exs 读取环境变量

Elixir 1.9 引入了 config/runtime.exs,专门用于在系统启动时评估配置。这是读取环境变量的最佳位置。

  1. 找到 项目根目录下的 config 文件夹。
  2. 打开 config/runtime.exs 文件。
  3. 修改 文件顶部,加载 .env 文件(仅在开发环境):
import Config

# 仅在 :dev 环境加载 .env 文件
if config_env() == :dev do
  Dotenvy.source!([".env", System.get_env()])
end
  1. 配置 具体的应用模块,例如数据库。使用 System.get_env/1Dotenvy 提供的强类型解析函数。推荐使用 Dotenvy,因为它能处理类型转换和默认值。

例如,配置 Ecto 数据库 Repo:

# config/runtime.exs

# 定义一个解析环境变量的辅助函数(可选,或直接使用 Dotenvy)
env = fn
  key, default -> System.get_env(key) || default
  key -> System.get_env(key) || raise "Environment variable #{key} is missing!"
end

# 配置数据库
if config_env() != :test do
  database_url =
    env.("DATABASE_URL") ||
      raise """
      environment variable DATABASE_URL is missing.
      For example: postgres://USER:PASS@HOST/DATABASE
      """

  config :my_app, MyApp.Repo,
    url: database_url,
    pool_size: String.to_integer(env.("POOL_SIZE", "10"))
end

注意Dotenvy 提供了更优雅的写法,例如 env!("DATABASE_URL", :string!),可以强制要求变量必须存在并转换类型。


第三步:在代码中使用配置

配置好 runtime.exs 后,在业务代码中获取这些值非常简单。

  1. 打开 任何需要使用配置的模块文件。
  2. 使用 Application.fetch_env!/2 读取 值。
defmodule MyApp.Accounts do
  alias MyApp.Repo

  def get_api_endpoint do
    # 读取 :my_app 应用下的 :api_endpoint 配置
    Application.fetch_env!(:my_app, :api_endpoint)
  end
end
  1. 确保config/runtime.exs设置了对应的值:
# config/runtime.exs
config :my_app, :api_endpoint, System.get_env("API_ENDPOINT")

第四步:生产环境部署设置

在生产环境(如 Docker 容器或云服务器),我们通常不使用 .env 文件,而是直接注入操作系统级别的环境变量。

  1. 设置 操作系统环境变量。

    • Docker 环境:在 docker-compose.yml 或运行命令中通过 -e 参数传入,或者在容器编排工具(如 Kubernetes)的 ConfigMap/Secret 中定义。
    • Linux 服务器:编辑 /etc/environment 或在用户的 .bashrcexport 变量。
  2. 验证 config/runtime.exs 中的逻辑。由于代码中判断了 if config_env() == :dev 才加载 .env,生产环境(MIX_ENV=prod)会自动跳过文件读取,直接读取 System.get_env,符合预期。


常见问题排查

如果遇到配置未生效的情况,按照以下顺序排查。

症状 可能原因 解决方案
启动报错 "Environment variable ... is missing" 变量未设置或拼写错误 检查 系统环境变量是否存在,核对 变量名的大小写。
修改了配置但应用行为不变 修改了 config.exs 而非 runtime.exs,或者已编译的代码未包含最新配置 确认 动态配置写在 runtime.exs 中;如果必须改 config.exs,需要重新编译 (mix clean && mix compile)。
生产环境读取到了本地测试值 .env 文件被意外提交并在生产环境被读取 检查 config/runtime.exs 中的加载逻辑,确保 生产环境不加载 .env 文件。

调试配置的最佳实践:在 iex -S mix 会话中,使用 Application.get_all_env(:my_app) 查看 当前应用所有已加载的配置,验证环境变量是否正确注入。

iex -S mix
iex> Application.get_all_env(:my_app)
[
  api_endpoint: "https://api.example.com",
  ecto_repos: [MyApp.Repo],
  ...
]

评论 (0)

暂无评论,快来抢沙发吧!

扫一扫,手机查看

扫描上方二维码,在手机上查看本文