Making a React application with reverse proxy and environment-aware at Kubernetes deployment

Yulong Song
3 min readJul 8, 2019

--

A little introduction of what I would like to achieve. I have been working on the frontend for quite some time I upgrade all my React dependencies to the latest stable versions(it’s all about hooks!) and using Webpack to optimize my build to the maximum (tree-shaking, compression, chunk splitting …etc) now I have two problems:

  1. How to serve my minimized and compressed js, css bundles as a micro service?
  2. How to switch my gateway endpoint from Development environment to Staging/Production environment(For example, in the development environment all the api calls should go to https://dev.gateway.io and in production environment it should go to https://gateway.io) without rebuilding the whole project?

In the next section I will explain how I tackled these two problems.

How to serve my minimized and compressed js, css bundles as a micro service?

I’m using compression-webpack-plugin as a result, I have my bundles like app.bundle.83b334b1c8ef06b0b956.js.gz app.83b334b1c8ef06b0b956.css.gz

I need a static server to host these bundles and also be able to serve compressed files so who will be the best candidate? it doesn’t require much research to finally come to the conclusion: Nginx.

Here is my Dockerfile

# Node image
FROM node:10 as builder
# set working directory
RUN mkdir /usr/src/app
WORKDIR /usr/src/app
# copy source code
COPY . /usr/src/app/
# install app dependencies
RUN npm install
# run production build
RUN npm run production
# Nginx
FROM nginx:1.15
RUN rm -rf /etc/nginx/conf.d
COPY conf /etc/nginx
COPY — from=builder /usr/src/app/app-build /usr/share/nginx/html
EXPOSE 80
CMD [“nginx”, “-g”, “daemon off;”]

Here is my Nginx conf.d, I enabled the gzip with gzip_static on;

server {
listen 80;
location / {
gzip_static on;
root /usr/share/nginx/html;
index index.html index.htm;
try_files $uri $uri/ /index.html;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}

Now you can run the image on your local to verify the result. You website should be waiting for you at http://localhost

How to switch my gateway endpoint from Development environment to Staging/Production environment?

Actually this can be more general for injecting any environment variables on the frontend. The way I did it is through the index.html with a small env.js

my env.js looks like this

window.DEV_ENDPOINT = 'https://dev.gateway.io';

my index.html

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge, chrome=1" />
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no" />
</head>
<body>
<div id="root">Loading...</div>
<!-- inject the env -->
<script type="text/javascript" src="/config/env.js"></script>
</body>
</html>

A place where I use the DEV_ENDPOINT

const instance = axios.create({
baseURL: window.DEV_ENDPOINT || CommonConstants.BASE_URL
});

BASE_URL is actually the production gateway endpoint as a result, if DEV_ENDPOINT is not presented it will fall back to the production endpoint. You can define anything in this env.js Now we finished the dev setup we need to wrap everything into the kubernetes.

Kubernetes provides configmap to achieve something like this. Here is the configmap yaml

apiVersion: v1
kind: ConfigMap
metadata:
name: frontend-dev-configmap
labels:
name: frontend-dev-configmap
data:
endpoint-config: |
window.DEV_ENDPOINT = 'https://dev.gateway.io';

and here is the deployment yaml

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: frontend
spec:
replicas: 2
strategy:
type: RollingUpdate
template:
metadata:
labels:
app: frontend
spec:
containers:
- name: frontend-container
image: frontend:latest
imagePullPolicy: Always
ports:
- containerPort: 80
name: http
readinessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 5
periodSeconds: 3
successThreshold: 1
volumeMounts:
- name: env-config
mountPath: /usr/share/nginx/html/config
volumes:
- name: env-config
configMap:
name: frontend-dev-configmap
items:
- key: endpoint-config
path: env.js

Now kubernetes will create the env.js at /usr/share/nginx/html/config before starting the frontend container.

That’s it!

--

--