Kubernetes 中升级 PHP 版本需替换镜像并滚动更新,用 kubectl set image 最直接;须校验就绪探针、灰度策略、扩展路径及配置兼容性,避免运行时失效。

在 Kubernetes 中升级 PHP 版本,本质是替换容器镜像并触发滚动更新,不是在运行中的 Pod 里改配置或装包——后者会立刻被 K8s 驱逐,且违反不可变基础设施原则。
用 kubectl set image 触发滚动更新
这是最直接、最可控的升级方式,适用于单容器 Deployment,且无需修改 YAML 文件。
- 执行命令:
kubectl set image deploy/<name> php-container=php:8.2-apache</name>,其中php-container是容器名(spec.containers[0].name),必须与 Deployment 中定义的一致 - 若容器名是
app或web,别硬写成php-container,否则报错container "php-container" not found - 该命令会立即触发滚动更新:新 Pod 启动 → 就绪探针通过 → 流量切过去 → 旧 Pod 终止
- 不建议在生产环境直接用
kubectl edit deploy修改 image 字段,容易手误保存失败或漏掉引号导致 YAML 解析错误
就绪探针(readinessProbe)必须真实反映 PHP 状态
很多升级失败,不是镜像问题,而是探针“假成功”:Pod 已 Running,但 php-fpm 没起来、扩展没加载、php.ini 路径错了,流量却已导过去。
- 推荐用 HTTP 探针访问一个轻量 PHP 健康端点,例如
/health.php,内容为:<?php echo json_encode(['status' => 'ok', 'version' => PHP_VERSION]); - 避免只用
tcpSocket或exec执行curl localhost:9000——它不校验 PHP 是否真能执行代码 - 设置合理超时和重试:
initialDelaySeconds: 15(等 PHP 启动完),periodSeconds: 10,failureThreshold: 3 - 如果用了自定义
entrypoint.sh启动 PHP,确保它启动失败时进程退出(否则探针永远收不到 5xx)
灰度发布靠 maxSurge 和 maxUnavailable 控制节奏
默认滚动更新策略对小集群够用,但面对高并发 PHP 应用,需主动限流,防止新旧版本混跑引发 session 冲突或扩展兼容问题。
立即学习“PHP免费学习笔记(深入)”;
- 在 Deployment 的
spec.strategy.rollingUpdate下显式配置:maxSurge: 1(最多多起 1 个新 Pod),maxUnavailable: 0(不允许任何旧 Pod 先下线) - 这样更新过程变成“先上后下”,始终有完整副本数在线,适合依赖共享存储或外部缓存的 PHP 应用
- 若用 Istio 或 Nginx Ingress 做更细粒度灰度(比如按 header 或 cookie 分流),注意 PHP 应用本身也要支持多版本共存——例如不同版本读写不同的 Redis key 前缀,否则数据污染无法回滚
- 千万别把灰度逻辑写进 PHP 代码里(如
if ($_SERVER['HTTP_X_VERSION'] === '8.2') {...}),这会让部署和排障耦合,违背声明式运维初衷
扩展与配置路径变更最容易被忽略
PHP 8.2 官方镜像的 extension_dir 是 /usr/lib/php/20220829,而 7.4 是 /usr/lib/php/20200930。硬编码路径的 php.ini 会导致 php -m 报 Unable to load dynamic library,但 Pod 仍可能通过探针(因为 HTTP 服务本身没挂)。
- 检查当前配置:
kubectl exec <pod-name> -- php -i | grep extension_dir</pod-name> - 若 ConfigMap 挂载了
php.ini,必须同步更新其中的extension_dir和所有extension=xxx.so路径 - 更稳妥的做法是在 Dockerfile 中用
RUN docker-php-ext-install mysqli pdo_mysql opcache,而不是靠ini文件动态加载——构建时失败比运行时失败更容易发现 - Redis、Xdebug 等第三方扩展,务必确认是否提供对应 PHP 主版本的预编译包;例如
phpredis5.3.x 不支持 PHP 8.2,得升到 6.0+
真正卡住升级的,往往不是命令会不会敲,而是 PHP 扩展链、OPcache 配置、时区设置这些细节在新版本里静默失效。上线前一定要用 kubectl run 起一个临时 Pod,手动执行 php -v、php -m、php -i | grep -E "(extension_dir|opcache|date.timezone)" 过一遍。



















