如何将PHP项目部署到K8s集群?

wen PHP项目 3

本文目录导读:

如何将PHP项目部署到K8s集群?

  1. 第一步:准备 PHP 项目与 Docker 镜像
  2. 第二步:创建 Kubernetes 资源 YAML 文件
  3. 第三步:部署到 K8s 集群
  4. 关键注意事项
  5. 常见问题排查
  6. 推荐工具

将 PHP 项目部署到 Kubernetes (K8s) 集群,通常遵循以下标准化步骤,核心思路是将 PHP 应用及其依赖(如 Nginx、PHP-FPM)打包成符合 K8s 要求的容器镜像,并通过声明式 YAML 文件进行管理。

以下是分步指南,包含关键配置和最佳实践:

第一步:准备 PHP 项目与 Docker 镜像

K8s 运行的是容器,因此第一步是将 PHP 应用容器化。

编写 Dockerfile 通常有两种模式:

  • 模式A:单体镜像(含 Nginx + PHP-FPM):适合简单应用,但灵活性较低。
  • 模式B:分离镜像(推荐):Nginx 和 PHP-FPM 跑在各自独立的容器(Pod内共享网络),更符合微服务架构。

示例:PHP-FPM 镜像 Dockerfile.php

FROM php:8.2-fpm-alpine
# 安装依赖和扩展
RUN apk add --no-cache $PHPIZE_DEPS \
    && docker-php-ext-install pdo_mysql mysqli opcache \
    && docker-php-ext-enable opcache
# 复制项目代码
COPY . /var/www/html
# 设置工作目录
WORKDIR /var/www/html
# 非 root 用户运行(安全)
RUN addgroup -g 1001 appuser && adduser -u 1001 -G appuser -s /bin/sh -D appuser
USER appuser
EXPOSE 9000
CMD ["php-fpm"]

示例:Nginx 镜像 Dockerfile.nginx

FROM nginx:alpine
# 复制 Nginx 配置文件
COPY nginx.conf /etc/nginx/nginx.conf
COPY default.conf /etc/nginx/conf.d/default.conf
# 复制静态文件(或整个项目,用于静态资源)
COPY public/ /var/www/html/public/
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

额外配置示例

  • Opcache 配置:在 Dockerfile 中设置 opcache.enable=1opcache.revalidate_freq=2
  • Composer 依赖:运行 composer install --optimize-autoloader --no-dev(建议在 CI 中预构建,避免在容器内安装依赖)。

构建并推送镜像:

docker build -t registry.example.com/my-app-php:latest -f Dockerfile.php .
docker build -t registry.example.com/my-app-nginx:latest -f Dockerfile.nginx .
docker push registry.example.com/my-app-php:latest
docker push registry.example.com/my-app-nginx:latest

第二步:创建 Kubernetes 资源 YAML 文件

通常需要管理以下资源:Deployment(控制 PHP-FPM)、Deployment(控制 Nginx)、Service、ConfigMap、Secret、Ingress。

定义 ConfigMap

# php-configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: php-app-config
data:
  # PHP 环境变量
  APP_ENV: production
  DB_HOST: mysql-service.default.svc.cluster.local
  CACHE_DRIVER: redis
  # Nginx 配置(如果内嵌在 ConfigMap 中)
  nginx.conf: |
    server {
        listen 80;
        index index.php index.html;
        root /var/www/html/public;
        ...
    }

定义 PHP-FPM Deployment + Service

# php-fpm-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: php-fpm
spec:
  replicas: 3
  selector:
    matchLabels:
      app: php-app
      tier: backend
  template:
    metadata:
      labels:
        app: php-app
        tier: backend
    spec:
      containers:
      - name: php-fpm
        image: registry.example.com/my-app-php:latest
        ports:
        - containerPort: 9000
        envFrom:
        - configMapRef:
            name: php-app-config
        - secretRef:
            name: php-app-secret   # 包含数据库密码等敏感信息
        resources:
          requests:
            memory: "256Mi"
            cpu: "250m"
          limits:
            memory: "512Mi"
            cpu: "500m"
---
apiVersion: v1
kind: Service
metadata:
  name: php-fpm-service
spec:
  selector:
    app: php-app
    tier: backend
  ports:
  - port: 9000
    targetPort: 9000

定义 Nginx Deployment + Service

# nginx-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
spec:
  replicas: 2
  selector:
    matchLabels:
      app: php-app
      tier: frontend
  template:
    metadata:
      labels:
        app: php-app
        tier: frontend
    spec:
      containers:
      - name: nginx
        image: registry.example.com/my-app-nginx:latest
        ports:
        - containerPort: 80
        volumeMounts:
        - mountPath: /etc/nginx/conf.d   # 挂载配置
          name: nginx-config
      volumes:
      - name: nginx-config
        configMap:
          name: php-app-config
          items:
          - key: nginx.conf
            path: default.conf
---
apiVersion: v1
kind: Service
metadata:
  name: nginx-service
spec:
  type: ClusterIP  # 或 LoadBalancer
  selector:
    app: php-app
    tier: frontend
  ports:
  - port: 80
    targetPort: 80

定义 Ingress(对外暴露流量)

# ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: php-app-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  ingressClassName: nginx
  rules:
  - host: www.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: nginx-service
            port:
              number: 80

第三步:部署到 K8s 集群

  1. 创建命名空间(可选)

    kubectl create namespace my-php-app
  2. 应用所有资源

    kubectl apply -f php-configmap.yaml -n my-php-app
    kubectl apply -f php-fpm-deployment.yaml -n my-php-app
    kubectl apply -f nginx-deployment.yaml -n my-php-app
    kubectl apply -f ingress.yaml -n my-php-app
    # 如果使用 Secret,也需要创建(例如数据库密码)
    kubectl create secret generic php-app-secret \
      --from-literal=DB_PASSWORD='xxxx' -n my-php-app
  3. 验证部署

    kubectl get pods -n my-php-app
    kubectl get svc -n my-php-app
    kubectl describe ingress php-app-ingress -n my-php-app

关键注意事项

  1. Session 存储

    • 在 K8s 中,默认文件存储 Session 不可靠(Pod 重启后丢失),建议使用外部存储(Redis、Memcached 或数据库)。
    • php.ini 或代码中配置 session.save_handler = redis 指向 Redis Service。
  2. 文件持久化

    • 上传文件:必须存储在持久卷(PV/PVC)、对象存储(S3/MinIO)或共享存储(NFS)上。
    • 日志:建议将日志输出到 stdout/stderr(K8s 会自动收集),或挂载到持久卷。
  3. 共享文件系统

    • PHP 和 Nginx 在同一 Pod(容器共享卷),确保代码或上传目录通过 emptyDir 或 PV 共享。
  4. 健康检查

    • 添加 Liveness 和 Readiness 探针,避免流量发送到异常 Pod:
      livenessProbe:
        httpGet:
          path: /health.php   # 需实现一个简单的健康检查接口
          port: 9000
        initialDelaySeconds: 10
        periodSeconds: 5
  5. CI/CD 集成

    • 在 GitLab CI / GitHub Actions 中构建镜像 → 推送到私有仓库 → 更新 Deployment 的镜像版本(kubectl set image)。

常见问题排查

  • 502 Bad Gateway:PHP-FPM 未启动或端口未正确暴露(检查 Service 和 Pod 连通性)。
  • 404 Not Found:Nginx 配置的 root 路径错误,或 Ingress 的 path 规则不匹配。
  • 权限问题:容器内用户(如 appuser:1001)对 var/ 目录无写权限,需在 Dockerfile 或启动命令中调整。

推荐工具

  • Helm:将上述 YAML 模板化,通过 helm install 一键部署。
  • Kustomize:Git 原生方式管理环境差异(开发/测试/生产)。
  • Statamic/Laravel 专用图表:社区已有现成的 Helm Chart(如 bitnami/laravelstatamic 等)。

通过以上步骤,你可以将 PHP 应用容器化并顺利部署到 K8s 集群,同时利用自动扩缩容(HPA)、滚动更新、服务发现等云原生特性。

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