本文详细记录了在现有 Kubernetes 集群上,为一个 PHP 项目部署“双 Nginx”架构的完整过程。该方案采用 应用内嵌 Nginx + 外部 Ingress Nginx 的模式,实现了动静分离、高性能反向代理和灵活的外部访问控制。


📋 架构概览

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

🏗️ “双 Nginx” 架构详解

  1. 内部 Nginx (Pod 内):

    • 作为 PHP-FPM 的前置服务器,直接处理所有请求。
    • 负责静态文件(JS, CSS, 图片)的高效服务。
    • 将 PHP 动态请求通过 fastcgi_pass 转发给同 Pod 内的 PHP-FPM 进程。
    • 提供应用级的 URL 重写和安全规则。
  2. 外部 Ingress Nginx (Kubernetes 层):

    • 作为集群的统一入口,管理所有对外暴露的服务。
    • 接收来自客户端的所有流量,并根据 Host 和 Path 规则将请求路由到后端 Service。
    • 统一处理 TLS/SSL 加密、HTTP 到 HTTPS 重定向等。
    • 实现跨应用的负载均衡和高级流量管理。

优势

  • 性能:内部 Nginx 直接服务静态资源,避免了 Ingress 层的数据拷贝。
  • 灵活性:可以独立配置每个应用的 Nginx 规则,无需修改全局 Ingress 配置。
  • 隔离性:应用的特定需求(如复杂的 rewrite 规则)由内部 Nginx 承载,不影响其他服务。

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

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

1. 创建 NFS PersistentVolume

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

2. 创建 PersistentVolumeClaim

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

🔧 操作步骤

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

✅ 第二步:构建应用镜像

本方案将 Nginx 和 PHP-FPM 打包进同一个 Docker 镜像。

1. Dockerfile 核心内容

FROM ubuntu:22.04

LABEL maintainer="devops@example.com"

# 设置环境变量
ENV NGINX_VERSION=1.26.2 \
    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/*

# 添加 Nginx GPG 密钥和 APT 源
RUN curl -fsSL https://nginx.org/keys/nginx_signing.key | gpg --dearmor -o /usr/share/keyrings/nginx-archive-keyring.gpg && \
    echo "deb [signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg] http://nginx.org/packages/ubuntu $(lsb_release -cs) nginx" | tee /etc/apt/sources.list.d/nginx.list && \
    echo "deb-src [signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg] http://nginx.org/packages/ubuntu $(lsb_release -cs) nginx" | tee -a /etc/apt/sources.list.d/nginx.list

# 添加 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

# 安装 Nginx 和 PHP-FPM
RUN apt-get install -y nginx=${NGINX_VERSION}* 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/testliveapi1.doubbjt.com /var/log/nginx

# 复制自定义 Nginx 配置
COPY nginx.conf /etc/nginx/nginx.conf
COPY liveapi.doubbjt.com.conf /etc/nginx/conf.d/liveapi.doubbjt.com.conf

# 复制自定义 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 /var/log/nginx

# 暴露端口
EXPOSE 80

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

CMD ["/start.sh"]

2. 自定义 Nginx 配置 (liveapi.doubbjt.com.conf)

server {
    listen 80;
    server_name liveapi.doubbjt.com;

    # ⭐ 根目录指向挂载的 NFS 卷
    root /www/wwwroot/testliveapi1.doubbjt.com;
    index index.php index.html index.htm;

    # ⭐ SSL 配置(证书和私钥从 Secret 挂载)
    ssl_certificate /ssl/doubbjt.com.pem;
    ssl_certificate_key /ssl/doubbjt.com.key;
    ssl_session_timeout 10m;
    add_header Strict-Transport-Security "max-age=31536000";
    error_page 497 https://$host$request_uri;

    # ⭐ 主要 location 块:反向代理到 PHP-FPM
    location / {
        proxy_pass http://dbb-live-api-service.test.svc.cluster.local:80;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header X-Forwarded-Host $host;
        proxy_set_header X-Forwarded-Port $server_port;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_http_version 1.1;
        proxy_buffering off;
        proxy_request_buffering off;
        proxy_read_timeout 300s;
        proxy_send_timeout 300s;
        client_max_body_size 100M;
    }

    # ⭐ Let's Encrypt 验证专用路径
    location ^~ /.well-known/acme-challenge/ {
        root /www/wwwroot/testliveapi1.doubbjt.com;
        allow all;
        default_type "text/plain";
        try_files $uri =404;
    }

    # ⭐ 日志配置
    access_log /var/log/nginx/liveapi.doubbjt.com.log main;
    error_log /var/log/nginx/liveapi.doubbjt.com.error.log;
}

🔐 关键点

  • location /: 将所有请求反向代理到后端的 Kubernetes Service。此配置确保了即使在 Pod 内,请求也遵循与生产环境一致的路由逻辑。
  • location ^~ /.well-known/acme-challenge/: 为 Cert-Manager 等工具提供 ACME 挑战验证的专用路径。
  • client_max_body_size 100M;: 允许大文件上传。

3. 自定义 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: 设置正确的时区。

4. 启动脚本 (start.sh)

#!/bin/bash
set -e

# 确保 Nginx 和 PHP-FPM 日志目录存在
mkdir -p /var/log/nginx /var/log/php-fpm

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

# 启动 PHP-FPM (后台运行)
/usr/sbin/php-fpm${PHP_VERSION} --daemonize --fpm-config /etc/php/${PHP_VERSION}/fpm/php-fpm.conf

# 启动 Nginx (前台运行,作为主进程)
exec /usr/sbin/nginx -g "daemon off;"

✅ 第三步:部署 Kubernetes 资源

1. 创建 TLS Secret

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

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

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


2. Deployment 配置 (deployment.yaml)

apiVersion: apps/v1
kind: Deployment
metadata:
  name: dbb-live-api-deployment
  namespace: test
  labels:
    app: dbb-live-api
spec:
  replicas: 2
  selector:
    matchLabels:
      app: dbb-live-api
  template:
    metadata:
      labels:
        app: dbb-live-api
    spec:
      containers:
        - name: nginx-php
          image: your-registry/dbb-live-api:v1.0 # 替换为你的镜像地址
          ports:
            - containerPort: 80
          volumeMounts:
            - name: code-storage
              mountPath: /www/wwwroot/testliveapi1.doubbjt.com
            - name: ssl-certs
              mountPath: /ssl
              readOnly: true
            - name: nginx-logs
              mountPath: /var/log/nginx
          resources:
            limits:
              cpu: 500m
              memory: 512Mi
            requests:
              cpu: 200m
              memory: 256Mi
      volumes:
        - name: code-storage
          persistentVolumeClaim:
            claimName: nfs-pvc-dbb-live-api-test
        - name: ssl-certs
          secret:
            secretName: doubbjt-com-tls
        - name: nginx-logs
          emptyDir: {}
---
apiVersion: v1
kind: Service
metadata:
  name: dbb-live-api-service
  namespace: test
spec:
  selector:
    app: dbb-live-api
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80
  type: ClusterIP

🔧 核心配置

  • volumeMounts: 挂载 PVC 用于代码和上传文件,挂载 Secret 用于 SSL 证书。
  • resources: 定义合理的 CPU 和内存限制。

3. Ingress 配置 (ingress.yaml)

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: dbb-live-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"
spec:
  ingressClassName: nginx
  tls:
    - hosts:
        - liveapi.doubbjt.com
      secretName: doubbjt-com-tls
  rules:
    - host: liveapi.doubbjt.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: dbb-live-api-service
                port:
                  number: 80

🌐 流量走向

  1. 客户端访问 https://liveapi.doubbjt.com
  2. 请求到达 ingress-nginx-controller Pod。
  3. Ingress Controller 根据规则,将请求转发到 dbb-live-api-service
  4. Service 将请求负载均衡到任一 dbb-live-api-deployment 的 Pod。
  5. Pod 内的 内部 Nginx 接收到请求,根据其配置进行处理(例如,如果是 PHP 请求,则通过 fastcgi_pass 转发给同 Pod 内的 PHP-FPM)。

✅ 总结

你已完成以下目标:

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

此方案特别适用于需要高性能静态资源服务、复杂 URL 重写或对 PHP 环境有精细控制需求的传统 PHP 应用迁移至 Kubernetes 的场景。

Logo

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

更多推荐