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

Kubernetes仅启动后端服务,前端报Nginx 502错误求助

React+Node.js K8s部署前端无法显示问题排查与修复

问题描述

React前端+Node.js后端应用,Kubernetes部署后后端可正常访问,但前端无法显示,怀疑端口配置问题,对Docker和K8s不熟悉,无法定位根源。


现有配置文件

前端Dockerfile

FROM node:14.14.0-alpine as builder
WORKDIR /app
COPY ./package.json ./
RUN npm i
COPY . .
RUN npm run build
FROM nginx
COPY ./nginx/default.conf /etc/nginx/conf.d/default.conf
COPY --from=builder /app/build /usr/share/nginx/html
COPY sw_PublicKey.crt /etc/ssl/sw_certificatePKCS7.crt
COPY private_key.pem /etc/ssl/private_key.pem
EXPOSE 443

后端Dockerfile

FROM node:14.14.0-alpine
WORKDIR /app
COPY ./package.json ./
RUN npm i
COPY . .
EXPOSE 4000
CMD ["npm", "run", "start"]

NGINX主配置文件

server{
  listen 443 ssl;
  #listen 10.10.100.66:3000;
  #Type your domain name below
  server_name spesen.sxdes.de;

  ssl_certificate /etc/ssl/sw_certificatePKCS7.crt;
  ssl_certificate_key /etc/ssl/private_key.pem;

  ssl_session_timeout 1d;
  ssl_session_cache shared:SSL:50m;
  ssl_session_tickets off;

  ssl_protocols TLSv1.2;

# Only use ciphersuites that are considered modern and secure by Mozilla
  ssl_ciphers 'ECDHE-ECDSA...';

  ssl_prefer_server_ciphers on;

  location / {
        root /usr/share/nginx/html;
        index index.html index.htm;
        try_files $uri $uri/ /index.html;
    }
}

NGINX Default.conf

upstream client {
    server client:3000;
}

upstream api {
    server api:4000;
}

server {
    listen 443;

    location / {
        proxy_pass http://client;
    }

    location /sockjs-node {
        proxy_pass http://client;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "Upgrade";
    }

    location /api {
        rewrite /api/(.*) /$1 break;
        proxy_pass http://api;
    }
}

Client ClusterIP Service

apiVersion: v1
kind: Service
metadata:
  name: client-cluster-ip-service
spec:
  type: ClusterIP
  selector:
    component: web
  ports:
    - port: 3000
      targetPort: 3000

Client Deployment

apiVersion: apps/v1
kind: Deployment
metadata:
  name: client-deployment
spec:
  replicas: 1
  selector:
    matchLabels:
      component: web
  template:
    metadata:
      labels:
        component: web
    spec:
      containers:
        - name: client
          image: ss/spesen-c:latest
          ports:
            - containerPort: 3000
          env:
            - name: REACT_APP_GOOGLE_MAPS_API_KEY
              value: "..."
      imagePullSecrets:
        - name: secret/...

Ingress Service

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: ingress-service
  annotations:
    kubernetes.io/ingress.class: "nginx"
    nginx.ingress.kubernetes.io/use-regex: "true"
    nginx.ingress.kubernetes.io/rewrite-target: /$1
spec:
  rules:
    - http:
        paths:
          - path: /?(.*)
            pathType: Prefix
            backend:
              service:
                name: client-cluster-ip-service
                port:
                  number: 3000
          - path: /api/?(.*)
            pathType: Prefix
            backend:
              service:
                name: server-cluster-ip-service
                port:
                  number: 4000

Server ClusterIP Service

apiVersion: v1
kind: Service
metadata:
  name: server-cluster-ip-service
spec:
  type: ClusterIP
  selector:
    component: web
  ports:
    - port: 4000
      targetPort: 4000

Server Deployment

apiVersion: apps/v1
kind: Deployment
metadata:
  name: server-deployment
spec:
  replicas: 1
  selector:
    matchLabels:
      component: web
  template:
    metadata:
      labels:
        component: web
    spec:
      containers:
        - name: server
          image: schorerwolfae/spesen-server
          ports:
            - containerPort: 4000
          env:
            - name: ACCESS_TOKEN_SECRET
              value: "..."
            - name: REFRESH_TOKEN_SECRET
              value: "..."
            - name: DATABASE_URI
              value: "..."
            - name: AD_PASSWORD
              value: "..."
      imagePullSecrets:
        - name: secret/...

核心问题修复方案

1. 端口配置不匹配

前端Dockerfile暴露443端口,但Deployment和Service配置的是3000端口,完全不匹配。修改如下:

  • 调整client-deployment的containerPort为443:
    ports:
      - containerPort: 443
    
  • 调整client-cluster-ip-service的targetPort为443:
    ports:
      - port: 3000
        targetPort: 443
    

2. NGINX配置冲突与冗余

前端容器内同时加载两个NGINX配置,且配置了反向代理,这在K8s环境中完全多余。简化配置:

  • 修改前端Dockerfile,去掉SSL配置,让NGINX监听80端口:
    FROM node:14.14.0-alpine as builder
    WORKDIR /app
    COPY ./package.json ./
    RUN npm i
    COPY . .
    RUN npm run build
    FROM nginx:alpine
    COPY --from=builder /app/build /usr/share/nginx/html
    COPY ./nginx/spa.conf /etc/nginx/conf.d/default.conf
    EXPOSE 80
    
  • 新建spa.conf,仅负责静态文件服务:
    server {
      listen 80;
      root /usr/share/nginx/html;
      index index.html;
      try_files $uri $uri/ /index.html;
    }
    
  • 同步调整Deployment和Service的端口为80(可选,更符合常规配置)。

3. Service选择器冲突

Server和Client的Pod标签都是component: web,导致Server Service会把流量转发到Client Pod,修改如下:

  • 调整server-deployment的Pod标签:
    template:
      metadata:
        labels:
          component: api
    
  • 调整server-cluster-ip-service的选择器:
    selector:
      component: api
    

4. Ingress路由优化

针对React单页应用调整Ingress规则,避免路由异常:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: ingress-service
  annotations:
    kubernetes.io/ingress.class: "nginx"
    nginx.ingress.kubernetes.io/use-regex: "true"
    nginx.ingress.kubernetes.io/rewrite-target: /$1
    # 适配SPA路由的额外配置
    nginx.ingress.kubernetes.io/configuration-snippet: |
      rewrite ^(/api)$ $1/ permanent;
spec:
  rules:
    - http:
        paths:
          - path: /(.*)
            pathType: Prefix
            backend:
              service:
                name: client-cluster-ip-service
                port:
                  number: 3000
          - path: /api/(.*)
            pathType: Prefix
            backend:
              service:
                name: server-cluster-ip-service
                port:
                  number: 4000

(若需要SSL,建议在Ingress层配置证书,而非前端容器内)


验证步骤

  1. 应用修改后的配置:kubectl apply -f <配置文件路径>
  2. 检查Client Pod状态:kubectl get pods
  3. 查看Client容器日志:kubectl logs <client-pod-name>
  4. 本地端口转发测试:kubectl port-forward service/client-cluster-ip-service 3000:3000,访问localhost:3000验证前端是否正常显示

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 11:34:56