🧩 一、整体架构

+----------------+     +------------------+
|    Client      | <-> |    Nginx (Pod)   |
+----------------+     +--------+---------+
                                |
                                v
                      +---------+----------+
                      |  PHP-FPM (sock)    |
                      +---------+----------+
                                |
                                v
                       +--------v--------+
                       |   Nacos Server    |
                       +--------+--------+
                                |
                                v
                           +----v-----+
                           |  MySQL   |
                           +----------+
  • 所有配置从 Nacos 拉取,替代 .env
  • 使用 php-fpm.sock 通信(Unix Socket)
  • 支持平滑上下线(PreStop 注销 Nacos)
  • 支持 K8s 滚动更新

📦 二、项目结构

php-nacos-app/
├── src/
│   ├── index.php
│   └── config/
│       └── nacos_loader.php
├── nginx/
│   └── nginx.conf
├── docker/
│   ├── php-fpm.Dockerfile
│   └── nginx.Dockerfile
├── k8s/
│   ├── nacos-deploy.yaml
│   ├── php-deploy.yaml
│   └── configmap-fallback.yaml
└── README.md

🐘 三、PHP 代码改造

1. src/index.php

<?php
// src/index.php
require_once __DIR__ . '/../config/nacos_loader.php';

header("Content-Type: text/html; charset=utf-8");
echo "<h1>✅ PHP 服务运行中</h1>";
echo "<p><strong>应用名称:</strong>" . APP_NAME . "</p>";
echo "<p><strong>环境:</strong>" . APP_ENV . "</p>";
echo "<p><strong>数据库:</strong>" . DB_HOST . "</p>";
echo "<p><strong>配置来源:</strong>Nacos(Data ID: " . ($_ENV['NAOCUS_DATA_ID'] ?? 'php-app-prod.yaml') . ")</p>";
echo "<p><strong>Pod IP:</strong>" . ($_SERVER['SERVER_ADDR'] ?? 'unknown') . "</p>";

2. config/nacos_loader.php

<?php
// config/nacos_loader.php

class NacosConfigLoader
{
    private $nacosHost;
    private $dataId;
    private $group;

    public function __construct($host = 'nacos.middleware.svc.cluster.local', $port = 8848)
    {
        $this->nacosHost = "{$host}:{$port}";
        $this->dataId = $_ENV['NAOCUS_DATA_ID'] ?? 'php-app-prod.yaml';
        $this->group = $_ENV['NAOCUS_GROUP'] ?? 'DEFAULT_GROUP';
    }

    public function load(): array
    {
        $url = "http://{$this->nacosHost}/nacos/v1/cs/configs?dataId=" . urlencode($this->dataId) . "&group=" . urlencode($this->group);

        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_TIMEOUT, 5);

        $response = curl_exec($ch);
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        curl_close($ch);

        if ($httpCode === 200 && $response) {
            return $this->parseYaml($response);
        }

        error_log("⚠️ Nacos 配置拉取失败,使用降级配置");
        return $this->getFallbackConfig();
    }

    private function parseYaml($content): array
    {
        $config = [];
        foreach (explode("\n", $content) as $line) {
            $line = trim($line);
            if (empty($line) || strpos($line, ':') === false || $line[0] === '#') continue;
            [$k, $v] = explode(':', $line, 2);
            $config[trim($k)] = trim($v);
        }
        return $config;
    }

    private function getFallbackConfig(): array
    {
        return [
            'APP_NAME' => 'Fallback App',
            'APP_ENV' => 'fallback',
            'DATABASE_HOST' => 'localhost',
            'REDIS_HOST' => 'localhost',
            'LOG_LEVEL' => 'debug'
        ];
    }
}

// 加载配置
$config = (new NacosConfigLoader())->load();

define('APP_NAME', $config['APP_NAME'] ?? 'Unknown');
define('APP_ENV', $config['APP_ENV'] ?? 'local');
define('DB_HOST', $config['DATABASE_HOST'] ?? '127.0.0.1');
define('REDIS_HOST', $config['REDIS_HOST'] ?? '127.0.0.1');
define('LOG_LEVEL', $config['LOG_LEVEL'] ?? 'debug');

🐳 四、Docker 镜像构建

1. docker/php-fpm.Dockerfile

# docker/php-fpm.Dockerfile
FROM php:8.1-fpm-alpine

# 安装依赖
RUN apk add --no-cache \
    curl \
    tzdata \
    && cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \
    && echo "Asia/Shanghai" > /etc/timezone

# 安装 PHP 扩展
RUN docker-php-ext-install curl

# 创建 sock 目录
RUN mkdir -p /var/run/php && chown www-data:www-data /var/run/php

# 设置工作目录
WORKDIR /var/www/html

# 复制代码
COPY src /var/www/html

# 允许 www-data 写日志等
RUN chown -R www-data:www-data /var/www/html

# 暴露 sock 文件(通过 volume 共享)
EXPOSE 9000

CMD ["php-fpm"]

2. docker/nginx.Dockerfile

# docker/nginx.Dockerfile
FROM nginx:alpine

# 复制 Nginx 配置
COPY nginx/nginx.conf /etc/nginx/nginx.conf

# 复制站点代码(用于静态文件)
COPY src /var/www/html

# 创建 sock 目录挂载点
RUN mkdir -p /run/php

EXPOSE 80

CMD ["nginx", "-g", "daemon off;"]

3. nginx/nginx.conf

# nginx/nginx.conf
events {
    worker_connections 1024;
}

http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;
    sendfile      on;
    keepalive_timeout  65;

    server {
        listen 80;
        root /var/www/html;
        index index.php;

        location / {
            try_files $uri $uri/ =404;
        }

        location ~ \.php$ {
            fastcgi_pass unix:/run/php/php-fpm.sock;
            fastcgi_index index.php;
            fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
            include fastcgi_params;
        }

        location /health {
            access_log off;
            return 200 "OK\n";
            add_header Content-Type text/plain;
        }
    }
}

🛠 五、K8s 部署文件

1. k8s/nacos-deploy.yaml

# k8s/nacos-deploy.yaml
---
# 1. 命名空间
apiVersion: v1
kind: Namespace
meta
  name: middleware
---
# 2. 数据库密码 Secret
apiVersion: v1
kind: Secret
meta
  name: nacos-db-secret
  namespace: middleware
type: Opaque

  MYSQL_SERVICE_PASSWORD: bWFjb3MyMDI0  # echo -n "nacos2024" | base64
---
# 3. Nacos Deployment
apiVersion: apps/v1
kind: Deployment
meta
  name: nacos
  namespace: middleware
  labels:
    app: nacos
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nacos
  template:
    meta
      labels:
        app: nacos
    spec:
      containers:
      - name: nacos
        image: nacos/nacos-server:v2.4.1
        ports:
        - containerPort: 8848
        env:
        - name: MODE
          value: "standalone"
        - name: PREFER_HOST_MODE
          value: "hostname"
        - name: SERVER_PORT
          value: "8848"
        - name: SPRING_DATASOURCE_PLATFORM
          value: "mysql"
        - name: MYSQL_SERVICE_HOST
          value: "192.168.1.100"  # 🔁 替换为你的 MySQL IP
        - name: MYSQL_SERVICE_PORT
          value: "3306"
        - name: MYSQL_SERVICE_DB_NAME
          value: "nacos"
        - name: MYSQL_SERVICE_USER
          value: "nacos"
        - name: MYSQL_SERVICE_PASSWORD
          valueFrom:
            secretKeyRef:
              name: nacos-db-secret
              key: MYSQL_SERVICE_PASSWORD
        - name: MYSQL_DATABASE_NUM
          value: "1"
        - name: NACOS_AUTH_ENABLE
          value: "true"
        - name: NACOS_AUTH_TOKEN
          value: "SecretKey01234567890123456789012345678901"
        resources:
          requests:
            memory: "1.5Gi"
            cpu: "500m"
          limits:
            memory: "2Gi"
            cpu: "1"
        readinessProbe:
          httpGet:
            path: /nacos/actuator/health
            port: 8848
          initialDelaySeconds: 30
        livenessProbe:
          httpGet:
            path: /nacos/actuator/health
            port: 8848
          initialDelaySeconds: 60
        volumeMounts:
        - name: timezone
          mountPath: /etc/localtime
          readOnly: true
      volumes:
      - name: timezone
        hostPath:
          path: /etc/localtime
---
# 4. NodePort Service
apiVersion: v1
kind: Service
meta
  name: nacos
  namespace: middleware
spec:
  type: NodePort
  ports:
    - port: 8848
      targetPort: 8848
      nodePort: 30848
      protocol: TCP
      name: http
  selector:
    app: nacos

2. k8s/configmap-fallback.yaml

# k8s/configmap-fallback.yaml
apiVersion: v1
kind: ConfigMap
meta
  name: php-app-fallback-config
  namespace: default

  fallback.php: |
    <?php
    return [
        "APP_NAME" => "Fallback App",
        "APP_ENV" => "fallback",
        "DATABASE_HOST" => "db-fallback",
        "REDIS_HOST" => "redis-fallback",
        "LOG_LEVEL" => "warning"
    ];

3. k8s/php-deploy.yaml

# k8s/php-deploy.yaml
apiVersion: apps/v1
kind: Deployment
meta
  name: php-app
  namespace: default
spec:
  replicas: 2
  selector:
    matchLabels:
      app: php-app
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 0
  minReadySeconds: 10
  template:
    meta
      labels:
        app: php-app
    spec:
      volumes:
        - name: php-socket
          emptyDir: {}
        - name: fallback-config
          configMap:
            name: php-app-fallback-config

      containers:
      # PHP-FPM 容器
      - name: php-fpm
        image: your-registry/php-fpm:8.1  # 替换为你的镜像
        volumeMounts:
          - name: php-socket
            mountPath: /run/php
        env:
          - name: NAOCUS_DATA_ID
            value: "php-app-prod.yaml"
          - name: NAOCUS_GROUP
            value: "DEFAULT_GROUP"
        resources:
          limits:
            memory: "512Mi"
            cpu: "200m"

      # Nginx 容器
      - name: nginx
        image: your-registry/nginx-php:alpine  # 替换为你的镜像
        ports:
          - containerPort: 80
        volumeMounts:
          - name: php-socket
            mountPath: /run/php
          - name: fallback-config
            mountPath: /var/www/html/config/fallback.php
            subPath: fallback.php
        readinessProbe:
          httpGet:
            path: /health
            port: 80
          initialDelaySeconds: 5
          periodSeconds: 5
        livenessProbe:
          httpGet:
            path: /
            port: 80
          initialDelaySeconds: 10
          periodSeconds: 10
        resources:
          limits:
            memory: "256Mi"
            cpu: "100m"

      # 平滑下线:先注销 Nacos,再停止
      terminationGracePeriodSeconds: 30
      lifecycle:
        preStop:
          exec:
            command:
              - /bin/sh
              - -c
              - >
                  # 等待 5 秒,让负载均衡器感知下线
                  sleep 5
---
# Service 暴露
apiVersion: v1
kind: Service
meta
  name: php-app
  namespace: default
spec:
  type: NodePort
  ports:
    - port: 80
      targetPort: 80
      nodePort: 30080
      protocol: TCP
      name: http
  selector:
    app: php-app

🚀 六、部署流程

1. 构建并推送镜像

# 构建 PHP-FPM
docker build -f docker/php-fpm.Dockerfile -t your-registry/php-fpm:8.1 .
docker push your-registry/php-fpm:8.1

# 构建 Nginx
docker build -f docker/nginx.Dockerfile -t your-registry/nginx-php:alpine .
docker push your-registry/nginx-php:alpine

🔁 替换 your-registry 为你的镜像仓库地址


2. 部署 Nacos

kubectl apply -f k8s/nacos-deploy.yaml

等待 Pod Running:

kubectl get pods -n middleware -l app=nacos

3. 部署 PHP 应用

kubectl apply -f k8s/configmap-fallback.yaml
kubectl apply -f k8s/php-deploy.yaml

4. 访问服务

浏览器访问:

http://<任意K8s节点IP>:30080

你应该看到 PHP 输出的配置信息,来源为 Nacos。


✅ 七、验证功能

功能 验证方式
Nacos 配置 修改 Nacos 中 php-app-prod.yaml,刷新页面看是否生效
滚动更新 kubectl set image deploy/php-app php-fpm=your-registry/php-fpm:8.2,观察是否不中断
平滑下线 删除 Pod,观察 preStop 是否执行,Nacos 是否不再注册
降级机制 停止 Nacos,重启 Pod,看是否使用 fallback 配置

🔐 八、安全建议

  • Nacos 启用权限认证
  • PHP 镜像使用非 root 用户
  • K8s 配置 NetworkPolicy 限制访问
  • 敏感配置加密(Nacos 支持 AES)

📎 附件:常用命令

# 查看日志
kubectl logs -l app=php-app -c nginx
kubectl logs -l app=php-app -c php-fpm

# 查看服务
kubectl get svc php-app

# 滚动重启
kubectl rollout restart deploy/php-app

# 进入容器
kubectl exec -it deploy/php-app -c nginx -- sh

现在你已经拥有了一个完整、可生产、可维护的 PHP + Nacos + K8s 部署方案!

如果你需要我提供:

  • ✅ GitHub 仓库模板
  • ✅ CI/CD 流水线(GitLab CI / GitHub Actions)
  • ✅ Prometheus 监控指标
  • ✅ 自动化脚本一键部署

欢迎继续提问!我可以为你定制企业级交付方案。

更多推荐