用途
本技能用于在本地搭建并运行 Symfony 项目:服务(PostgreSQL、Mailpit)跑在 Docker 中,PHP 跑在宿主机,由 Symfony CLI 把两者连接起来。它属于核心层级——项目跑不起来就无法测试;而生产近似容器是按需使用的部分,应在发布前运行,而不是每天使用。
主要能力
- 用 Docker Compose 启动 PostgreSQL 与 Mailpit。
- 用 Symfony CLI 启动开发服务器(HTTPS),并自动注入环境变量。
- 打开应用与查看已发送邮件的 Web 界面。
- 通过
symfony var:export --debug查看实际注入的变量及其来源。 - 提供生产近似容器,用于发布前验证。
- 提供常见启动故障的症状与原因对照。
使用方式
日常循环命令:
docker compose up -d # PostgreSQL + Mailpit
symfony server:start -d # dev server, HTTPS, variables injected
symfony open:local # open the app
symfony open:local:webmail # read the emails it sent
变量注入机制:不需要在任何地方写 DATABASE_URL 或 MAILER_DSN。Symfony CLI 会检查正在运行的容器,把每个暴露的容器端口与已知服务表进行匹配,并将变量导出到它启动的 PHP 进程中。可用以下命令查看:
symfony var:export --debug # exactly what is being injected, and from where
这也是 compose.override.yaml 发布端口时不指定宿主机端口的原因:
services:
database:
ports:
- "5432" # not "5432:5432"
Docker 会选择一个空闲的宿主机端口,CLI 会发现它。两个项目可以并行运行,无需为了避开冲突而修改文件。固定宿主机端口会白白丢掉这一好处。
需要知道的后果:
symfony console不等于php bin/console。前者会获得注入的变量,后者不会。按此方式配置的项目中,php bin/console doctrine:migrations:migrate会连接失败,而symfony console …可以正常工作,且错误信息不会解释原因。- 注入的变量优先于 .env.test。
symfony console doctrine:database:drop --force --env=test会删除开发数据库,因为 Docker 变量无论--env如何都会被应用。这是有文档记录的行为,且已导致真实数据丢失。针对测试数据库的操作请使用php bin/console。
完整的检测表、服务命名标签以及如何让某个服务退出检测,见 references/symfony-cli.md。
搭建一个两者都没有的项目
把 assets/compose.yaml 和 assets/compose.override.yaml 复制到项目根目录。它们与 Doctrine 和 Mailer recipe 生成的内容一致,因此仍保留 recipe 的项目无需从这里获取任何内容。
然后执行:
docker compose up -d
symfony console doctrine:database:create
symfony console doctrine:migrations:migrate --no-interaction
symfony console doctrine:fixtures:load --no-interaction # if the project has fixtures
symfony server:start -d
如果项目没有 fixtures 也没有种子数据,应如实说明,而不是编造数据行——一个能启动的空应用是正常结果,悄悄编造数据会掩盖上手流程不完整这一事实。
HTTPS
symfony server:ca:install # once per machine
之后每个项目都通过 HTTPS 与 HTTP/2 提供服务,且没有证书警告。
这不仅是舒适度问题。AssetMapper 依赖 HTTP/2 多路复用:它提供许多小文件而不是一个 bundle。用纯 HTTP 开发意味着,唯一能注意到问题的环境与生产行为不同。它还会在你写代码的当天就暴露混合内容与安全 cookie 问题,而不是在部署之后。
邮件
Mailpit 捕获所有邮件,不会有任何内容离开本机。
symfony open:local:webmail
邮件似乎消失时检查两件事:
- 它们可能只是排队,并未发送。该标准会把 SendEmailMessage 路由到 async 传输,因此在 worker 消费之前不会有内容到达 Mailpit。运行
symfony console messenger:consume async -vv,或接受邮件延迟出现。在测试中,适用的断言是assertQueuedEmailCount(),而不是assertEmailCount()。 - mailer 服务必须暴露 1025 端口,这是 CLI 匹配的依据。8025 端口只是 Web 界面。
按生产方式检查
开发服务器在生产不具备的方面很宽容:加载了 profiler、OPcache 关闭、资源通过 PHP 提供、错误可见。有些 bug 只存在于这条线的另一侧。
docker compose -f compose.yaml -f compose.prod-like.yaml up --build
open https://localhost
assets/Dockerfile.prod-like 以 APP_ENV=prod、生产 php.ini、权威 classmap 和 asset-map:compile 构建。它能回答开发服务器无法回答的问题:
- 资源是否真的能编译,并且是被提供而不是被生成;
- 应用是否能在没有仅开发用 bundle 的情况下启动;
- 是否有任何东西依赖 profiler 或 APP_DEBUG=1;
- 当错误不再显示时,页面是否仍然可用。
这是验证步骤,不是工作环境。不要把日常开发搬进去:你会失去即时重载和单步调试,并且每次修改都要付出重建代价。在发布重要内容前运行,而不是每次提交前运行。
它也不是生产用 Dockerfile。真实部署请使用 dunglas/symfony-docker,它处理 worker、健康检查、非 root 用户和 TLS。运行时应查看的细节与清单见 references/frankenphp.md。
适用场景
- 在本地启动并运行 Symfony 项目。
- 需要 PostgreSQL 与邮件捕获的日常开发。
- 发布前做生产近似验证。
- 排查本地启动、变量注入、端口与邮件相关问题。
限制
- 生产近似容器仅用于验证,不适合日常开发。
- 它不是生产 Dockerfile;真实部署需使用 dunglas/symfony-docker。
- 注入变量会覆盖 --env=test,针对测试数据库需使用 php bin/console。
- 邮件默认走 async 传输,需消费 worker 才会到达 Mailpit。
启动故障排查
| 症状 | 原因 |
|---|---|
| 数据库连接被拒绝 | 容器未运行,或使用了 php bin/console 而非 symfony console |
| could not find driver | 宿主机 PHP 缺少 pdo_pgsql——容器的扩展在这里无关 |
| 变量未注入 | 容器从不同目录启动,或 compose 项目名不同。检查 symfony var:export --debug |
| 端口已被占用 | compose.override.yaml 中固定了宿主机端口。移除它,让 Docker 选择 |
| 邮件从未到达 | 它们被排队了;消费该传输 |
| 迁移跑到了错误的数据库 | Docker 变量覆盖了 --env=test。测试数据库请使用 php bin/console |
symfony server:log 会把服务器、PHP 和应用日志显示在一个流中,通常比打开 var/log/dev.log 更快。
参考文件
| 文件 | 何时阅读 |
|---|---|
| references/symfony-cli.md | 变量注入、服务检测、命名标签、worker 进程 |
| references/frankenphp.md | 运行生产近似检查以及应关注什么 |