如何在Kubernetes Pod中实现Caddy与PHP-FPM的代码分离部署
解决方案:实现Caddy仅存配置、代码在PHP-FPM容器的架构
你的问题核心在于:Caddy的file_server指令需要读取本地静态文件,而PHP-FPM仅能处理PHP脚本的FastCGI请求,无法直接响应静态文件HTTP请求。要实现Caddy仅存放配置、代码完全在PHP-FPM侧的架构,有两种可行方案:
方案1:PHP-FPM容器内置HTTP服务器(严格满足代码仅在PHP-FPM容器)
让PHP-FPM容器同时运行一个HTTP服务器(比如Nginx),由它负责处理静态文件,并将PHP请求转发给本地的PHP-FPM进程。Caddy仅作为反向代理,将所有请求转发到PHP-FPM容器内的HTTP服务器,完全不接触代码。
步骤1:修改Caddy配置
移除原配置中涉及本地文件读取的root、file_server和静态文件规则,改为反向代理:
my.caddy.website:80 { reverse_proxy localhost:8080 # 指向PHP-FPM容器内的HTTP服务器端口 encode gzip log { output file /var/log/caddy/my.caddy.website.access.log } # 静态文件缓存规则可以保留,由后端HTTP服务器处理后,Caddy添加响应头 @static { path *.ico *.css *.js *.gif *.jpg *.jpeg *.png *.svg *.woff *.pdf *.webp } header @static Cache-Control max-age=5184000 }
步骤2:构建包含HTTP服务器的PHP-FPM镜像
需要自定义PHP-FPM镜像,内置Nginx、应用代码,并配置Nginx处理静态文件和PHP请求:
- 镜像中安装PHP-FPM、Nginx和进程管理工具(如
supervisord) - 添加Nginx配置示例:
server { listen 8080; root /app; # 处理静态文件 location / { try_files $uri $uri/ /index.php?$query_string; } # 转发PHP请求到本地PHP-FPM location ~ \.php$ { fastcgi_pass 127.0.0.1:9000; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; } }
- 编写启动脚本,用
supervisord同时启动Nginx和PHP-FPM
步骤3:Kubernetes Deployment配置
将Caddy和自定义PHP-FPM容器放在同一个Pod中(共享网络,可通过localhost通信):
apiVersion: apps/v1 kind: Deployment metadata: name: php-caddy-app spec: replicas: 1 selector: matchLabels: app: php-caddy template: metadata: labels: app: php-caddy spec: containers: - name: php-fpm-nginx image: your-custom-php-nginx-image # 替换为你的自定义镜像 ports: - containerPort: 8080 - name: caddy image: caddy:2-alpine volumeMounts: - name: caddy-config mountPath: /etc/caddy/Caddyfile ports: - containerPort: 80 volumes: - name: caddy-config configMap: name: caddy-config # 提前创建包含Caddy配置的ConfigMap
方案2:共享卷挂载(K8s最佳实践,性能更优)
用Kubernetes共享卷存储应用代码,Caddy和PHP-FPM容器同时挂载该卷。此方案中,代码存储在卷而非容器镜像内,Caddy镜像仅包含Caddy程序和配置,符合“仅存配置”的要求,同时静态文件由Caddy直接处理,性能更好。
步骤1:调整Kubernetes Deployment配置
定义共享卷(生产环境建议用PersistentVolumeClaim,示例用EmptyDir),并挂载到两个容器的/app目录:
apiVersion: apps/v1 kind: Deployment metadata: name: php-caddy-app spec: replicas: 1 selector: matchLabels: app: php-caddy template: metadata: labels: app: php-caddy spec: volumes: - name: app-code emptyDir: {} # 临时存储,重启Pod会丢失,生产环境替换为PersistentVolumeClaim - name: caddy-config configMap: name: caddy-config # 可选:用initContainer拉取代码到共享卷 initContainers: - name: fetch-app-code image: alpine/git command: ["git", "clone", "https://your-repo-url.git", "/app"] volumeMounts: - name: app-code mountPath: /app containers: - name: php-fpm image: php:8.2-fpm volumeMounts: - name: app-code mountPath: /app - name: caddy image: caddy:2-alpine volumeMounts: - name: app-code mountPath: /app - name: caddy-config mountPath: /etc/caddy/Caddyfile ports: - containerPort: 80
步骤2:保留原Caddy配置
原配置可直接使用,因为Caddy现在能通过共享卷访问到/app目录的静态文件,PHP请求转发到localhost:9000(同一Pod内的PHP-FPM容器)。
方案对比
| 方案 | 优点 | 缺点 |
|---|---|---|
| PHP-FPM内置HTTP服务器 | 代码完全在PHP-FPM容器内,Caddy完全不接触代码 | 容器需运行多进程,复杂度高;静态文件性能略低 |
| 共享卷挂载 | 架构清晰,各容器职责单一;静态文件由Caddy处理,性能更优 | 代码存储在卷而非PHP-FPM镜像内;需管理卷的代码同步 |
内容的提问来源于stack exchange,提问作者Nagri
相关产品推荐
相关产品推荐

