明文使用MYSQL_ROOT_PASSWORD极不安全,因其会暴露在ps输出、Shell历史、docker inspect结果及日志中;应改用Docker Secrets挂载为/run/secrets/下的只读文件,避免进入环境变量空间。

直接用环境变量传数据库密码,等于把钥匙挂在门把手上——能连上,但不安全。
为什么MYSQL_ROOT_PASSWORD明文写在docker run命令里很危险
这类参数会完整出现在宿主机的ps输出、Shell历史记录、容器元数据(docker inspect)中,任何有权限执行这些命令的人都能直接看到密码。更糟的是,如果容器崩溃并生成日志,错误堆栈可能意外打印出整个连接字符串。
-
docker run -e MYSQL_ROOT_PASSWORD=123456 ...→ 密码立刻暴露在进程列表里 - 镜像构建阶段用
ENV硬编码 → 密码固化进镜像层,docker history可追溯 - 没设
.gitignore的.env文件 → 提交到代码仓库,全员可见
用docker-compose.yml的secrets机制替代environment
Docker原生secrets将敏感数据挂载为只读文件(默认路径/run/secrets/xxx),不进入环境变量空间,避免被ps或inspect捕获。PHP/Node.js等应用需改用文件读取方式获取凭据。
- 先创建密钥文件:
echo "my_strong_password" > ./secrets/db_root_pass.txt - 在
docker-compose.yml中声明:secrets: db_root_pass: file: ./secrets/db_root_pass.txt - 服务中挂载并使用:
secrets: -db_root_pass,然后在容器内读/run/secrets/db_root_pass - MySQL容器本身不原生支持从文件读密码,需配合启动脚本或使用
mysql-client时通过--defaults-file指定配置文件
env_file只能用于低/中敏感配置,且必须.gitignore
env_file比命令行传参稍好,但它仍是明文加载进环境变量。它适合DB_HOST、DB_NAME这类非凭据信息,或生产环境中的DB_PASSWORD(前提是文件权限严格、不入版本库)。
-
env_file内容仍可通过printenv或应用日志泄露,不能用于SECRET_KEY或私钥 - 必须确保
.env.prod在.gitignore中,且宿主机上chmod 600 ./env.prod - PHP中用
getenv('DB_PASSWORD')没问题,但别在error_log()里直接打印该变量值
SQL Server容器的ACCEPT_EULA和MSSQL_SA_PASSWORD要特别处理
SQL Server Linux镜像强制要求ACCEPT_EULA=Y,但MSSQL_SA_PASSWORD绝不能和它混在同一-e参数块里。微软官方文档明确警告:SA密码长度至少8位且含大小写字母、数字、符号——而很多人图省事设成sa123,导致容器启动失败且报错模糊。
- 错误示范:
docker run -e ACCEPT_EULA=Y -e MSSQL_SA_PASSWORD=sa123 ...→ 容器静默退出 - 正确做法:用
env_file隔离密码,或用secrets(需自定义entrypoint脚本读取并注入SA_PASSWORD) -
ACCEPT_EULA本身无敏感性,可放心写在docker-compose.yml的environment区
真正难的不是“怎么传”,而是“谁有权读”。哪怕用了secrets,如果容器内进程以root身份运行并开放了任意端口,攻击者拿下容器后仍能读取/run/secrets/下的文件。最小权限原则——降权运行、限制能力、网络隔离——一样都不能少。


















