必须用Nginx+PHP-FPM替代php -S:入口命令需前台运行(如nginx -g "daemon off;"),Web根目录设为public/,注入APP_ENV与APP_DEBUG环境变量,禁用.env依赖。

如何在K8s中正确启动Symfony应用容器
直接用 php -S 启动 Symfony 会立刻失败——K8s 的 Pod 生命周期不兼容 PHP 内置服务器的阻塞模型,且无进程管理、无健康探针支持。
必须改用生产级 Web 服务器(如 Nginx + PHP-FPM)并确保主进程可被 K8s 正确识别。关键点:
- 入口命令必须是前台运行的长期进程,例如
nginx -g "daemon off;",不能是php bin/console server:start或后台化脚本 - PHP-FPM 需配置
pm = dynamic并显式设置pm.max_children,避免默认值在资源受限容器中触发 OOM - Web 根目录必须指向
public/,Nginx 配置里root /var/www/public;缺一不可,否则 404 不报错但全路径失效 - 环境变量
APP_ENV和APP_DEBUG必须在容器启动时注入,不能依赖 .env 文件(K8s 中该文件通常不挂载)
为什么 Deployment 的 replicas 设置为 3 却没真正横向扩展
常见错觉:只要改了 replicas: 3,流量就会自动分摊。实际中,90% 的问题出在服务暴露层或应用自身状态管理上。
典型断点:
- Service 类型不是
ClusterIP或LoadBalancer,而是NodePort且未配置外部负载均衡,导致只有一台 Node 被访问 - Symfony 的 session 默认写入本地文件(
src/Kernel.php中未覆盖getCacheDir()),多个 Pod 共享同一份 session 导致登录态丢失或 500 错误 - 未启用 OPcache 配置共享(
opcache.file_cache指向空目录或未设opcache.validate_timestamps=0),每个 Pod 独立编译字节码,CPU 使用率虚高反制约扩缩容效果 - Liveness/Readiness 探针路径错误,例如探测
/healthz但控制器未定义该路由,K8s 反复重启 Pod,看似“扩了”实则“没活下来”
如何让 Symfony 日志实时进入集中式日志系统
K8s 容器标准输出(stdout/stderr)是日志采集唯一可信入口。Symfony 默认写入 var/log/prod.log 文件,这在 Pod 重启后即丢失,且无法被 Fluentd 或 Loki 自动捕获。
必须强制重定向:
- 在
config/packages/prod/monolog.yaml中将 handler 改为console,禁用stream:handlers: main: type: console process_psr_3_messages: false - 确保容器启动时未设置
SF_LOG_LEVEL或其他覆盖行为,否则 Monolog 会降级回 file handler - PHP-FPM 配置中关闭
catch_workers_output = no,否则子进程错误(如 Fatal Error)不会透出到 stdout - 若使用自定义
ErrorHandler::register(),必须调用$handler->setExceptionHandler()并确保异常最终 throw 到顶层,否则静默吞掉错误
扩展时遇到 “Too many open files” 或 “Connection refused to database” 怎么办
这不是数据库连接池不够,而是 Symfony 应用在容器中未适配 K8s 的 DNS 解析与连接生命周期。
根因和解法:
- 数据库 DSN 使用 service 名称(如
mysql://user:pass@mysql:3306/db)没问题,但 PHP 的 PDO 默认不启用持久连接;需显式加;pdo_mysql.default_socket=/var/run/mysqld/mysqld.sock或确认mysql.default_socket配置为空(走 TCP) - 连接数爆炸常源于 Doctrine 的
auto_commit: true+ 长事务未 close,应在config/packages/doctrine.yaml中设connection: { options: { 1002: "SET NAMES utf8mb4" } }并配合doctrine.dbal.connections.default.url的?connect_timeout=5&read_timeout=30参数 - “Too many open files” 多因容器未提升 ulimit:在 Deployment 的
securityContext下加runAsUser: 33和fsGroup: 33,并在容器内执行ulimit -n 65536(通过 initContainer 或 entrypoint.sh) - 不要在
Kernel::boot()中做任何远程调用(如调用配置中心),K8s 扩容时并发 boot 会压垮下游
最易被忽略的是环境变量加载顺序:K8s 的 envFrom: configMapRef 和 secretRef 注入的变量,会覆盖 Dockerfile 中 ENV 声明的同名变量,但 Symfony 的 %env(APP_SECRET)% 解析发生在容器启动之后,若 ConfigMap 中漏写 APP_SECRET,应用直接启动失败而非报错提示——这种静默失败必须靠 Init Container 预检环境变量是否存在来拦截。











