How to override env variables in React JS application with Kuberenetes? - reactjs

I've a simle React JS application and it's using a environment variable(REACT_APP_BACKEND_SERVER_URL) defined in .env file. Now I'm trying to deploy this application to minikube using Kubernetes.
This is my deployment file:
apiVersion: apps/v1
kind: Deployment
metadata:
name: test-ui
spec:
replicas: 1
selector:
matchLabels:
app: test-ui
template:
metadata:
name: test-ui-pod
labels:
app: test-ui
spec:
containers:
- name: test-ui
image: test-ui:1.0.2
ports:
- containerPort: 80
env:
- name: "REACT_APP_BACKEND_SERVER_URL"
value: "http://127.0.0.1:59058"
When I run the application, it's working but REACT_APP_BACKEND_SERVER_URL is giving the value which I defined in .env file. Not the one I'm overriding. Can someone help me with this please? How to override the env variable using Kubernetes deployment?

After starting the app with your deployment YAML and checking for the environment variables I see the environment variables for that environment variable.
REACT_APP_BACKEND_SERVER_URL=http://127.0.0.1:59058
you can check that by doing an kubectl exec -it <pod-name> -- sh and running env command.
So you can see that REACT_APP_BACKEND_SERVER_URL is there in the environment variables. It's available for your application to use. I suspect that you may need to understand better from the React app side on how to use the .env file.

Related

Kubernetes environment variables read in static react project

Is is possible to read environment variables, defined in containers, in a react-app which is created using create-react-app?
eg
Deployment.yml:
apiVersion: apps/v1
kind: Deployment
..
spec:
template:
spec:
containers:
- name: my-container
env:
- name: REACT_APP_MY_ENV_VARIABLE
value: abc
Dockerfile:
..
CMD PORT=8080 npm start
Package.json:
"start":"react-scripts start"
"build":"react-scripts build"
In App.js:
process.env.REACT_APP_MY_ENV_VARIABLE returns undefined
You can export those variables in your Dockerfile by doing:
ARG REACT_APP_MY_ENV_VARIABLE
ENV REACT_APP_MY_ENV_VARIABLE=${REACT_APP_MY_ENV_VARIABLE}
..
CMD PORT=8080 npm start

Why can I not open a React web app in a browser through an ingress when deploying it in a Kubernetes cluster

I have a very simple React web app (using Argon Dashboard Pro Template) deployed in a Kubernetes cluster. The Docker image of it works locally as well as in the cluster when exposing it via nodeport. But exposing it via NGINX ingress doesn't work, although the ingress itself is tested for other services and applications which expose REST endpoints. The content of the web page is not built correctly, because some js files are not found, although this is the case when they are exposed via nodeport.
Kubernetes Deployment:
apiVersion: apps/v1
kind: Deployment
metadata:
name: react-deployment
namespace: support
labels:
app: react
stage: dev
spec:
replicas: 1
template:
metadata:
labels:
app: react
spec:
containers:
- name: react
image: fmaus/react-test:argon
ports:
- containerPort: 3000
name: react-port
imagePullPolicy: Always
restartPolicy: Always
selector:
matchLabels:
app: react
Kubernetes Ingress
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: react-ingress
namespace: support
annotations:
nginx.ingress.kubernetes.io/use-regex: "true"
nginx.ingress.kubernetes.io/rewrite-target: /$2
nginx.ingress.kubernetes.io/configuration-snippet: |
proxy_set_header Accept-Encoding "";
more_set_headers "Content-Type: text/javascript; charset=UTF-8";
nginx.ingress.kubernetes.io/ssl-redirect: "false"
spec:
ingressClassName: nginx
rules:
- http:
paths:
- path: /test(/|$)(.*)
pathType: Prefix
backend:
service:
name: react-service
port:
number: 3000
Kubernetes Service:
apiVersion: v1
kind: Service
metadata:
name: "react-service"
namespace: support
spec:
selector:
app: "react"
ports:
- port: 3000
type: ClusterIP
This Code can also be found in my GitHub Repository: https://github.com/fmaus/react-kubernetes-test
To reproduce the problem, just apply these Kubernetes resources to a cluster and try to reach the web app through a browser via ingress (http://host/subpath). I have the resources deployed here: http://c105-164.cloud.gwdg.de:31600/test
The error messages can be visited in the console of the browser (F12 when using Firefox):
Loading failed for the <script> with source “http://c105-164.cloud.gwdg.de:31600/static/js/bundle.js”. subpath:61:1
Loading failed for the <script> with source “http://c105-164.cloud.gwdg.de:31600/static/js/vendors~main.chunk.js”. subpath:61:1
Loading failed for the <script> with source “http://c105-164.cloud.gwdg.de:31600/static/js/main.chunk.js”.
I use Mozilla Firefox and the following NGINX ingress controller: https://kubernetes.github.io/ingress-nginx/
I think you have two issues in place here:
You set the content type to javascript, so the html is not interpreted correctly by the browser. F.e. http://c105-164.cloud.gwdg.de:31600/test/index.html is shown as source
You need to make sure the resources are referenced including the sub path, or a 404 will result
For example
<script src="/static/js/bundle.js"></script><script src="/static/js/vendors~main.chunk.js"></script><script src="/static/js/main.chunk.js"></script></body>
Needs to load the bundle from /subpath/static/js/bundle.js since it is an absolute link.

kubectl secrets not accessible in React app Pods

I've tried to avoid, but really haven't had the need, to set specific env vars for a React FE. But I'm working on social authentication, with Azure AD specifically, and now I do have a use case for it.
I acknowledge the AAD_TENANT_ID and AAD_CLIENT_ID aren't exactly "secret" or sensitive information and will be compiled in the JS, but I'm trying to do this for a few reasons:
I can more easily manage dev and prod keys from a Key Vault...
Having environment independent code (i.e., process.env.AAD_TENANT_ID will work whether it is dev or prod).
But it doesn't work.
The issue I'm running into is that the env vars are not accessible at process.env despite having the following:
apiVersion: apps/v1
kind: Deployment
metadata:
name: admin-v2-deployment-dev
namespace: dev
spec:
replicas: 1
revisionHistoryLimit: 5
selector:
matchLabels:
component: admin-v2
template:
metadata:
labels:
component: admin-v2
spec:
containers:
- name: admin-v2
image: admin-v2
ports:
- containerPort: 4001
env:
- name: AAD_CLIENT_ID
valueFrom:
secretKeyRef:
name: app-dev-secrets
key: AAD_CLIENT_ID
- name: AAD_TENANT_ID
valueFrom:
secretKeyRef:
name: app-dev-secrets
key: AAD_TENANT_ID
---
apiVersion: v1
kind: Service
metadata:
name: admin-v2-cluster-ip-service-dev
namespace: dev
spec:
type: ClusterIP
selector:
component: admin-v2
ports:
- port: 4001
targetPort: 4001
When I do the following anywhere in the code, it comes back undefined:
console.log(process.env.AAD_CLIENT_ID);
console.log(process.env.AAD_TENANT_ID);
The values are definitely there when I check secrets in the namespace and in the Pod itself:
Environment:
AAD_CLIENT_ID: <set to the key 'AAD_CLIENT_ID' in secret 'app-dev-secrets'> Optional: false
AAD_TENANT_ID: <set to the key 'AAD_TENANT_ID' in secret 'app-dev-secrets'> Optional: false
So how should one go about getting kubectl secrets into React Pods?
I am guessing you are using create-react-app app for React FE. You have to make sure that your environment variables starts with REACT_APP_ else it will be ignored inside app.
According to create-react-app documentation
Note: You must create custom environment variables beginning with REACT_APP_.
Any other variables except NODE_ENV will be ignored to avoid accidentally
exposing a private key on the machine that could have the same name.
Source - https://create-react-app.dev/docs/adding-custom-environment-variables/

ReactJS app displays whitescreen using Kubernetes Ingress

I am trying to get hands around ingress routing to deploy multiple ReactJS application using one public ip address. Using SpeedyMath app available at https://github.com/pankajladhar/speedy-math.git with below routing file trying to access this app as http://myapps.centralus.cloudapp.azure.com/speedymath displays a white screen. From browser logs what i see is http://myapps.centralus.cloudapp.azure.com/static/js/bundle.js net::ERR_ABORTED 404 (Not Found). I notice index.html getting loaded but errors "Failed to load resource" at line <script type="text/javascript" src="/static/js/bundle.js"></script></body>
ingress-routing.yml:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: myapps-ingress
annotations:
nginx.org/server-snippet: "proxy_ssl_verify off;"
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
rules:
- http:
paths:
- path: /speedymath
backend:
serviceName: speedymath-service
servicePort: 80
The same application loads properly when the routing file is updated for path from "/speedymath" to "/". But this does not help me in building different routing rules based on incoming url
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: myapps-ingress
annotations:
nginx.org/server-snippet: "proxy_ssl_verify off;"
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
rules:
- http:
paths:
- path: /
backend:
serviceName: speedymath-service
servicePort: 80
Appreciate your help here
My issue got resolved with couple of things:
As #mk_sta stated, path as path: /speedymath(/|$)(.*) and nginx.ingress.kubernetes.io/rewrite-target: /$2
To handle the context issue with ReactJS app, updated package.json to include "homepage": ".". This will update all links and paths to refer from current directory.
I've managed to reproduce the issue in the similar user case with Nginx Ingress controller 0.25.1 version:
$ kubectl exec -it $(kubectl get po -l component=controller|awk '{print $1}'| sed '1d') -- /nginx-ingress-controller
A few concerns that might help you to resolve a problem:
FYI, since 0.22.0 version of Nginx Ingress was announced, some significant changes in Rewrite annotations being propagated that are not compatible with previous configurations, read more here.
If you are using more latest Ingress controller release, then you would probably need to slightly improve the origin Ingress definition, according to the documentation:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: myapps-ingress
annotations:
nginx.org/server-snippet: "proxy_ssl_verify off;"
nginx.ingress.kubernetes.io/rewrite-target: /$2
spec:
rules:
- http:
paths:
- path: /speedymath(/|$)(.*)
backend:
serviceName: speedymath-service
servicePort: 80
Afterwards, you might be able to reach the application endpoint, however I have added Trailing slash in my target URL, instructing Nginx engine to properly serve some static content; looking at your URL:
http://myapps.centralus.cloudapp.azure.com/speedymath/
Following this discussion, you can even redirect all requests to a non trailing location, adjusting appropriate Configuration snippet annotation to the source Ingress resource:
nginx.ingress.kubernetes.io/configuration-snippet: |
rewrite ^(/speedymath)$ $1/ permanent;
The last time I did this my annotation was a bit different. That's the only difference I see between what worked for me.
annotations:
ingress.kubernetes.io/rewrite-target: /
I also had this problem. It's caused because you specified a path in your ingress (in your case speedymath) but the react application will try to access the root path.
This can be solved by adding an environment variable (PUBLIC_URL) assigned with the same path you specified on ingress (would be \speedymath\ in your case) in your deployment (or pod) yaml like this:
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp
labels:
app: myapp
spec:
replicas: 1
selector:
matchLabels:
app: myapp
template:
metadata:
labels:
app: myapp
spec:
containers:
- name: myapp
env:
- name: PUBLIC_URL
value: "/<MY_INGRESS_PATH>/"
image: myapp/image:latest
ports:
- containerPort: 80
Hope this can help others!

Where is the cassandra.yaml location on the MAC?

I am working on the docker environment, and executed docker exec -it mycassandra cqlsh. Then, I am inserting the data, and it is occurring the following error:
WriteTimeout - Error from server: code=1100
By this, it tells me that I need to find out the cassandra.yaml document and amend the write-time, but I can not find that on my MAC.
Could you tell me how can I find it and how to amend the document?
Thanks.
for those who have installed it as brew install cassandra, yaml file will located in usr/local/etc/cassandra
If you are running the official cassandra image then cassandra.yaml may be found at /etc/cassandra/cassandra.yaml in the container. If you want to create a custom cassandra.yaml file then you may try to overwrite it in your Dockerfile or docker-compose.yml file. For example, in my docker-compose.yml file I have something like:
services:
cassandra:
image: cassandra:3.11.4
volumes:
- ./cassandra.yaml:/etc/cassandra/cassandra.yaml
which causes the cassandra.yaml file in the container to be overwritten by my local cassandra.yaml.
I hope this helps.
From the provided example, it seems that the database is executed from inside a container. So the cassandra.yaml that you're looking for will be created on the fly when the container is started up, based on the configuration that you provided.
We have set Cassandra Containers with Kubernetes, and execute them in docker, based on the instructions found here, and been able to modify the settings of the cassandra.yaml file in the configuration of the statefulset, updating the variables in env for the spec of the container.
For example, to modify the seeds list, the cluster name, and the rack of the C* cluster named c-test-qa:
apiVersion: apps/v1
kind: StatefulSet
...
spec:
serviceName: c-test-qa
replicas: 1
selector:
matchLabels:
app: c-test-qa
template:
metadata:
labels:
app: c-test-qa
spec:
containers:
- name: c-test-qa
image: cassandra:3.11
imagePullPolicy: IfNotPresent
...
env:
- name: CASSANDRA_SEEDS
value: c-test-qa-0.c-test-qa.qa.svc.cluster.local
- name: CASSANDRA_CLUSTER_NAME
value: "testqa"
- name: CASSANDRA_RACK
value: "DC1"
- name: CASSANDRA_RACK
value: "CustomRack1"
...
On MacOS :
It will be found in either of the below locations:
Cassandra package installations: /etc/cassandra
Cassandra tarball installations: install_location/conf
DataStax Enterprise package installations: /etc/dse/cassandra
DataStax Enterprise tarball installations: install_location/resources/cassandra/conf

Resources