I'm struggling to make Http calls from the frontend app to the backend app in Kubernetes.
So basically I have deployment,service and ingress rules for both frontend and backend application and the frontend service can't connect to backend service.
This is the error message Im getting
GET http://spring-boot-vuejs:8080/api/courses net::ERR_NAME_NOT_RESOLVED
I am trying to create a simple web application using Vuejs as frontend and Spring boot as backend. The backend exposes REST api's on /api/courses/* endpoint and the frontend consumes it.
I have deployed two separate pods, one for frontend and one for backend on a bare metal Kubernetes cluster. I have also installed Nginx ingress controller.
if I run both docker images in my local machine, everything works fine because Im using "http://localhost:8080" as the backend end point but the moment I deploy the apps on Kubernetes, it wont work anymore as it can resolve the service name "http://spring-boot-vuejs:8080"
I already referred to issues mentioned here, here, here but none of them helped me.
Below are the respective yaml files. Please correct me if Im making mistake in any yaml files or the ingress rules.
Backend:
apiVersion: apps/v1
kind: Deployment
metadata:
name: spring-boot-vuejs
labels:
app: spring-boot-vuejs
spec:
replicas: 1
selector:
matchLabels:
app: spring-boot-vuejs
template:
metadata:
labels:
app: spring-boot-vuejs
spec:
containers:
- name: spring-boot-vuejs
imagePullPolicy: ifNotPresent
image: <my docker hub username>/spring-boot-vuejs:0.0.1
ports:
- containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
name: spring-boot-vuejs
labels:
app: spring-boot-vuejs
spec:
clusterIP: None
ports:
- port: 8080
targetPort: 8080
protocol: TCP
name: spring-boot-vuejs
selector:
app: spring-boot-vuejs
Ingress rules
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: spring-boot-vuejs
annotations:
kubernetes.io/ingress.class: nginx
spec:
backend:
serviceName: default-http-backend
servicePort: 80
rules:
- host: spring-boot-vuejs
- http:
paths:
- path: /api/.*
backend:
serviceName: spring-boot-vuejs
servicePort: 8080
Yaml files for frontend
Deployment and service
apiVersion: apps/v1
kind: Deployment
metadata:
name: vuejs-frontend
labels:
app: vuejs-frontend
spec:
replicas: 1
selector:
matchLabels:
app: vuejs-frontend
template:
metadata:
labels:
app: vuejs-frontend
spec:
containers:
- name: vuejs-frontend
imagePullPolicy: ifNotPresent
image: <my dockerhub username>/vuejs-frontend:0.0.1
ports:
- containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
name: vuejs-frontend
labels:
app: vuejs-frontend
spec:
clusterIP: None
ports:
- port: 8080
targetPort: 8080
protocol: TCP
name: vuejs-frontend
selector:
app: vuejs-frontend
Ingress rules
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: vuejs-frontend
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
backend:
serviceName: default-http-backend
servicePort: 80
rules:
- host: spring-boot-vuejs
- http:
paths:
- path: /
backend:
serviceName: vuejs-frontend
servicePort: 8080
If I understood you correctly, the issue is that the vuejs-frontend
can't reach spring-boot-vuejs
on port 8080
.
I see that you have created a headless Service
( a Service with clusterIP: None
). Moreover , that service has no selectors specified in yaml, thus no EndPoinds
were created)
Official documentation on topic says:
Sometimes you don’t need load-balancing and but single Service IP. In this case, you can create what are termed “headless” Services, by explicitly specifying
"None"
for the cluster IP (.spec.clusterIP
).For headless
Services
, a cluster IP is not allocated, kube-proxy does not handle these Services, and there is no load balancing or proxying done by the platform for them. How DNS is automatically configured depends on whether the Service has selectors defined.For headless Services that do not define selectors, the endpoints controller does not create
Endpoints
records. However, the DNS system looks for and configures either:
- CNAME records for
ExternalName
-type Services.- A records for any
Endpoints
that share a name with the Service, for all other types
There are a few solutions here.
apiVersion: v1
kind: Endpoints
metadata:
name: spring-boot-vuejs
namespace: default
subsets:
- addresses:
- ip: IP_spring-boot-vuejs_pod
ports:
- name: http
port: 8080
protocol: TCP
as a result, the DNS will be configured properly.
below you can see how it works on my k8s installation. All the files I'm using are from my GitHub repo.
$ kubectl create -f deployment.yaml
deployment.apps/server-go-deploy created
$ kubectl get deployments
NAME READY UP-TO-DATE AVAILABLE AGE
server-go-deploy 1/1 1 1 9s
$ kubectl create deployment nginx --image=nginx
deployment.apps/nginx created
$ kubectl get pods -o wide
NAME READY STATUS AGE IP
nginx-65f88748fd-vzgxx 1/1 Running 9m16s 10.52.3.13
server-go-6c84bbd44d-r5bsb 1/1 Running 14m 10.52.3.12
$ kubectl create -f service.yaml
service/hello-go created
$ kubectl get services -o wide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
hello-go ClusterIP None <none> 8180/TCP 13s <none>
kubernetes ClusterIP 10.0.0.1 <none> 443/TCP 123d <none>
$ kubectl exec -it nginx-65f88748fd-vzgxx -- curl hello-go:8180
curl: (6) Could not resolve host: hello-go
command terminated with exit code 6
## As you can see K8s knows nothing that request to 'hello-go' should be routed to 'hello-go' Pod.
$ kubectl create -f ep.yaml
endpoints/hello-go created
$ kubectl get ep -o wide
NAME ENDPOINTS AGE
hello-go 10.52.3.12:8180 3s
kubernetes 35.234.103.244:443 123d
kiwi@kiwi-dv7:~/PycharmProjects/innovative-solutions/61326587-svc$ kubectl exec -it nginx-65f88748fd-vzgxx -- curl hello-go:8180/whoo-hoo
Hello from ServerGo. You requested: /whoo-hoo
#And now it works.
Hope that helps.