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

Kubernetes部署NextJS时符号链接更新失败致应用崩溃求助

概述

在Kubernetes中部署了NextJS应用,希望以开发模式运行,实现文件更新时的即时热重载,重点是更新config文件夹中的JSON配置文件。已创建Docker容器,复制必要文件但排除配置文件,转而通过Kubernetes ConfigMap作为卷挂载到容器内。运行环境为Windows WSL2上的minikube。

问题

容器首次运行正常,但访问部分页面或修改ConfigMap中的值时,会出现类似如下错误(针对PlanModel.config.json等其他文件的错误逻辑类似):

> @ dev-base /usr/src/app
> next dev

▲ Next.js 14.2.3

- Local: http://localhost:3000

✓ Starting...
Attention: Next.js now collects completely anonymous telemetry regarding usage.
This information is used to shape Next.js' roadmap and prioritize features.
You can learn more, including how to opt-out
if you'd not like to participate in this anonymous program, by visiting the following URL:https://nextjs.org/telemetry

✓ Ready in 3s
○ Compiling /middleware ...
✓ Compiled /middleware in 2.3s (216 modules) ○ Compiling / ...
Browserslist: caniuse-lite is outdated. Please run:
npx update-browserslist-db@latest
Why you should do it regularly: https://github.com/browserslist/update-db#readme  
 ✓ Compiled / in 18.6s (4401 modules)
cookie is: undefined
GET / 200 in 19523ms
✓ Compiled in 1339ms (1847 modules)
cookie is: undefined
GET / 200 in 68ms
cookie is: undefined
GET / 200 in 46ms
cookie is: undefined
GET / 200 in 37ms
⨯ ./config/ai/..2024_09_30_15_42_23.830652425/actions.config.json
Module build failed: Error: ENOENT: no such file or directory, open '/usr/src/app/config/ai/..2024_09_30_15_42_23.830652425/actions.config.json'

Import trace for requested module:
./config/ai/..2024_09_30_15_42_23.830652425/actions.config.json
./lib/chat/actions.config.tsx
./lib/chat/actions.tsx
./app/(chat)/page.tsx

有时应用不会立即报错,但会停止热重载。两种情况下,进入容器shell手动验证过文件确实存在且内容正确。

可能原因

Kubernetes为ConfigMap中的文件创建了多层符号链接,结构如下:

actions.config.json -> ..data/actions.config.json -> ..2024_09_30_15_42_23.830652425/actions.config.json

Next.js开发模式下对符号链接的追踪存在问题,根源在于webpack的文件监听机制限制。目前考虑两个解决方向:一是采用不创建符号链接的Kubernetes方案(仍需支持配置文件的轻松更新),二是修复Next.js的符号链接追踪问题。

更多背景

目标是构建一个平台,允许用户通过修改JSON格式的配置文件自定义NextJS应用,这些配置文件被NextJS应用静态导入,决定应用的颜色、样式和行为。用户可通过编辑器完成两种操作:

  • 定制应用的生产版本:部署到生产环境
  • 定制应用的预览版本:编辑时自动刷新预览效果

为支持实时变更,选择直接以开发模式运行应用,而非基于现有应用创建变体版本。由于生产和预览版本都需要规模化运行,因此采用Kubernetes,并创建API动态生成两种版本的Kubernetes清单。

问题出在预览版本,以下是简化后的Kubernetes清单示例:

apiVersion: v1
kind: Namespace
metadata:
  labels:
    app_id: myId
    app_subdomain: testapp
  name: myId
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: app-environment
  namespace: myId
data:
  # App configuration
  APP_ID: myId

  # Postgres database, MongoDB database, etc env variables
---
apiVersion: v1
kind: ConfigMap
metadata:
  labels:
    app_id: myId
    app_subdomain: testapp
  name: app-config
  namespace: myId
data:
  theme.config.json: |
    CONTENT
---
apiVersion: v1
kind: ConfigMap
metadata:
  labels:
    app_id: myId
    app_subdomain: testapp
  name: app-config-ai
  namespace: myId
data:
  actions.config.json: |
    CONTENT
---
apiVersion: v1
kind: ConfigMap
metadata:
  labels:
    app_id: myId
    app_subdomain: testapp
  name: app-config-components
  namespace: myId
data:
  button-scroll-to-bottom.config.json: |
    CONTENT
  chat-history.config.json: |
    CONTENT
  chat-message-actions.config.json: |
    CONTENT
---
apiVersion: v1
kind: ConfigMap
metadata:
  labels:
    app_id: myId
    app_subdomain: testapp
  name: app-config-components-ui
  namespace: myId
data:
  sheet.config.json: |
    CONTENT
---
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app_id: myId
    app_subdomain: testapp
  name: app
  namespace: myId
spec:
  replicas: 1
  selector:
    matchLabels:
      app_id: myId
  template:
    metadata:
      labels:
        app_id: myId
        app_subdomain: testapp
    spec:
      containers:
        - name: nginx
          image: my-nginx:latest
          imagePullPolicy: Always
          ports:
            - containerPort: 80
        - name: app
          image: my-app-configurable:latest
          imagePullPolicy: Always
          envFrom:
            - configMapRef:
                name: app-environment
          ports:
            - containerPort: 3000
          volumeMounts: # /usr/src/app/ is the root directory of the app in the container
            - name: app-config
              mountPath: /usr/src/app/config
            - name: app-config-ai
              mountPath: /usr/src/app/config/ai
            - name: app-config-components
              mountPath: /usr/src/app/config/components
            - name: app-config-components-ui
              mountPath: /usr/src/app/config/components/ui
      volumes:
        - name: app-config
          configMap:
            name: app-config
        - name: app-config-ai
          configMap:
            name: app-config-ai
        - name: app-config-components
          configMap:
            name: app-config-components
        - name: app-config-components-ui
          configMap:
            name: app-config-components-ui
---
apiVersion: v1
kind: Service
metadata:
  labels:
    app_id: myId
    app_subdomain: testapp
  name: nginx-service
  namespace: myId
spec:
  ports:
    - port: 80
      protocol: TCP
      targetPort: 80
  selector:
    app_id: myId
---
apiVersion: v1
kind: Service
metadata:
  labels:
    app_id: myId
    app_subdomain: testapp
  name: app
  namespace: myId
spec:
  ports:
    - port: 3000
      protocol: TCP
      targetPort: 3000
  selector:
    app_id: myId
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  labels:
    app_id: myId
    app_subdomain: testapp
  name: nginx
  namespace: myId
spec:
  rules:
    - host: testapp.zshape.ai
      http:
        paths:
          - backend:
              service:
                name: nginx-service
                port:
                  number: 80
            path: /
            pathType: Prefix

NextJS应用中导入JSON文件的示例:

import rawConfig from '@/config/components/empty-screen.config.json'

interface ComponentConfig {
  [key: string]: any
  title?: string
  description?: string
  linkURL?: string
  linkLabel?: string
}

const { title, description, linkURL, linkLabel }: ComponentConfig = rawConfig

export const emptyScreenConfig = {
  title,
  description,
  linkURL,
  linkLabel
}

导出的emptyScreenConfig会被应用其他部分导入使用。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 15:55:05