I have a React app that I want to pull data from a springboot endpoint on load. If I run it locally (via intellij and webstorm) it loads and I see my page render. It looks like this:
The 1: course1 and 2: course2 are the response being read from my springboot call.
The ONLY thing I'm changing in the code between local run and local cluster is the endpoint that react calls. I change from http://localhost:8080/greeting to http://bootdemo:8080/greeting (bootdemo being the name of the service). When I run it in my local cluster (Im using docker-desktop and navigating my browser to http://localhost:31000/) I get a page that just says "Loading..." and nothing ever loads. Using google developer tools on the page I can see this:
[HMR] Waiting for update signal from WDS...
App.js:12 Fetching from http://bootdemo:8080/greeting
App.js:13 GET http://bootdemo:8080/greeting net::ERR_NAME_NOT_RESOLVED
App.js:24 error: TypeError: Failed to fetch
Any help would be appreciated. Below is the react code and the k8's files and output I thought relevant to the problem. Let me know what else I can add if needed!
React App.js:
import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';
class App extends Component {
state = {
isLoading: true,
groups: []
};
async componentDidMount() {
console.log("Fetching from http://bootdemo:8080/greeting")
await fetch('http://bootdemo:8080/greeting').then((response) => {
if(!response.ok) throw new Error("Couldnt make the connection: " response.status.toString());
else return response.json();
})
.then((data) => {
console.log("Testing Testing")
this.setState({ isLoading: false, groups: data });
console.log(data)
console.log("DATA STORED");
})
.catch((error) => {
console.log('error: ' error);
this.setState({ requestFailed: true });
});
}
render() {
const {groups, isLoading} = this.state;
if (isLoading) {
return <p>Loading...</p>;
}
console.log("Made it here")
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<div className="App-intro">
<h2>Attempted Response</h2>
<div>
{groups.map((group) => (
<p>{group.id} : {group.name}</p>
))}
</div>
</div>
</header>
</div>
);
}
}
export default App;
K8's Springboot setup:
apiVersion: apps/v1
kind: Deployment
metadata:
name: bootdemo
labels:
name: bootdemo
spec:
replicas: 1
selector:
matchLabels:
app: bootdemo
template:
metadata:
labels:
app: bootdemo
spec:
containers:
- name: bootdemo
image: demo:latest
imagePullPolicy: Never
ports:
- containerPort: 80
---
kind: Service
apiVersion: v1
metadata:
name: bootdemo
labels:
app: bootdemo
spec:
selector:
app: bootdemo
ports:
- name: http
port: 8080
targetPort: 80
K8's React setup:
apiVersion: apps/v1
kind: Deployment
metadata:
name: demo
labels:
name: demo
spec:
replicas: 1
selector:
matchLabels:
app: demo
template:
metadata:
labels:
app: demo
spec:
containers:
- name: reactdemo
image: reactdemo:latest
imagePullPolicy: Never
ports:
- name: http
containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: demo
spec:
type: NodePort
selector:
app: demo
ports:
- name: ingressport
port: 3000
targetPort: 3000
nodePort: 31000
Kubenetes after applying the deployment yamls:
NAME READY STATUS RESTARTS AGE
pod/bootdemo-7f84f48fc6-2zw4t 1/1 Running 0 30m
pod/demo-c7fbcd87b-w77xh 1/1 Running 0 30m
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/bootdemo ClusterIP 10.102.241.8 <none> 8080/TCP 30m
service/demo NodePort 10.108.61.5 <none> 3000:31000/TCP 30m
service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 23d
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/bootdemo 1/1 1 1 30m
deployment.apps/demo 1/1 1 1 30m
NAME DESIRED CURRENT READY AGE
replicaset.apps/bootdemo-7f84f48fc6 1 1 1 30m
replicaset.apps/demo-c7fbcd87b 1 1 1 30m
It seems that the react service just cant reach the boot service. I suspect it is one or more of the following:
- a naming/mapping issue in the deployment files
- using two services instead of just one
- React served into my browser doesn't know how to reach back into my cluster and get to springboot. Do I need something like nginx in the mix?
CodePudding user response:
Your browser won't be able to resolve http://bootdemo:8080/
because bootdemo
is only resolvable by pods running inside the same namespace.
You see, even if you run Kubernetes cluster on your local machine via Docker Desktop, the cluster and your local machine are effectively isolated by their separate networking layers and hence any access from your local machine to any service in your cluster requires special bridging mechanisms such as NodePort
or LoadBalancer
services (as I can see you are already using NodePort
service for the demo
).
In a proper clusters served by Kubernetes distributions like AKS, GCP, EKS, PKS etc, however, you would need to design how the cluster would accept and route inbound traffics to the component within the cluster, which would commonly require setting up ingress controllers (NGINX being most popular though you can also use Traefik or HAProxy) as well as creating ingress resources which will map specific URLs & paths to specific services inside the cluster and namespace.