本文目录导读:

将 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=1和opcache.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 集群
-
创建命名空间(可选)
kubectl create namespace my-php-app
-
应用所有资源
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
-
验证部署
kubectl get pods -n my-php-app kubectl get svc -n my-php-app kubectl describe ingress php-app-ingress -n my-php-app
关键注意事项
-
Session 存储:
- 在 K8s 中,默认文件存储 Session 不可靠(Pod 重启后丢失),建议使用外部存储(Redis、Memcached 或数据库)。
- 在
php.ini或代码中配置session.save_handler = redis指向 Redis Service。
-
文件持久化:
- 上传文件:必须存储在持久卷(PV/PVC)、对象存储(S3/MinIO)或共享存储(NFS)上。
- 日志:建议将日志输出到
stdout/stderr(K8s 会自动收集),或挂载到持久卷。
-
共享文件系统:
- PHP 和 Nginx 在同一 Pod(容器共享卷),确保代码或上传目录通过
emptyDir或 PV 共享。
- PHP 和 Nginx 在同一 Pod(容器共享卷),确保代码或上传目录通过
-
健康检查:
- 添加 Liveness 和 Readiness 探针,避免流量发送到异常 Pod:
livenessProbe: httpGet: path: /health.php # 需实现一个简单的健康检查接口 port: 9000 initialDelaySeconds: 10 periodSeconds: 5
- 添加 Liveness 和 Readiness 探针,避免流量发送到异常 Pod:
-
CI/CD 集成:
- 在 GitLab CI / GitHub Actions 中构建镜像 → 推送到私有仓库 → 更新 Deployment 的镜像版本(
kubectl set image)。
- 在 GitLab CI / GitHub Actions 中构建镜像 → 推送到私有仓库 → 更新 Deployment 的镜像版本(
常见问题排查
- 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/laravel、statamic等)。
通过以上步骤,你可以将 PHP 应用容器化并顺利部署到 K8s 集群,同时利用自动扩缩容(HPA)、滚动更新、服务发现等云原生特性。