You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Kubernetes中Nginx容器无法访问PHP-FPM Laravel容器问题排查

问题描述

我在Kubernetes中部署了Nginx和运行Laravel的PHP-FPM两个Deployment,但Nginx的请求无法到达PHP-FPM容器,返回404错误,Nginx访问日志如下:

172.18.0.1 - - [18/Jul/2022:16:51:10 +0000] "GET / HTTP/1.1" 404 555 "-" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Safari/537.36"

部署文件

apiVersion: v1
kind: ConfigMap
metadata:
  name: web-server-config
  namespace: dev-api
data:
  nginx.conf: |
    server {
        listen 80;
        index index.php index.html;
        error_log  /var/log/nginx/error.log;
        access_log /var/log/nginx/access.log;
        root /var/www/html/public;

        location ~ \.php$ {
            try_files $uri =404;
            fastcgi_split_path_info ^(.+\.php)(/.+)$;

            fastcgi_pass api-web-svc:9000;
            fastcgi_index index.php;
            include fastcgi_params;
            fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
            fastcgi_param PATH_INFO $fastcgi_path_info;
        }

        location / {
            try_files $uri $uri/ /index.php?$query_string;
                gzip_static on;
        }
    }
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: php-config
  namespace: dev-api
data:
  laravel.ini: |
    upload_max_filesize: 80M
    post_max_size: 80M
---
apiVersion: v1
kind: Secret
metadata:
  name: api-web-secret
  namespace: dev-api
type: Opaque
data:
 ...
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: api-web
  namespace: dev-api
spec:
  selector:
    matchLabels:
      app: api-web
  replicas: 1
  template:
    metadata:
      labels:
        app: api-web
    spec:
      containers:
      - name: api-web
        image: XXX.dkr.ecr.us-east-1.amazonaws.com/api-web:0.9.4-alpha
        volumeMounts:
         - name: php-config
           mountPath: /usr/local/etc/php/conf.d/laravel.ini
         - name: env-config
           mountPath: /var/www/html/.env
        ports:
        - containerPort: 9000
      volumes:
        - name: php-config
          configMap:
            name: php-config
        - name: env-config
          secret:
            secretName: api-web-secret
      imagePullSecrets:
      - name: regcred  
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  namespace: dev-api
spec:
  selector:
    matchLabels:
      app: nginx
  replicas: 1
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:alpine
        volumeMounts:
         - name: web-server-config
           mountPath: /etc/nginx/conf.d/
        ports:
        - containerPort: 80
      volumes:
        - name: web-server-config
          configMap:
            name: web-server-config 
---
apiVersion: v1
kind: Service
metadata:
  name:  web-server-svc
  namespace: dev-api
spec:
  type: NodePort
  selector:
    app:  nginx
  ports:
  - protocol: TCP
    port:  80
    targetPort:  80
    nodePort: 32420
---
apiVersion: v1
kind: Service
metadata:
  name:  api-web-svc
  namespace: dev-api
  labels:
    app: api-web
spec:
  type: ClusterIP
  selector:
    app:  api-web
  ports:
  - protocol: TCP
    port:  9000

容器日志

Nginx容器日志

k logs deployment/nginx-deployment  -n dev-api
/docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration
/docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/
/docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh
10-listen-on-ipv6-by-default.sh: info: /etc/nginx/conf.d/default.conf is not a file or does not exist
/docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh
/docker-entrypoint.sh: Launching /docker-entrypoint.d/30-tune-worker-processes.sh
/docker-entrypoint.sh: Configuration complete; ready for start up
2022/07/18 16:18:50 [notice] 1#1: using the "epoll" event method
2022/07/18 16:18:50 [notice] 1#1: nginx/1.21.6
2022/07/18 16:18:50 [notice] 1#1: built by gcc 10.3.1 20211027 (Alpine 10.3.1_git20211027) 
2022/07/18 16:18:50 [notice] 1#1: OS: Linux 5.4.0-109-generic
2022/07/18 16:18:50 [notice] 1#1: getrlimit(RLIMIT_NOFILE): 1048576:1048576
2022/07/18 16:18:50 [notice] 1#1: start worker processes
2022/07/18 16:18:50 [notice] 1#1: start worker process 21
2022/07/18 16:18:50 [notice] 1#1: start worker process 22
2022/07/18 16:18:50 [notice] 1#1: start worker process 23
2022/07/18 16:18:50 [notice] 1#1: start worker process 24
2022/07/18 16:18:50 [notice] 1#1: start worker process 25
2022/07/18 16:18:50 [notice] 1#1: start worker process 26
2022/07/18 16:18:50 [notice] 1#1: start worker process 27
2022/07/18 16:18:50 [notice] 1#1: start worker process 28

PHP-FPM容器日志

k logs deployment/api-web -n dev-api
[18-Jul-2022 16:18:51] NOTICE: [pool www] 'user' directive is ignored when FPM is not running as root
[18-Jul-2022 16:18:51] NOTICE: [pool www] 'user' directive is ignored when FPM is not running as root
[18-Jul-2022 16:18:51] NOTICE: [pool www] 'group' directive is ignored when FPM is not running as root
[18-Jul-2022 16:18:51] NOTICE: [pool www] 'group' directive is ignored when FPM is not running as root
[18-Jul-2022 16:18:51] NOTICE: fpm is running, pid 1
[18-Jul-2022 16:18:51] NOTICE: ready to handle connections

PHP-FPM镜像Dockerfile

FROM php:7.2-fpm

# Copy composer.lock and composer.json
COPY composer.lock composer.json /var/www/html/

# Set working directory
WORKDIR /var/www/html

# Install dependencies
RUN apt-get update && apt-get install -y \
    build-essential \
    libpng-dev \
    libjpeg62-turbo-dev \
    libfreetype6-dev \
    locales \
    zip \
    jpegoptim optipng pngquant gifsicle \
    vim \
    unzip \
    git \
    curl \
    nodejs \
    npm

# Clear cache
RUN apt-get clean && rm -rf /var/lib/apt/lists/*

# Install extensions
RUN docker-php-ext-install pdo_mysql mbstring zip exif pcntl
RUN docker-php-ext-configure gd --with-gd --with-freetype-dir=/usr/include/ --with-jpeg-dir=/usr/include/ --with-png-dir=/usr/include/
RUN docker-php-ext-install gd

# Install composer
RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer

# Add user for laravel application
RUN groupadd -g 1000 www
RUN useradd -u 1000 -ms /bin/bash -g www www

# Copy existing application directory contents
COPY . /var/www/html/

# Copy existing application directory permissions
COPY --chown=www:www . /var/www/html/

# Change current user to www
USER www

## Run composer dependencies
RUN composer update
RUN composer install

# Expose port 9000 and start php-fpm server
EXPOSE 9000
CMD ["php-fpm"]

该镜像在docker-compose环境下可正常运行,但在Kubernetes中出现上述问题。


问题原因与解决方案

核心原因

Nginx容器中没有Laravel应用的代码文件:

  • PHP-FPM容器通过Dockerfile构建时已经把Laravel代码复制到了/var/www/html目录
  • 但Nginx容器使用的是纯净的nginx:alpine镜像,没有挂载或复制任何Laravel代码,导致Nginx配置中指定的root /var/www/html/public目录是空的

当用户访问/时,Nginx的try_files规则会尝试查找/var/www/html/public/index.php,但该文件在Nginx容器中不存在,因此直接返回404,请求根本没有转发到PHP-FPM容器。

次要问题修正

  1. PHP配置文件格式错误:ConfigMap中的laravel.ini使用了冒号:, 但PHP的ini文件语法要求用等号=,否则配置不生效,修改为:

    upload_max_filesize = 80M
    post_max_size = 80M
    
  2. Nginx FastCGI路径验证逻辑:原配置中try_files $uri =404会让Nginx先检查自身容器内的文件是否存在,建议移除该规则,让PHP-FPM验证文件是否存在:

    location ~ \.php$ {
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass api-web-svc:9000;
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param PATH_INFO $fastcgi_path_info;
    }
    

核心解决方案:让Nginx获取Laravel代码

方式一:构建包含Laravel代码的Nginx镜像

基于现有的PHP-FPM镜像,复制Laravel的public目录到Nginx镜像中:

FROM nginx:alpine

# 从PHP-FPM镜像中复制Laravel静态文件
COPY --from=XXX.dkr.ecr.us-east-1.amazonaws.com/api-web:0.9.4-alpha /var/www/html/public /var/www/html/public

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

方式二:用Init容器同步代码到共享Volume

在Nginx的Deployment中添加Init容器,从PHP-FPM镜像复制代码到EmptyDir,再让Nginx挂载该Volume:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  namespace: dev-api
spec:
  selector:
    matchLabels:
      app: nginx
  replicas: 1
  template:
    metadata:
      labels:
        app: nginx
    spec:
      initContainers:
      - name: copy-laravel-files
        image: XXX.dkr.ecr.us-east-1.amazonaws.com/api-web:0.9.4-alpha
        command: ["sh", "-c", "cp -r /var/www/html/public /shared/public"]
        volumeMounts:
        - name: shared-files
          mountPath: /shared
      containers:
      - name: nginx
        image: nginx:alpine
        volumeMounts:
        - name: web-server-config
          mountPath: /etc/nginx/conf.d/
        - name: shared-files
          mountPath: /var/www/html/public
          subPath: public
        ports:
        - containerPort: 80
      volumes:
        - name: web-server-config
          configMap:
            name: web-server-config 
        - name: shared-files
          emptyDir: {}

方式三:使用PersistentVolume共享代码

创建PersistentVolumeClaim,让PHP-FPM和Nginx容器都挂载该PVC,确保两者访问相同的代码目录(适合生产环境,需提前将代码同步到PVC中)。

验证步骤

  1. 应用修改后的配置文件
  2. 检查Nginx容器中是否存在Laravel静态文件:
    kubectl exec -it deployment/nginx-deployment -n dev-api -- ls /var/www/html/public
    
  3. 重新访问服务,确认请求能正常转发到PHP-FPM并返回响应

内容的提问来源于stack exchange,提问作者reayn3

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 04:39:20