Infisical 与 Docker 环境变量集成

本文说明本项目如何用 Infisical 管理密钥/覆盖配置,并与现有 Docker Compose 工作流结合。目标是:.env 负责编排与非密钥默认值,.env.local 由 Infisical 在启动时导出,注入到 WordPress 容器。Infisical 的 Project、Environment 与登录连接信息一律通过环境变量提供。

相关文件:

  • start:启动前通过 infisical/cli 登录并导出 .env.local
  • docker-compose.ymlwordpress_frankenphp 同时加载 .env.env.local
  • .env.default:可提交的本地默认环境变量模板
  • .env.infisical.example:Infisical 连接参数模板(可提交);复制为 .env.infisical 后填写真实值

自托管地址示例:https://secret-manager.it-consultis.net

Infisical 环境变量

环境变量用途
INFISICAL_DOMAIN自托管或 Cloud API 地址
INFISICAL_ORGANIZATION_ID登录时的 Organization ID
INFISICAL_PROJECT_IDInfisical Project ID,export / run 时传给 --projectId
INFISICAL_ENVInfisical Environment slug,如 localproduction-us
INFISICAL_EMAIL / INFISICAL_PASSWORD本机个人登录(勿提交)
INFISICAL_CLIENT_ID / INFISICAL_CLIENT_SECRETMachine Identity(CI / 服务器推荐)

变量分层

类型示例存放位置
Compose 编排COMPOSE_PROJECT_NAMEWORDPRESS_HTTP_PORTVERSIONCONTAINER_REGISTRYDOCKER_NETWORK_*.env(由 .env.default 生成)
环境差异配置ENVIRONMENTWORDPRESS_SITE_URL、DB host可放 .env,逐步迁移到 Infisical
密钥 / 敏感覆盖WORDPRESS_*_KEYWORDPRESS_*_SALTJWT_AUTH_SECRET_KEY、DB 密码、管理员密码等Infisical → 导出为 .env.local
Infisical 连接与认证Domain、Organization ID、Project ID、INFISICAL_ENV、登录凭据本机 .env.infisical(勿提交)

不要把 Infisical 个人邮箱/密码、Machine Identity Client Secret 写进 start 或任何会提交的文件。

文件约定

.env                    # 本地编排与默认配置(gitignore)
.env.default            # 可提交模板;首次启动由 start 复制为 .env
.env.local              # Infisical export 产物(gitignore)
.env.infisical          # Infisical 连接/认证(gitignore)
.env.infisical.example  # 可提交模板,不含真实密码

请确保 .gitignore 至少包含:

.env
.env.local
.env.infisical

启动流程

./start 中的逻辑顺序:

  1. 若无 .env,从 .env.default 复制生成。
  2. .env.infisical(或已导出的环境变量)读取 Infisical 连接信息。
  3. 使用 infisical/cli 镜像登录,拿到短期 INFISICAL_TOKEN
  4. infisical export --projectId=... --env=... 写出 .env.local
  5. source .env,创建网络并执行 ./docker-compose up

docker-compose.yml 中 WordPress 服务示例:

services:
  wordpress_frankenphp:
    env_file:
      - path: ./.env
        required: true
      - path: ./.env.local
        required: false
  • 后加载的 .env.local 会覆盖 .env 中的同名变量(仅对 service env_file 合并生效)。
  • required: false:导出失败或本地未配置 Infisical 时,仍可仅靠 .env 启动(视业务是否依赖密钥而定)。

本机认证文件示例

复制模板并填写:

cp .env.infisical.example .env.infisical

.env.infisical 内容示例:

INFISICAL_DOMAIN=https://secret-manager.it-consultis.net
INFISICAL_ORGANIZATION_ID=<organization-id>
INFISICAL_PROJECT_ID=<project-id>
INFISICAL_ENV=local

# 开发机可用个人登录(仅本机)
INFISICAL_EMAIL=<your-email>
INFISICAL_PASSWORD=<your-password>

# 或改用 Machine Identity(推荐用于 CI / 共享服务器)
# INFISICAL_CLIENT_ID=<client-id>
# INFISICAL_CLIENT_SECRET=<client-secret>

start 中建议先加载该文件,再调用 CLI,例如:

if [ -f .env.infisical ]; then
  # shellcheck disable=SC1091
  source .env.infisical
fi

: "${INFISICAL_DOMAIN:?INFISICAL_DOMAIN is required}"
: "${INFISICAL_PROJECT_ID:?INFISICAL_PROJECT_ID is required}"
: "${INFISICAL_ORGANIZATION_ID:?INFISICAL_ORGANIZATION_ID is required}"

export INFISICAL_TOKEN=$(docker run --rm infisical/cli login \
  --domain "${INFISICAL_DOMAIN}" \
  --email "${INFISICAL_EMAIL}" \
  --password "${INFISICAL_PASSWORD}" \
  --organization-id "${INFISICAL_ORGANIZATION_ID}" \
  --plain \
  --silent)

docker run --rm infisical/cli export \
  --domain "${INFISICAL_DOMAIN}" \
  --env="${INFISICAL_ENV:-local}" \
  --projectId="${INFISICAL_PROJECT_ID}" \
  --token="${INFISICAL_TOKEN}" > .env.local

多环境时通过 INFISICAL_ENV(也可映射自 ENVIRONMENT)选择 Infisical environment,例如 localdevelop-usproduction-eu

Machine Identity(CI / 服务器)

export INFISICAL_TOKEN=$(docker run --rm infisical/cli login \
  --domain "${INFISICAL_DOMAIN}" \
  --method=universal-auth \
  --client-id "${INFISICAL_CLIENT_ID}" \
  --client-secret "${INFISICAL_CLIENT_SECRET}" \
  --plain \
  --silent)

凭据放在部署平台或服务器私密配置中,不要写入 Git。

Compose 插值与覆盖顺序(重要)

Docker Compose 里有两套「环境变量」机制,容易混淆:

  1. 项目级 .env(或 --env-file:用于 compose 文件里的 ${VAR} 插值(镜像名、端口、网络名等)。
  2. service env_file:注入到容器进程环境。

同时注意:若服务还写了 environment:,其值会覆盖 env_file 中的同名键;而 ${WORDPRESS_DB_PASSWORD:-root} 这类插值只读项目级 .env不会自动读 .env.local

因此:

  • 仅放在 .env.local 的密钥,不要再在 environment: 里用 ${...} 写一遍,否则会被项目 .env 的默认值盖掉。
  • Compose 编排所需变量继续放在 .env
  • 密钥与运行时覆盖放在 Infisical → .env.local,并尽量通过 env_file 注入,而不是重复出现在 environment:

推荐的容器侧优先级:

.env(默认) → .env.local(Infisical 覆盖) → environment:(仅保留非密钥、确实需要写死的项)

Infisical 侧配置建议

  1. 在 Infisical 中为仓库创建 Project,把 Project ID 写入本机 INFISICAL_PROJECT_ID
  2. 按部署环境建立 Environment(建议与现有 ENVIRONMENT 对齐,如 localuat-usproduction-eu),对应值写入 INFISICAL_ENV
  3. 将密钥与需要按环境覆盖的变量导入对应 Environment。
  4. 本地开发:个人账号或开发用 Machine Identity,只读 local
  5. CI / 各区域服务器:独立 Machine Identity,最小权限,只读对应 Environment。

原先 deploy/scripts/modify-dot-env-*.sh 中与密钥、区域差异相关的 sed 修改,可逐步改为「按环境 infisical export」,减少在磁盘上长期维护多份手工改过的 .env

日常使用

# 1. 准备 .env(首次)
cp .env.default .env   # 或由 ./start 自动复制

# 2. 准备 Infisical 连接参数(首次)
cp .env.infisical.example .env.infisical
# 编辑 .env.infisical,填写 Project ID、Organization ID、登录凭据等

# 3. 在 Infisical 对应 environment 中维护密钥

# 4. 启动(会刷新 .env.local 并 up 容器)
./start -d

验证容器是否拿到 Infisical 变量:

./docker-compose exec wordpress_frankenphp env | grep -E 'INFISICAL_TEST|WP_REDIS_PREFIX|JWT_AUTH'

安全注意

  • 不要将 Infisical 密码、Client Secret、完整 .env.local 提交到 Git 或打进镜像。
  • 若凭据曾写入 start 或聊天记录,应立即在 Infisical / 账号侧轮换密码或撤销 Client Secret。
  • INFISICAL_TOKEN 为短期令牌,仅用于当次 export;不要持久化进镜像层。
  • 生产环境优先 Machine Identity,避免个人账号密码出现在服务器脚本中。

后续可选演进

当前方案(主机侧 export → .env.localenv_file)改动小,适合本地与现有部署脚本平滑过渡。

若后续希望减少服务器磁盘上的密钥落盘,可再演进为:

  • 镜像内安装 Infisical CLI;
  • 容器 CMD 使用 infisical run --projectId=... --env=... -- ... /start
  • Compose 仅传入 INFISICAL_TOKEN(及自托管时的 INFISICAL_DOMAIN)。

编排用薄 .env 仍需保留,因为 Compose 解析 ${...} 发生在容器启动拉密之前。

相关文档

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注