Next js production build is not finding environment variables when deployed via kubernetes

6/16/2021

I have a next js app that I am trying to deploy to a kubernetes cluster as a deployment. Parts of the application contain axios http requests that reference an environment variable containing the value of a backend service.

If I am running locally, everything works fine, here is what I have in my .env.local file:

NEXT_PUBLIC_BACKEND_URL=http://localhost:8080

Anywhere in the app, I can successfully access this variable with process.env.NEXT_PUBLIC_BACKEND_URL.

When I create a kubernetes deployment, I try to inject that same env variable via a configMap and the variable shows as undefined.

deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  creationTimestamp: null
  labels:
    app: my-site-frontend
  name: my-site-frontend
spec:
  replicas: 1
  selector:
    matchLabels:
      app: my-site-frontend
  strategy: {}
  template:
    metadata:
      creationTimestamp: null
      labels:
        app: my-site-frontend
    spec:
      containers:
      - image: my-site:0.1
        name: my-site
        resources: {}
        envFrom:
        - configMapRef:
            name: my-site-frontend
      imagePullSecrets:
      - name: dockerhub

configMap.yaml

apiVersion: v1
kind: ConfigMap
metadata:
  name: my-site-frontend
data:
  NEXT_PUBLIC_BACKEND_URL: backend_service

When I run the deployment and expose the application via a nodePort, I see these environment variables as undefined in my browser console. All api calls to my backend_service (ClusterIP) fail as you can imagine.

I can see the env variable is present when I exec into the running pod.

my-mac:manifests andy$ k get pods

NAME                                READY   STATUS    RESTARTS   AGE
my-site-frontend-77fb459dbf-d996n   1/1     Running   0          25m

---

my-mac:manifests andy$ k exec -it my-site-frontend-77fb459dbf-d996n -- sh

---

/app $ env | grep NEXT_PUBLIC

NEXT_PUBLIC_BACKEND_URL=backend_service

Any idea as to why the build process for my app does not account for this variable?

Thanks!

-- Andy
environment-variables
kubernetes
next.js

1 Answer

6/17/2021

Make sure kubernetes part did the job right

First what's needed to check if environment actually get to the pod. Your option works, however there are cases when kubectl exec -it pod_name -- sh / bash creates a different session and all configmaps can be reloaded again.

So let's check if it works right after pod is created and environment is presented.

I created a deployment with your base, put nginx image and extended spec part with:

command: ["/bin/bash", "-c"]
args: ["env | grep BACKEND_URL ; nginx -g \"daemon off;\""]

Right after pod started, got logs and confirmed environment is presented:

kubectl logs my-site-frontend-yyyyyyyy-xxxxx -n name_space | grep BACKEND
NEXT_PUBLIC_BACKEND_URL=SERVICE_URL:8000

Why browser doesn't show environment variables

This is part is more tricky. Based on some research on next.js, variables should be set before project building (more details here):

The value will be inlined into JavaScript sent to the browser because of the NEXTPUBLIC prefix. This inlining occurs at build time, so your various NEXTPUBLIC envs need to be set when the project is built.

You can also see a good example of using environment variables from next.js github project. You can try Open in StackBlitz option, very convenient and transparent.

At this point you may want to introduce DNS names since IPs can be changed and also different URL paths for front and back ends (depending on the application, below is an example of react app)

Kubernetes ingress

If you decide to use DNS, then you may run into necessity to route the traffic.

Short note what ingress is:

An API object that manages external access to the services in a cluster, typically HTTP.

Ingress may provide load balancing, SSL termination and name-based virtual hosting.

Why this is needed. Once you have DNS endpoint, frontend and backend should be separated and have the same domain name to avoid any CORS policies and etc (this is possible to resolve of course, here's more for testing and developing on a local cluster).

This is a good case for solving issues with react application with python backend. Since next.js is a an open-source React front-end development web framework, it should be useful.

In this case, there's a frontend which is located on / and has service on 3000 port and backend which located on /backend (please see deployment with example). Then below is how to setup /etc/hosts, test it and have the deployed app work.

Useful links:

-- moonkotte
Source: StackOverflow