本文详细记录了在现有 Kubernetes 集群上,为一个 PHP 项目部署“单 Nginx”架构的完整过程。该方案采用 仅使用 Ingress Nginx 的模式,将应用的反向代理和静态资源服务完全交给 Kubernetes 层的 Ingress Controller 处理。


📋 架构概览

项目 配置
应用类型 PHP (ThinkPHP)
容器运行时 containerd
部署方式 Kubernetes Deployment
网络架构 单 Nginx 模式
存储 NFS PersistentVolume
Ingress 控制器 ingress-nginx

🏗️ “单 Nginx” 架构详解

  1. Pod 内应用:

    • 仅包含 php-fpm 进程,负责执行 PHP 脚本。
    • 不包含任何 Web 服务器(如 Nginx 或 Apache)。
  2. 外部 Ingress Nginx (Kubernetes 层):

    • 作为集群的统一入口,管理所有对外暴露的服务。
    • 接收来自客户端的所有流量,并根据 Host 和 Path 规则将请求路由到后端 Service。
    • 统一处理 TLS/SSL 加密、HTTP 到 HTTPS 重定向等。
    • 直接从 Pod 中提供静态文件服务(通过挂载的 PVC),并动态地将 PHP 请求反向代理给 php-fpm

优势

  • 简单性:架构更简单,运维复杂度低。
  • 统一管理:所有应用的 SSL 证书、URL 重写规则都在 Ingress 层集中配置。
  • 资源优化:每个 Pod 不再需要运行额外的 Nginx 进程,节省了 CPU 和内存。

✅ 第一步:准备持久化存储 (NFS)

为 PHP 应用创建基于 NFS 的持久化存储,用于存放代码和上传文件。

1. 创建 NFS PersistentVolume

# nfs-pv.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
  name: nfs-pv-wanyanzhenjiang-api-test
spec:
  capacity:
    storage: 10Gi
  accessModes:
    - ReadWriteMany # 必须支持多节点读写
  persistentVolumeReclaimPolicy: Retain
  nfs:
    server: 192.168.122.189 # NFS 服务器 IP
    path: /opt/nfs/wanyanzhenjiang-api-test # NFS 共享目录
  mountOptions:
    - nfsvers=4.1
    - hard
    - intr

2. 创建 PersistentVolumeClaim

# nfs-pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: nfs-pvc-wanyanzhenjiang-api-test
  namespace: test # 部署目标命名空间
spec:
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 10Gi
  volumeName: nfs-pv-wanyanzhenjiang-api-test # 关联已创建的 PV

🔧 操作步骤

  1. 在 NFS 服务器 (192.168.122.189) 上创建共享目录并设置权限:
    sudo mkdir -p /opt/nfs/wanyanzhenjiang-api-test
    sudo chmod 755 /opt/nfs/wanyanzhenjiang-api-test
    
  2. /etc/exports 中添加导出规则:
    /opt/nfs/wanyanzhenjiang-api-test *(rw,sync,no_root_squash)
    
  3. 重新加载 NFS 配置:
    exportfs -ra
    
  4. 在 Kubernetes 集群中应用 PV 和 PVC YAML 文件。

✅ 第二步:构建应用镜像

本方案只包含 php-fpm 进程。

1. Dockerfile 核心内容

FROM ubuntu:22.04

LABEL maintainer="devops@example.com"

# 设置环境变量
ENV PHP_VERSION=8.1.29 \
    DEBIAN_FRONTEND=noninteractive

# 使用阿里云镜像源加速 apt
RUN sed -i 's/archive.ubuntu.com/mirrors.aliyun.com/g' /etc/apt/sources.list && \
    sed -i 's/security.ubuntu.com/mirrors.aliyun.com/g' /etc/apt/sources.list

# 安装基础工具和依赖
RUN apt-get update && \
    apt-get install -y curl wget gnupg lsb-release ca-certificates && \
    rm -rf /var/lib/apt/lists/*

# 添加 PHP GPG 密钥和 APT 源
RUN curl -fsSL https://packages.sury.org/php/apt.gpg | gpg --dearmor -o /usr/share/keyrings/php-archive-keyring.gpg && \
    echo "deb [signed-by=/usr/share/keyrings/php-archive-keyring.gpg] https://packages.sury.org/php/ $(lsb_release -cs) main" | tee /etc/apt/sources.list.d/php.list

# 更新软件包列表
RUN apt-get update

# 仅安装 PHP-FPM 及其扩展
RUN apt-get install -y php${PHP_VERSION}-fpm php${PHP_VERSION}-mysql php${PHP_VERSION}-gd php${PHP_VERSION}-curl php${PHP_VERSION}-mbstring php${PHP_VERSION}-xml php${PHP_VERSION}-zip

# 清理缓存
RUN apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*

# 创建 Web 目录
RUN mkdir -p /www/wwwroot/testwanyanzhenjiangapi1.wanyanzhenjiang.com

# 复制自定义 PHP 配置
COPY php.ini /etc/php/${PHP_VERSION}/fpm/php.ini

# 创建 www-data 用户组并加入 php-fpm
RUN groupadd -g 82 www-data && \
    usermod -u 82 -g www-data www-data && \
    usermod -a -G www-data www-data

# 确保目录权限正确
RUN chown -R www-data:www-data /www

# 启动脚本
COPY start.sh /start.sh
RUN chmod +x /start.sh

CMD ["/start.sh"]

2. 自定义 PHP 配置 (php.ini)

[PHP]
zend.exception_ignore_args = On
zend.exception_string_param_max_len = 0
expose_php = Off
max_execution_time = 15
max_input_time = 30
memory_limit = 512M
error_reporting = E_ALL & ~E_DEPRECATED & ~E_STRICT & ~E_WARNING & ~E_NOTICE
display_errors = Off
display_startup_errors = Off
log_errors = On
log_errors_max_len = 1024
ignore_repeated_errors = On
ignore_repeated_source = On
report_memleaks = On
variables_order = GPCS
request_order = GP
register_argc_argv = Off
auto_globals_jit = On
post_max_size = 50M
auto_prepend_file =
auto_append_file =
default_mimetype = text/html
default_charset =

[Session]
session.save_handler = files
session.save_path = "/tmp"
session.use_strict_mode = 0
session.use_cookies = 1
session.cookie_secure = 1
session.cookie_httponly = 1
session.cookie_samesite = Lax
session.name = PHPSESSID
session.gc_probability = 1
session.gc_divisor = 1000
session.gc_maxlifetime = 1440
session.referer_check =
session.cache_limiter = nocache
session.cache_expire = 180
session.use_trans_sid = 0
session.sid_length = 26
session.sid_bits_per_character = 5

[Date]
date.timezone = Asia/Shanghai

[mbstring]
mbstring.language = neutral
mbstring.internal_encoding = UTF-8
mbstring.http_input = auto
mbstring.http_output = UTF-8
mbstring.encoding_translation = Off
mbstring.detect_order = auto
mbstring.substitute_character = none
mbstring.func_overload = 0

[opcache]
opcache.enable = 1
opcache.enable_cli = 0
opcache.memory_consumption = 128
opcache.interned_strings_buffer = 8
opcache.max_accelerated_files = 4000
opcache.validate_timestamps = 1
opcache.revalidate_freq = 2
opcache.fast_shutdown = 1

[mysqlnd]
mysqlnd.collect_statistics = On
mysqlnd.collect_memory_statistics = Off

优化说明

  • expose_php = Off: 隐藏 PHP 版本信息,提升安全性。
  • session.cookie_secure = 1: 仅通过 HTTPS 发送会话 Cookie。
  • opcache.enable = 1: 启用 OPcache,大幅提升 PHP 脚本执行性能。
  • date.timezone = Asia/Shanghai: 设置正确的时区。

3. 启动脚本 (start.sh)

#!/bin/bash
set -e

# 初始化时,如果 NFS 目录为空,可以从备份恢复或克隆代码
# if [ ! "$(ls -A /www/wwwroot/testwanyanzhenjiangapi1.wanyanzhenjiang.com)" ]; then
#   git clone https://your-repo.git /www/wwwroot/testwanyanzhenjiangapi1.wanyanzhenjiang.com
# fi

# 启动 PHP-FPM (前台运行,作为主进程)
exec /usr/sbin/php-fpm${PHP_VERSION} --nodaemonize --fpm-config /etc/php/${PHP_VERSION}/fpm/php-fpm.conf

⚠️ 关键点:使用 --nodaemonize 参数确保 PHP-FPM 在前台运行,这样它才能接收 SIGTERM 信号并优雅关闭。


✅ 第三步:部署 Kubernetes 资源

1. 创建 TLS Secret

首先,将 SSL 证书和私钥创建为 Kubernetes Secret。

kubectl create secret tls wanyanzhenjiang-com-tls \
  --cert=wanyanzhenjiang.com.pem \
  --key=wanyanzhenjiang.com.key \
  --namespace=test

🔐 敏感信息处理:原文中的证书内容已被移除,实际部署时需使用有效的证书文件。


2. Deployment 配置 (deployment.yaml)

apiVersion: apps/v1
kind: Deployment
meta
  name: wanyanzhenjiang-api-deployment
  namespace: test
  labels:
    app: wanyanzhenjiang-api
spec:
  replicas: 2
  selector:
    matchLabels:
      app: wanyanzhenjiang-api
  template:
    meta
      labels:
        app: wanyanzhenjiang-api
    spec:
      containers:
        - name: php-fpm
          image: your-registry/wanyanzhenjiang-api-php:v1.0 # 替换为你的镜像地址
          ports:
            - containerPort: 9000 # PHP-FPM 默认 FastCGI 端口
          volumeMounts:
            - name: code-storage
              mountPath: /www/wwwroot/testwanyanzhenjiangapi1.wanyanzhenjiang.com
          resources:
            limits:
              cpu: 500m
              memory: 512Mi
            requests:
              cpu: 200m
              memory: 256Mi
      volumes:
        - name: code-storage
          persistentVolumeClaim:
            claimName: nfs-pvc-wanyanzhenjiang-api-test
---
apiVersion: v1
kind: Service
meta
  name: wanyanzhenjiang-api-service
  namespace: test
spec:
  selector:
    app: wanyanzhenjiang-api
  ports:
    - protocol: TCP
      port: 9000
      targetPort: 9000
  type: ClusterIP

🔧 核心配置

  • containerPort: 9000: PHP-FPM 侦听的 FastCGI 端口。
  • volumeMounts: 挂载 PVC 用于代码和上传文件。

3. Ingress 配置 (ingress.yaml)

apiVersion: networking.k8s.io/v1
kind: Ingress
meta
  name: wanyanzhenjiang-api-ingress
  namespace: test
  annotations:
    kubernetes.io/ingress.class: "nginx"
    nginx.ingress.kubernetes.io/ssl-redirect: "true"
    nginx.ingress.kubernetes.io/proxy-body-size: "100m"
    nginx.ingress.kubernetes.io/proxy-read-timeout: "300"
    nginx.ingress.kubernetes.io/proxy-send-timeout: "300"
    # 👇 关键:启用 fastcgi 支持
    nginx.ingress.kubernetes.io/fastcgi-index: index.php
    nginx.ingress.kubernetes.io/fastcgi-socket-path: /run/php/php8.1-fpm.sock
    # 👇 将所有非静态文件请求转发给 php-fpm
    nginx.ingress.kubernetes.io/configuration-snippet: |
      location ~ \.php$ {
        fastcgi_pass wanyanzhenjiang-api-service:9000;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param PATH_INFO $fastcgi_path_info;
      }
spec:
  ingressClassName: nginx
  tls:
    - hosts:
        - wanyanzhenjiangapi.wanyanzhenjiang.com
      secretName: wanyanzhenjiang-com-tls
  rules:
    - host: wanyanzhenjiangapi.wanyanzhenjiang.com
      http:
        paths:
          # 👇 将根路径映射到代码目录
          - path: /
            pathType: Prefix
            backend:
              service:
                name: wanyanzhenjiang-api-service
                port:
                  number: 9000

🌐 流量走向

  1. 客户端访问 https://wanyanzhenjiangapi.wanyanzhenjiang.com
  2. 请求到达 ingress-nginx-controller Pod。
  3. Ingress Controller 根据 configuration-snippet 中的规则:
    • 如果是 .php 文件,则通过 fastcgi_pass 将请求转发给后端 Service 的 9000 端口(即 PHP-FPM)。
    • 如果是静态文件(JS, CSS, 图片),则直接从挂载的代码目录中读取并返回。
  4. PHP-FPM 执行 PHP 脚本,并将结果返回给 Ingress Controller,最终响应给客户端。

✅ 总结

你已完成以下目标:

✅ 为 PHP 项目设计并实现了“单 Nginx”架构,简化了部署结构
✅ 配置了基于 NFS 的 ReadWriteMany 存储,满足多副本应用的共享存储需求
✅ 编写了仅包含 PHP-FPM 的轻量级生产级 Docker 镜像
✅ 通过 Kubernetes Secret 安全地管理了 SSL 证书
✅ 部署了完整的 Kubernetes 资源(Deployment, Service, Ingress),实现了应用的高可用和外部访问

此方案特别适用于希望简化架构、统一管理入口、并对运维复杂度有要求的新建 PHP 应用迁移至 Kubernetes 的场景。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐