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!
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: