Docker Compose 修改环境变量后,restart 仍使用旧值
Docker Compose 修改 environment 或 env_file 后,restart 不会更新已有容器的环境。区分最终配置、容器环境与应用行为,再重建指定服务,并核对数据保留和回退条件。
把 compose.yaml 中的环境变量改了,或者更新了服务引用的 app.env,执行 docker compose restart app 后,应用仍连接旧地址、使用旧日志级别。即使容器显示刚刚启动,变量也可能还是创建容器时的值。
对于通过 Compose 的 environment 或 env_file 注入的变量,restart 不会应用新配置。要让已有服务采用变化后的环境,需要让 Compose 重新创建对应容器。确认最终配置正确后,再执行目标服务的 up -d。
下面使用当前 Docker Compose 插件的 docker compose 命令,针对普通 Compose 项目。Swarm 服务更新、镜像构建时的变量,以及应用自行读取挂载文件的热更新不在此范围内。示例服务名 app、文件名 compose.yaml 和变量 APP_LOG_LEVEL 都应按实际项目替换。
区分配置文件、容器环境和应用行为
这三个位置可能显示不同结果:文件里已经改成新值,Compose 解析时又被覆盖;Compose 的最终模型正确,现有容器却还保存旧环境;容器环境已更新,应用仍被启动参数或其他配置覆盖。
先保留变更前可用的配置和环境文件,再用实际部署参数检查模型:
docker compose -f compose.yaml config -q
docker compose -f compose.yaml config
第一条只校验配置。第二条展开服务定义,重点看 services.app.environment 中的目标变量。完整输出可能包含凭据,只在受控终端查看,不要贴入公开日志。config --environment 展示的是用于插值的环境,也不能代替目标服务的最终环境配置。
所有命令都要沿用启动时的项目名、多个 -f 及顺序、环境文件和项目目录参数。否则检查与更新可能落在不同项目,或漏掉一个覆盖文件。
如果最终模型中仍是旧值,继续检查变量来源和覆盖关系,此时强制重建只会把旧值再注入一次。特别是 .env 不会自动把所有条目送进容器,必须由服务配置明确引用;同名 environment 也可能覆盖 env_file。
如果最终模型已是新值,再找现有容器:
docker compose -f compose.yaml ps -a -q app
记下输出的容器 ID。多副本服务可能返回多个 ID,应逐个检查;没有输出则先确认项目、服务名与 Docker 连接目标,不能直接认定变量已经更新。
在包含 printenv 工具的运行中容器内,可只查看一个非敏感变量:
docker compose -f compose.yaml exec -T app printenv APP_LOG_LEVEL
这个命令启动一个新的检查进程,看到的是它继承的容器环境,并不直接读取正在运行的应用进程内部状态。没有 printenv 的精简镜像可以用下面的容器配置检查,不必为排错临时安装工具。
docker inspect --type container --format '{{json .Config}}' CONTAINER_ID
将 CONTAINER_ID 换成前面实际记录的单个 ID,在返回的 Env 列表中查看目标变量。这份配置可能包含全部环境变量和其他敏感信息,同样只在受控终端查看。检查命令不要额外加 exec -e,否则会临时覆盖检查进程的环境,掩盖容器原本的值。
让 Compose 重新创建目标服务
例如,现有服务的环境片段原来是:
environment:
APP_LOG_LEVEL: "info"
应用支持 debug 这个值时,将其改成:
environment:
APP_LOG_LEVEL: "debug"
这里只展示服务内的配置片段,保留现有镜像、网络、挂载等定义。变量名和取值必须是应用实际支持的;重建容器不会让应用认识一个不存在的配置项。
重建前确认持久数据已经放在适当的数据卷或绑定挂载中,并完成必要备份。普通容器可写层里的文件不会随着新容器保留,临时手工安装的软件和修改也不能当作部署配置。固定本次使用的镜像版本,检查是否还夹带其他未发布的配置变更。
如果依赖服务已经运行且本次无需更新它们,可以在允许服务中断的时间执行:
docker compose -f compose.yaml up -d --no-deps app
Compose 检测到服务配置或镜像变化后,会停止并重新创建相应容器,同时保留挂载卷。-d 只表示后台运行;--no-deps 避免顺带启动依赖服务,因此依赖尚未就绪时不能靠这条命令补齐整个项目。
单实例容器的停止、重建和启动会产生中断。它不保证零停机,无需先对整个项目执行 down。不要加 --no-recreate,它会阻止已有容器重建。
若最终模型确实正确,但需要明确要求重新创建目标容器,可以使用:
docker compose -f compose.yaml up -d --no-deps --force-recreate app
--force-recreate 即使配置或镜像没有变化也会重建。它不负责修正变量来源,应在前面的检查完成后使用。单纯修改运行时环境通常不需要重建镜像;如果实际改的是 Dockerfile 或构建产物,则应按该项目的构建和发布流程处理。
用新容器和实际请求验证结果
更新后重新获取容器 ID,并检查运行状态和启动日志:
docker compose -f compose.yaml ps -a app
docker compose -f compose.yaml ps -a -q app
docker compose -f compose.yaml logs --tail 100 app
对于本次发生重建的容器,新 ID 应不同于旧 ID。再用前面的单变量检查或 inspect 核对新容器环境。只有启动时间变化、ID 没变,不能证明执行了重新创建。
随后发起应用的正常请求,检查目标设置对应的行为。环境已经是新值,应用仍表现异常时,排查应用是否读取这个变量、是否被命令行参数或配置文件覆盖,以及请求是否仍落在旧副本。此时继续重建同一个正确配置的容器,通常不能提供更多判断依据。
数据库镜像还要区分初始化变量与运行时设置。若变量只在空数据目录初始化时使用,重建并保留已有数据卷,不代表数据库中的账号、密码或库名会随之改写。应按数据库支持的方式处理已有状态,不能为了让变量“生效”删除数据卷。
恢复旧设置也需要应用配置
如果新设置导致启动失败或业务异常,恢复之前保存的可用配置、环境文件和镜像引用,用相同项目参数重新执行目标服务的 up -d --no-deps app,再确认容器环境和业务行为。
回退配置不能撤销应用已经写入的数据。若新设置触发了数据变更,需要另按业务备份与恢复方案处理。排查环境更新不需要 down -v、删除卷或更换项目名;这些动作可能改变数据挂载关系,让原本的配置问题变成数据恢复问题。


