Unable to reach backend service from frontend service in Kubernetes

4/20/2020

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
-- rakesh
kubernetes
kubernetes-ingress
kubernetes-service
nginx
spring-boot

1 Answer

4/21/2020

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.

  • to create EP manually.
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.

  • to create a Service of other type or at least to add selectors to your current service.

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.

-- Nick
Source: StackOverflow