本文目录导读:

- 核心架构:PHP-FPM + Nginx 分离
- PHP 容器镜像最佳实践
- 配置管理:ConfigMap + Secret
- 有状态部分:Session 和 文件存储
- 水平伸缩与监控
- CI/CD 流水线建议
- 常见坑与优化
- 完整项目结构示例
在Kubernetes中编排管理PHP容器,核心思路是将PHP应用无状态化,并利用K8s的调度、伸缩、服务发现和配置管理能力,以下是具体的编排方案和最佳实践。
核心架构:PHP-FPM + Nginx 分离
这是最标准、最高效的K8s PHP部署模式。PHP-FPM 处理PHP代码逻辑,Nginx 作为反向代理静态文件和请求转发。
部署文件示例(Deployment + Service)
(1) PHP-FPM Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: php-fpm
spec:
replicas: 3
selector:
matchLabels:
app: php-backend
template:
metadata:
labels:
app: php-backend
spec:
# 可选:使用私有仓库拉取镜像
# imagePullSecrets:
# - name: my-registry-key
containers:
- name: php-fpm
image: your-registry/php-fpm:8.2 # 或使用官方镜像加自定义
ports:
- containerPort: 9000
env:
- name: APP_ENV
value: "production"
- name: DB_HOST
valueFrom:
secretKeyRef:
name: db-secret
key: host
livenessProbe:
tcpSocket:
port: 9000
initialDelaySeconds: 10
periodSeconds: 15
readinessProbe:
tcpSocket:
port: 9000
initialDelaySeconds: 5
periodSeconds: 5
resources:
requests:
memory: "128Mi"
cpu: "100m"
limits:
memory: "512Mi"
cpu: "500m"
volumeMounts:
- name: php-code
mountPath: /var/www/html
# 可选:挂载配置文件
- name: php-config
mountPath: /usr/local/etc/php/conf.d/custom.ini
subPath: custom.ini
volumes:
- name: php-code
emptyDir: {} # 或使用PVC共享代码
- name: php-config
configMap:
name: php-config
(2) Nginx Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
replicas: 3
selector:
matchLabels:
app: nginx-proxy
template:
metadata:
labels:
app: nginx-proxy
spec:
volumes:
- name: php-code
emptyDir: {}
- name: nginx-config
configMap:
name: nginx-config
initContainers:
- name: copy-php-code
image: busybox
command: ['sh', '-c', 'cp -r /src/* /dest/']
volumeMounts:
- name: php-code
mountPath: /dest
containers:
- name: nginx
image: nginx:alpine
ports:
- containerPort: 80
volumeMounts:
- name: php-code
mountPath: /var/www/html
readOnly: true
- name: nginx-config
mountPath: /etc/nginx/conf.d/default.conf
subPath: default.conf
livenessProbe:
httpGet:
path: /health.php # 需要有一个健康检查文件
port: 80
initialDelaySeconds: 10
periodSeconds: 10
(3) 共享代码卷
通常使用 PVC(PersistentVolumeClaim) 或 InitContainer 来同步代码:
- PVC方式:
ReadWriteMany模式(如NFS、CephFS) - InitContainer方式:用
emptyDir+ InitContainer从代码仓库拉取,适合代码定期更新场景
(4) 服务发现 Service
---
apiVersion: v1
kind: Service
metadata:
name: php-fpm-service
spec:
selector:
app: php-backend
ports:
- port: 9000
targetPort: 9000
---
apiVersion: v1
kind: Service
metadata:
name: nginx-service
spec:
type: ClusterIP # 外部访问用Ingress
selector:
app: nginx-proxy
ports:
- port: 80
targetPort: 80
(5) Ingress 暴露外部访问
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: php-app-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
ingressClassName: nginx
rules:
- host: app.yourdomain.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: nginx-service
port:
number: 80
tls: # 可选HTTPS
- hosts:
- app.yourdomain.com
secretName: tls-secret
PHP 容器镜像最佳实践
# 多阶段构建,减小镜像体积
FROM composer:2.5 as build
WORKDIR /app
COPY composer.json composer.lock ./
RUN composer install --no-dev --optimize-autoloader
FROM php:8.2-fpm-alpine
WORKDIR /var/www/html
# 安装必要扩展
RUN docker-php-ext-install pdo_mysql opcache redis bcmath
# 复制依赖(从第一阶段)
COPY --from=build /app/vendor /var/www/html/vendor
# 复制应用代码
COPY . /var/www/html
# 设置权限
RUN chown -R www-data:www-data /var/www/html \
&& chmod -R 755 /var/www/html/storage /var/www/html/bootstrap/cache
# 挂载点声明
VOLUME ["/var/www/html/storage", "/var/www/html/public/uploads"]
USER www-data
EXPOSE 9000
CMD ["php-fpm"]
配置管理:ConfigMap + Secret
# configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: php-config
data:
custom.ini: |
memory_limit = 256M
max_execution_time = 120
post_max_size = 50M
upload_max_filesize = 20M
---
# secret.yaml
apiVersion: v1
kind: Secret
metadata:
name: db-secret
type: Opaque
stringData:
host: "mysql-service.default.svc.cluster.local"
database: "myapp"
username: "app_user"
password: "your_secure_password"
在PHP代码中,通过环境变量读取配置:
$dbHost = $_ENV['DB_HOST'] ?? 'localhost'; // 或使用 dotenv 库
有状态部分:Session 和 文件存储
PHP应用通常需要处理 Session 和 上传文件,在K8s中必须外部化:
- Session存储 → 使用 Redis 或 Memcached
- 上传文件存储 → 使用 对象存储 (AWS S3 / MinIO) 或 共享PVC (NFS)
- 日志集中化 → 使用
Filebeat+ELK或 直接输出到stdout/stderr由容器运行时处理
Session 配置示例(Redis):
session.save_handler = redis session.save_path = "tcp://redis-service:6379?auth=yourpass"
水平伸缩与监控
自动伸缩 (HPA)
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: php-fpm-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: php-fpm
minReplicas: 2
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: 80
Pod 资源请求/限制
- PHP-FPM:通常每个Pod建议 200m CPU / 256Mi 内存(请求),500m / 512Mi(限制)
- Nginx:更轻量,100m / 128Mi 即可
监控集成
- K8s自带的dashboard、Prometheus + Grafana 或 Datadog。
- 提示:可以暴露PHP-FPM的状态页(
pm.status_path = /status)给监控组件。
CI/CD 流水线建议
- 代码提交 → 触发GitLab CI / GitHub Actions
- 构建镜像 → 将PHP应用编译到镜像中(包含所有依赖)
- 推送到仓库 → 带版本标签(如
v1.2.3或commit hash) - 更新K8s → 执行
kubectl set image deployment/php-fpm app=your-registry/php-app:v1.2.3 - 滚动更新 → K8s自动处理,零停机
常见坑与优化
| 问题 | 解决方案 |
|---|---|
| PHP代码文件需要频繁更新 | 用InitContainer或sidecar同步代码,或把代码放入镜像重建 |
| 上传文件丢失 | 必须用PVC (ReadWriteMany) 或 S3 代替本地存储 |
| Session丢失 | 迁移到 Redis/数据库存储 |
| PHP-FPM进程数不合适 | 调整 pm.max_children, pm.start_servers,使用 HPA |
| Nginx缓存问题 | 清理opcache,使用CDN |
| 数据库连接过多 | 配置数据库最大连接数,使用连接池 |
完整项目结构示例
php-k8s/
├── k8s/
│ ├── namespace.yaml
│ ├── configmap.yaml
│ ├── secret.yaml
│ ├── php-fpm-deployment.yaml
│ ├── nginx-deployment.yaml
│ ├── services.yaml
│ ├── ingress.yaml
│ └── hpa.yaml
├── docker/
│ ├── php.Dockerfile
│ └── nginx.Dockerfile
├── src/
│ ├── public/
│ ├── app/
│ ├── config/
│ └── composer.json
└── .gitlab-ci.yml
K8s编排PHP的核心原则:无状态 + 外部化存储 + 合理资源控制,推荐采用 PHP-FPM + Nginx 分离架构,用 ConfigMap 管理配置,Secret 管理敏感信息,Redis 管理Session,对象存储 管理文件,配合HPA实现弹性伸缩。
这样既发挥了K8s的弹性优势,又避免了PHP传统部署中的状态管理难题。