I have created the free IBM Cloud Kubernetes cluster and try to deploy my react pwa(created with create-react-app) in it from Docker image. I managed to deploy the app in the cluster, but my service worker doesn't work.
When I do npm run build and serve -s build everything in the app is working fine in localhost:5000.
But in the deployed app the serviceWorker is not found in the navigator and it never register the service worker:
if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {
...
//never goes in here
registerValidSW(swUrl, config);
});
And also getting this error when trying to access caches in the deployed app:
Uncaught (in promise) ReferenceError: caches is not defined
at c (runtime.js:45)
at Generator._invoke (runtime.js:264)
at Generator.O.forEach.e.<computed> [as next] (runtime.js:98)
at r (asyncToGenerator.js:3)
at l (asyncToGenerator.js:25)
at asyncToGenerator.js:32
at new Promise (<anonymous>)
at t.getRequests (asyncToGenerator.js:21)
at t.value (index.js:142)
My Dockerfile looks like this:
FROM node:alpine as builder
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build
FROM nginx
EXPOSE 80
COPY --from=builder /app/build /usr/share/nginx/html
And my deployment.yaml is looking like this:
apiVersion: v1
kind: Service
metadata:
name: my-app-service
labels:
app: app
spec:
type: NodePort
ports:
- port: 80
name: http
selector:
app: app
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: my-app-deployment
spec:
replicas: 1
template:
metadata:
labels:
app: app
spec:
containers:
- name: my-app
image: us.icr.io/my-app-namespace/my-app
ports:
- containerPort: 8080
Which node and npm version do you have installed locally?
You set up in your Dockerfile the latest version of node:
FROM node:alpine as builder
Identify the version that you have locally running:
node --version
Now select the right version here Docker Hub node tags
Example: If your node version is 8, you need set some version like:
FROM node:8-alpine
Related
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
I have a very simple react typescript application and using Vite for the first time to replace Webpack.
I have the following vite.config.js:
server: {
watch: {
usePolling: true,
},
open: false,
host: '0.0.0.0',
},
and created a Dockerfile with these instructions:
FROM node:latest
WORKDIR /usr/src/app
COPY package.json package-lock.json ./
COPY ./build-prod ./build-prod
COPY ./node_modules ./node_modules
RUN npm install husky -g --production
RUN npm install esbuild-linux-arm64 --production
COPY . .
EXPOSE 3000
CMD ["npm", "run", "dev"]
When I now run docker run -p 3000:3000 hello-world-app-frontend I can access my app with http://localhost:3000/ but opening the network address http://172.17.0.3:3000/ just loads an untitled window.
I think this is especially a problem for me as I want to create a basic Kubernetes config like this:
kind: Deployment
apiVersion: apps/v1
metadata:
name: hello-world-app-frontend
spec:
replicas: 2
selector:
matchLabels:
app: hello-world-app-frontend
template:
metadata:
labels:
app: hello-world-app-frontend
spec:
containers:
- name: hello-world-app-frontend
image: hello-world-app-frontend
imagePullPolicy: Never
ports:
- containerPort: 3000
restartPolicy: Always
kind: Service
apiVersion: v1
metadata:
name: hello-world-app-frontend
spec:
type: NodePort
ports:
- port: 3000
targetPort: 3000
protocol: TCP
nodePort: 31000
selector:
app: hello-world-app-frontend
But opening the IP address from my Pod returns nothing in my Chrome (f.e. http://10.106.213.128:3000/).
NAMESPACE NAME READY STATUS RESTARTS AGE
default pod/hello-world-app-frontend-77899b46d7-cc4td 1/1 Running 0 16h
default pod/hello-world-app-frontend-77899b46d7-vqtbz 1/1 Running 0 16h
NAMESPACE NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
default service/hello-world-app-frontend NodePort 10.106.213.128 <none> 3000:31000/TCP 16h
Can somebody give me a few hints how I can access the React application from my k8s pod?
I want to deploy a worker (FastApi) and a web (react) container to Heroku using docker-compose. Running locally, everything works. But on Heroku, the frontend cannot reach the backend.
Dockerfile.worker
FROM tiangolo/uvicorn-gunicorn-fastapi:python3.7
WORKDIR /app
COPY app .
COPY requirements.txt ./requirements.txt
ENV IS_IN_DOCKER=true
RUN pip3 install -r requirements.txt
RUN pip3 install -r ./custom_model/custom_requirements.txt
CMD uvicorn main:app --host 0.0.0.0 --port 8800
Dockerfile.web
# pull official base image
FROM node:13.12.0-alpine
# set working directory
WORKDIR /app
# add `/app/node_modules/.bin` to $PATH
ENV PATH /app/node_modules/.bin:$PATH
# install app dependencies
COPY package.json ./
COPY package-lock.json ./
RUN npm install --silent
RUN npm install react-scripts#3.4.1 -g --silent
# add app
COPY . ./
# start app
CMD ["npm", "start"]
docker-compose.yml (using the Port Env variable from heroku for the frontend, locally i have a .env File with PORT=80)
version: '3.7'
services:
ml-starter-frontend:
depends_on:
- ml-starter-backend
container_name: ml-starter-frontend
build:
context: ./frontend
dockerfile: Dockerfile.web
ports:
- '${PORT}:3000'
restart: always
ml-starter-backend:
container_name: ml-starter-backend
build:
context: ./backend
dockerfile: Dockerfile.worker
restart: always
setupProxy.js in React src
const { createProxyMiddleware } = require('http-proxy-middleware');
module.exports = function(app) {
app.use(
'/api/*',
createProxyMiddleware({
target: 'http://ml-starter-backend:8800',
changeOrigin: true,
})
);
};
Call in React frontend to backend
export const getConfiguration = () => async (dispatch) =>{
const {data} = await axios.get('/api/configs')
dispatch({type: GET_CONFIGURATION, payload: data })
}
Running locally the call works:
Locally
Deployment to heroku:
heroku container:push --recursive --app {appName}
heroku container:release worker --app {appName}
heroku container:release web --app {appName}
Frontend cannot reach backend:
Heroku
Heroku Worker (FastAPI) log
2021-04-09T10:10:55.322684+00:00 app[worker.1]: INFO: Application startup complete.
2021-04-09T10:10:55.325926+00:00 app[worker.1]: INFO: Uvicorn running on http://0.0.0.0:8800 (Press CTRL+C to quit)
Heroku Web (React) Log
2021-04-09T10:11:21.572639+00:00 app[web.1]: [HPM] Proxy created: / -> http://ml-starter-backend:8800
.....
2021-04-09T10:25:37.404622+00:00 app[web.1]: [HPM] Error occurred while trying to proxy request /api/configs from {appName}.herokuapp.com to http://ml-starter-backend:8800 (ENOTFOUND) (https://nodejs.org/api/errors.html#errors_common_system_errors)
If possible i would like to avoid nginx as I already spent 2 hours trying to make it work with proxies in the prod build. Does anybody have experience with heroku and docker-compose and could give me a hint how to fix this?
For everybody with a similiar problem.. Actually i ended up with a workaround.. I made a dockerfile containing the backend and frontend.. and deployed it to Heroku as a web app..
During my search i discovered, that Heroku workers are not really suitable in a HTTP scenario. If I understood it right, they are meant for reading messages from a queue.. https://devcenter.heroku.com/articles/background-jobs-queueing
Yup, I did something like what Loki34 did too. My approach was to run npm run build, then have FastAPI serve these build files. And like what Loki34 says, this is a workaround approach, meaning it's probably not the best approach out there when it comes to deploying frontend and backend in Docker containers. Anyway, those who are curious about how I did it can check out this app that I did: https://github.com/yxlee245/app-iris-ml-react-fastapi
Environment health has transitioned from Ok to Severe. ELB processes are not healthy on all instances. ELB health is failing or not available for all instances.
I am deploying a react app in AWS using the docker platform. I am getting HEALTH-Severe issues when I deploy my app. I have also added custom TCP inbound rules in the EC2 instance (source-anywhere).
I am using free tier in AWS. The following is my Dockerfile.
FROM node:alpine as builder
WORKDIR '/app'
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build
FROM nginx
EXPOSE 80
COPY --from=builder /app/build /usr/share/nginx/html
My .travis.yml file:
language: generic
sudo: required
services:
- docker
before_install:
- docker build -t username/docker-react -f Dockerfile.dev .
script:
- docker run -e CI=true username/docker-react npm run test
deploy:
provider: elasticbeanstalk
region: us-east-2
app: "docker-react"
env: "DockerReact-env"
bucket_name: "my bucket-name"
bucket_path: "docker-react"
on:
branch: master
access_key_id: $AWS_ACCESS_KEY
secret_access_key: $AWS_SECRET_KEY
When I open my app I am getting 502 Bad Gateway error.
I had the same problem. After reading some of the documentation here I figured maybe docker-compose.yml is actually picked up first before anything. Deleting my docker-compose.yml (which I was only using locally) solved the issue for me.
I have a problem with a simple react app that was created using npx create-react-app react-app. Once deployed on k8s, I got this:
Uncaught SyntaxError: Unexpected token '<'
However, if I would to kubectl port-forward to the pod and view the app at localhost:3000 (container's pod is at 3000, cluster ip service listening on 3000 and forwarding to 3000) no problem at all.
The ingress routing looks to be fine as I can get to other services to work within the cluster but not to the app. Some help would be greatly appreciated.
Deployment yaml:
apiVersion: apps/v1
kind: Deployment
metadata:
name: react-app-deployment
# namespace: gitlab-managed-apps
spec:
replicas: 1
selector:
matchLabels:
component: react-app
template:
metadata:
labels:
component: react-app
spec:
imagePullSecrets:
- name: simpleweb-token-namespace
containers:
- name: react-app
image: registry.gitlab.com/mttlong/sample/react-app
env:
- name: "PORT"
value: "3000"
ports:
- containerPort: 3000
Cluster ip service:
apiVersion: v1
kind: Service
metadata:
name: react-app-cluster-ip-service
spec:
type: ClusterIP
selector:
component: react-app
ports:
- port: 3000
targetPort: 3000
Dockerfile:
FROM node:10.15.3-alpine as builder
WORKDIR '/app'
COPY ./package.json ./
RUN npm install
COPY . .
RUN npm run build
FROM nginx
EXPOSE 3000
COPY ./nginx/default.conf /etc/nginx/conf.d/default.conf
COPY --from=builder /app/build /usr/share/nginx/html
Ingress Service:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: orion-ingress-service
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/rewrite-target: /$2
spec:
rules:
- host: horizon.zeezum.com
http:
paths:
- path: /
backend:
serviceName: react-app-cluster-ip-service
servicePort: 3000
- path: /api(/|$)(.*)
backend:
serviceName: simple-api-nodeport-service
servicePort: 3050
I ran into the same issue as you have described. I solved it by splitting up the Ingress for the front-end and the API.
In your case this would look something like this:
Front-end ingress service (without rewrite target):
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: orion-ingress-frontend-service
annotations:
kubernetes.io/ingress.class: nginx
spec:
rules:
- host: horizon.zeezum.com
http:
paths:
- path: /
backend:
serviceName: react-app-cluster-ip-service
servicePort: 3000
Back-end ingress service (with the /$2 rewrite-target):
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: orion-ingress-backend-service
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/rewrite-target: /$2
spec:
rules:
- host: horizon.zeezum.com
http:
paths:
- path: /api(/|$)(.*)
backend:
serviceName: simple-api-nodeport-service
servicePort: 3050
The rest of you configuration should be good.
Remove nginx.ingress.kubernetes.io/rewrite-target: /$2 this line and it should work
This is most likely the result of a 404 page or a redirect to a page that serves regular html instead of the expected JavaScript files. (A HTML page starts with <html> or a <!DOCTYPE...> therefore the < as unexpected token)
Make sure that you have correctly build the image and you access the page correctly. You can verify by manually accessing the URL with the browser or look into the network tab of your browser development tools to inspect the response.
(I assume that either you have cached the index.html and try to access old assets, check your cache header, or that the paths to not match. In that case inspect your image and access the URLs manually)
I had a similar thing. I got rid of the Ingress altogether, and in my Service yaml file changed my Service to type: Nodeport and added the fields protocol: TCP and nodePort: <insert nodeport> under each port.
I got the values ofthe nodeports by running kubectl expose deployment <insert deployment name> --type=NodePort --name=example-service. Which creates a service and assigns the ports. You can then run kubectl describe services example-service to display all the nodeport values. You can then copy the values to your Service yaml file.
When its all running you would access the website from the browser using the nodeport that was generated, ie localhost:31077for example, and not the actual port 3000.
I then changed any url routes I had to use the nodeport instead of the actual ports and boom.