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容器。
次要问题修正
PHP配置文件格式错误:ConfigMap中的
laravel.ini使用了冒号:, 但PHP的ini文件语法要求用等号=,否则配置不生效,修改为:upload_max_filesize = 80M post_max_size = 80MNginx 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中)。
验证步骤
- 应用修改后的配置文件
- 检查Nginx容器中是否存在Laravel静态文件:
kubectl exec -it deployment/nginx-deployment -n dev-api -- ls /var/www/html/public - 重新访问服务,确认请求能正常转发到PHP-FPM并返回响应
内容的提问来源于stack exchange,提问作者reayn3
相关产品推荐
相关产品推荐

