无法访问 kubernetes/terraform 中的 NEXTjs env

Jas*_*ane 6 environment-variables docker kubernetes next.js

这个问题之前已经被问过,在过去的两天里我尝试了很多例子来尝试和配置,但没有成功,所以我发布了我的环境以寻求帮助。

问题
Nextjs 使用 Terraform 部署到 kubernetes 后环境变量全部未定义

预期结果

staging: NEXT_PUBLIC_APIROOT=https://apis-staging.mywebsite.com
production: NEXT_PUBLIC_APIROOT=https://apis.mywebsite.com
Run Code Online (Sandbox Code Playgroud)

秘密存储在 github actions 中。我有一个 terraform 设置,可将我的应用程序部署到我的暂存和生产 klusters,下面是一个片段:

env:
  ENV: staging
  PROJECT_ID: ${{ secrets.GKE_PROJECT_STAG }}
  GOOGLE_CREDENTIALS: ${{ secrets.GOOGLE_CREDENTIALS_STAG }}
  GKE_SA_KEY: ${{ secrets.GKE_SA_KEY_STAG }}
  NEXT_PUBLIC_APIROOT: ${{ secrets.NEXT_PUBLIC_APIROOT_STAGING }}
Run Code Online (Sandbox Code Playgroud)

我还有一个额外的步骤来手动创建 .env 文件

    - name: env-file
      run: |
        touch .env.local
        echo NEXT_PUBLIC_APIROOT: ${{ secrets.NEXT_PUBLIC_APIROOT_STAGING }} >> .env.local
Run Code Online (Sandbox Code Playgroud)

Dockerfile

FROM node:16-alpine AS deps
RUN apk add --no-cache libc6-compat

WORKDIR /app
COPY package.json package-lock.json .npmrc ./
RUN npm ci

FROM node:16-alpine AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN npm run build

FROM node:16-alpine AS runner
WORKDIR /app

RUN addgroup -g 1001 -S nodejs
RUN adduser -S nextjs -u 1001

# You only need to copy next.config.js if you are NOT using the default configuration
COPY --from=builder /app/next.config.js ./
COPY --from=builder /app/public ./public
COPY --from=builder /app/package.json ./package.json

# Automatically leverage output traces to reduce image size
# https://nextjs.org/docs/advanced-features/output-file-tracing
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static

USER nextjs

EXPOSE 3000

ENV PORT 3000

CMD ["node", "server.js"]
Run Code Online (Sandbox Code Playgroud)

next.config.js

module.exports = withBundleAnalyzer({
    publicRuntimeConfig: {
        NEXT_PUBLIC_APIROOT: process.env.NEXT_PUBLIC_APIROOT,
    },
    output: 'standalone',
    webpack: (config, { dev, isServer }) => {
        if (dev && isServer) {
            const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin')
            config.plugins.push(
                new ForkTsCheckerWebpackPlugin({
                    eslint: {
                        files: './src/**/*.{ts,tsx,js,jsx}',
                    },
                })
            )
        }
        return config
    },
})
Run Code Online (Sandbox Code Playgroud)

有人对这个问题有经验吗?

vla*_*zam 2

首先我想说我绝不是 NextJS 的专家。因此,我尝试在以下假设下解决您的问题:

  • 该问题不一定与 NextJS 有关,因为它似乎与 Kubernetes 资源部署和管理有关
  • 利用默认next.config.js机制自动加载环境变量.env.local
  • 使用 GKE 集群使用相同的部署目标(区域us-central1-c:)

我的第一步是创建一个具有单个 API 端点的虚拟 NextJS 应用程序,该应用程序仅打印我在将工作负载部署到 Kubernetes 时尝试设置的环境变量之一。当谈到 Dockerfile 时,我使用了与您提供的完全相同的图像。请在下面找到我的虚拟应用程序中的相关文件:

页面/api/test.js

export default function handler(req, res) {
    res.status(200).json(process.env.NEXT_PUBLIC_APIROOT)
}
Run Code Online (Sandbox Code Playgroud)

next.config.js

const withBundleAnalyzer = require('@next/bundle-analyzer')({
    enabled: true,
});

module.exports = withBundleAnalyzer({
    publicRuntimeConfig: {
        NEXT_PUBLIC_APIROOT: process.env.NEXT_PUBLIC_APIROOT,
    },
    output: 'standalone'
})
Run Code Online (Sandbox Code Playgroud)

Dockerfile

FROM node:16-alpine AS deps
RUN apk add --no-cache libc6-compat

WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci

FROM node:16-alpine AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN npm run build

FROM node:16-alpine AS runner
WORKDIR /app

RUN addgroup -g 1001 -S nodejs
RUN adduser -S nextjs -u 1001

# You only need to copy next.config.js if you are NOT using the default configuration
COPY --from=builder /app/next.config.js ./
COPY --from=builder /app/public ./public
COPY --from=builder /app/package.json ./package.json

# Automatically leverage output traces to reduce image size
# https://nextjs.org/docs/advanced-features/output-file-tracing
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static

USER nextjs

EXPOSE 3000

ENV PORT 3000

CMD ["npm", "start"]
Run Code Online (Sandbox Code Playgroud)

我在 Dockerfile 中做了一个更改,即更新 CMD 条目,以便应用程序通过命令启动npm start

根据官方文档,NextJS 将尝试在应用程序根文件夹中查找.env.local并将这些环境变量加载到process.env.

因此,我使用 Kubernetes 资源创建了一个 YAML 文件,该文件将用于创建部署设置。

nextjs-app-setup.yaml

apiVersion: v1
kind: ConfigMap
metadata:
  name: nextjs-app-config
data:
  .env.local: |-
    NEXT_PUBLIC_APIROOT=hello_i_am_an_env_variable
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nextjs-app
  labels:
    app: nextjs-app
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nextjs-app
  template:
    metadata:
      labels:
        app: nextjs-app
    spec:
      containers:
      - name: nextjs-app
        image: public.ecr.aws/u4x8r8g3/nextjs-app:latest
        ports:
        - containerPort: 3000
        volumeMounts:
        - name: nextjs-app-config
          mountPath: "/app/.env.local"
          subPath: ".env.local"
          readOnly: true
      volumes:
      - name: nextjs-app-config
        configMap:
          name: nextjs-app-config
---
apiVersion: v1
kind: Service
metadata:
  name: nextjs-service
spec:
  selector:
    app: nextjs-app
  ports:
    - protocol: TCP
      port: 3000
      targetPort: 3000
Run Code Online (Sandbox Code Playgroud)

上述配置中发生了多种情况:

  • 定义一个 ConfigMap 资源,该资源将保存 NextJS 应用程序所需的所有必需环境变量。有一个条目.env.local将保存所有环境变量并将作为文件安装在应用程序 pod 中
  • 为 NextJS 应用程序定义部署资源。这里最重要的部分是volumesvolumeMounts块。在这里,我正在挂载路径.env.local上定义的 ConfigMap 中的条目/app/.env.local
  • 定义一个服务资源以便能够与 NextJS 应用程序交互

通过 kubectl 连接到 GKE 集群后,我通过kubectl apply -f nextjs-app-setup.yaml.

为了从本地工作站连接到该服务,我执行了kubectl port-forward service/nextjs-service 3000:3000. 然后我在浏览器中导航localhost:3000/api/test并可以看到我在 ConfigMap 中设置为输出的值。

免责声明:我知道您的设置可能涉及一些额外的组件,特别是在 CI/CD 和基础设施即代码方面,但我在这里的回答至少应该为您提供一种访问容器化 NextJS 工作负载中的环境变量的方法。如果您仍然获得undefined值,我的假设是,它很可能与您在 CI/CD 管道中配置它们的方式有关,但这将是一个与 NextJS 或 Kubernetes 无关的不同问题。