PHP 怎么部署到K8s

wen PHP项目 3

PHP应用容器化上K8s全攻略:从镜像构建到滚动发布

PHP 怎么部署到K8s

目录导读

  1. 为什么PHP上K8s需要打破传统思维
  2. 前置准备:Docker镜像的PHP-FPM与Nginx解耦设计
  3. 核心编排:Deployment、Service、Ingress三件套实战
  4. 有状态难题:Session共享与MySQL连接池的K8s解法
  5. 配置管理:ConfigMap与Secret在PHP项目中的落地方案
  6. CI/CD集成:GitLab CI自动构建镜像并滚动更新
  7. 常见坑位避雷:热更新、日志收集与优雅终止
  8. 问答精选:PHP开发者最常见的10个K8s疑问

为什么PHP上K8s需要打破传统思维

传统PHP部署(LNMP架构)直接装在ECS或物理机上,而K8s要求应用无状态、可水平扩展,PHP本身是解释型语言,无编译产物,但PHP-FPM进程与Nginx静态文件分离是上云的关键,你需要将PHP代码打入镜像,把/var/www/html作为只读挂载,而session和日志必须外置到Redis与标准输出。

前置准备:Docker镜像的PHP-FPM与Nginx解耦设计

必杀技:双容器同Pod

# php-deployment.yaml
spec:
  containers:
  - name: php-fpm
    image: myapp-php:7.4-fpm
    volumeMounts:
    - name: code
      mountPath: /var/www/html
  - name: nginx
    image: nginx:1.21
    volumeMounts:
    - name: code
      mountPath: /usr/share/nginx/html
  volumes:
  - name: code
    emptyDir: {}

先通过initContainer将代码从Git仓库拉取到emptyDir共享卷。关键点:Nginx容器内的fastcgi_pass必须指向0.0.1:9000,因为同Pod共享网络命名空间。

核心编排:Deployment、Service、Ingress三件套实战

  • Deployment:设置replicas: 3strategy: RollingUpdatemaxSurge: 1maxUnavailable: 0,保证PHP服务不中断。
  • Service:ClusterIP类型,targetPort: 9000(PHP-FPM),port: 80(Nginx)。
  • Ingress:使用nginx-ingress,配置TLS证书,并强制ssl-redirect: true

PHP代码更新每次docker build后打tag为新版本,修改Deployment的image版本即可触发滚动。

有状态难题:Session共享与MySQL连接池的K8s解法

Session问题:多副本下PHP默认文件Session失效,必须改用Redis存储,在PHP配置中修改:

session.save_handler = redis
session.save_path = "tcp://redis-service:6379"

MySQL连接:环境变量注入连接信息,但需注意max_connections,推荐使用ProxySQL作为DB中间件,或使用mysql-operator自动管理连接池。

配置管理:ConfigMap与Secret在PHP项目中的落地方案

.env配置抽离成ConfigMap(非敏感)与Secret(敏感),并挂载为文件:

apiVersion: v1
kind: ConfigMap
metadata:
  name: php-config
data:
  php.ini: |
    memory_limit=256M
    max_execution_time=60

在Deployment中引用:

envFrom:
- configMapRef:
    name: php-config

重点:修改ConfigMap后需重启Pod或使用rollout restart,PHP-FPM不会自动热加载。

CI/CD集成:GitLab CI自动构建镜像并滚动更新

.gitlab-ci.yml核心步骤:

  1. composer install --no-dev
  2. docker build生成含Nginx配置的镜像
  3. 推送镜像到私有Registry
  4. 使用kubectl set image deployment/myapp php-fpm=$CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
  5. 执行kubectl rollout status检测是否健康

白屏发布:结合readinessProbe检查/healthz接口,确保PHP-FPM能连接Redis与DB后再接收流量。

常见坑位避雷

  • 容器内PHP进程权限:必须运行在www-data用户,runAsNonRoot: true,否则Nginx读取不到文件。
  • 日志:PHP的error_log需指向/dev/stdout,用filelog驱动统一收集。
  • 优雅终止:PHP-FPM处理完请求后退出,K8s发送SIGTERM,需在lifecycle.preStop中延迟5秒。

问答精选:PHP开发者最常见的10个K8s疑问

Q1: PHP代码更新必须重新构建镜像吗?
A: 是,K8s不做代码同步,只认镜像,可以用emptyDir+initContainer实现git clone,但生产环境建议构建不可变镜像。

Q2: 如何水平扩展PHP进程数?
A: 调整pm.max_children,它对应每个副本的进程数,通过Deployment副本数乘max_children计算总容量。

Q3: K8s中PHP能用file_put_contents写本地文件吗?
A: 不行,多副本下数据会丢失,必须挂载PV或使用OSS/S3对象存储,临时文件使用/tmp临时卷。

Q4: 为什么Pod重启后PHP-FPM连接MySQL失败?
A: 检查MySQL的wait_timeoutmax_connections,PHP短连接方案下需要调整pconnectfalse

Q5: 如何做PHP灰度发布?
A: 使用Argo RolloutsIngress Canary,将A/B版本按权重分配流量。

Q6: K8s环境下的PHP Cron任务怎么跑?
A: 使用CronJob资源,独立副本与Job执行,避免与web服务争抢资源。

Q7: opcache配置有什么建议?
A: K8s容器内代码不可变,开启opcache.validate_timestamps=0提升性能,但注意每次发版本要清缓存。

Q8: 如何迁移老项目的.htaccess重写规则?
A: 转为Nginx的locationrewrite规则,在ConfigMap中维护nginx.conf片段。

Q9: 镜像内需要装gdpdo_mysql扩展吗?
A: 用官方php:7.4-fpm-alpine为基础,通过docker-php-ext-install写入Dockerfile,保证扩展与PHP版本锁定。

Q10: 监控PHP-FPM状态怎么弄?
A: 暴露/status接口,用Prometheus的php-fpm-exporter采集,再配Grafana大盘。


部署PHP到K8s并非玄学,核心路径是:镜像瘦身→无状态改造→配置外置→健康检查,记住每个Pod设计成“Nginx+PHP-FPM双容器”是官方推荐的模式,既保持传统LNMP思维,又完全拥抱云原生,若你的业务是高并发低延迟,请务必抛弃file_put_contents,全面拥抱Redis与对象存储。动手先写一个Deployment,比看十篇教程都有效。

抱歉,评论功能暂时关闭!