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

Next.js部署Kubernetes遇静态资源404,求零停机配置方案

解决Next.js应用K8s部署后静态资源404+零停机部署的配置方案

一、先搞定静态资源404的问题

1. 检查Dockerfile的构建逻辑

你的Dockerfile必须完整复制Next.js构建生成的所有静态资源,不能只挑部分复制。正确的多阶段构建示例:

FROM node:18-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

FROM node:18-alpine AS runner
WORKDIR /app
ENV NODE_ENV production
COPY --from=builder /app/package*.json ./
RUN npm ci --only=production
# 必须完整复制.next目录,里面包含带哈希的静态资源
COPY --from=builder /app/.next ./.next
COPY --from=builder /app/public ./public
COPY --from=builder /app/next.config.js ./

EXPOSE 3000
CMD ["npm", "start"]

重点:.next/static下的哈希目录是构建时自动生成的,每个版本的哈希都不一样,必须完整复制整个.next目录,否则新Pod会找不到旧版本的静态资源,反之亦然。

2. 调整Ingress的路径转发规则

确保Ingress不会截断/_next/static/后面的哈希路径,比如用Nginx Ingress的话,配置要这样写:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: nextjs-app-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /$1
spec:
  rules:
  - host: your-domain.com
    http:
      paths:
      - path: /(.*)
        pathType: Prefix
        backend:
          service:
            name: nextjs-app-service
            port:
              number: 3000

如果用Traefik之类的其他Ingress控制器,核心是保证/_next/static/xxx/xxx.js这种完整路径能被正确转发到Pod,别被规则吃掉后面的哈希部分。

3. 确认Pod的文件访问权限

有时候Pod启动后没权限读取静态资源目录,导致404。可以给容器加SecurityContext配置:

# 加到Deployment的template.spec.containers下面
securityContext:
  runAsUser: 1000
  runAsGroup: 1000
  fsGroup: 1000

二、实现零停机部署的核心配置

1. 配置滚动更新策略

在Deployment里设置滚动更新的参数,保证更新过程中始终有可用的Pod:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nextjs-app-deployment
spec:
  replicas: 3
  strategy:
    rollingUpdate:
      maxSurge: 25%  # 每次最多新增1个Pod(按3副本算)
      maxUnavailable: 0  # 更新时绝不允许有Pod不可用,确保零停机
    type: RollingUpdate

2. 必须加就绪探针(Readiness Probe)

这个是零停机的关键,只有当Pod完全启动、能正常返回静态资源时,才把它加入服务的端点列表,避免把请求打到还没准备好的Pod上:

# 加到Deployment的template.spec.containers下面
readinessProbe:
  httpGet:
    # 用public目录里的固定静态资源当探测路径,比根路径更可靠
    path: /your-fixed-static-file.png
    port: 3000
  initialDelaySeconds: 10  # 容器启动后等10秒再开始探测
  periodSeconds: 5  # 每5秒测一次
  failureThreshold: 3  # 连续3次失败就标记为未就绪

也可以用/_next/static/下的某个固定资源,只要是每个版本都存在的就行。

3. 可选:加PreStop钩子

让Pod在被终止前等10秒,处理完正在进行的请求再 shutdown,避免中途断开:

# 加到Deployment的template.spec.containers下面
lifecycle:
  preStop:
    exec:
      command: ["sleep", "10"]

三、额外优化点

  • 如果应用有用户会话,可以给Service加sessionAffinity: ClientIP,让同一用户的请求始终打到同一个Pod,避免跨版本的静态资源问题。
  • 要是用了CDN,把/_next/static/路径的资源缓存起来,因为哈希路径是唯一的,缓存时间可以设长一点,能减少Pod切换时的资源请求压力。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 21:15:34