0

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
  • 135
  • 3
  • 15
  • spring-boot-vuejs cannot be the Hostname. What's the Nginx hostname? – Simon Martinelli Apr 20 '20 at 15:55
  • Is it mandatory to mention hostname? I removed it but still no luck. This is the nginx details pod name `ngress-nginx nginx-ingress-controller-6879cf6459-8cg44 1/1 Running 0 64d` Nginx service `ingress-nginx ingress-nginx NodePort 10.105.123.73 80:32372/TCP,443:30907/TCP 64d` – rakesh Apr 20 '20 at 16:01
  • I don't think this is your problem.... but you don't need an ingress resource for the backend if your frontend and backend are on the same k8s cluster. I would remove the backend ingress service unless you want external apps to be able to reach the backend directly? – TuxInvader Apr 20 '20 at 20:15
  • also check your resolv.conf in the frontend... try `kubectl exec pod/ cat /etc/resolv.conf` What does that return? You should see a list of k8s cluster search domains? – TuxInvader Apr 20 '20 at 20:23
  • This is what I have in `/etc/resolv.conf` on frontend pod. `# cat /etc/resolv.conf nameserver 10.96.0.10 search vuejs.svc.cluster.local svc.cluster.local cluster.local lswv130.leasewebcloud.com options ndots:5` I removed the ingress for backend – rakesh Apr 21 '20 at 07:43
  • @rakesh , could you add an output for `kubectl get pods -o wide` as well as for services and endpoints ? I didn't notice "selectors" when I was giving my answer – Nick Apr 21 '20 at 17:17
  • @rakesh Were you able to solve this problem? – Mark Apr 28 '20 at 10:51
  • @Hanx no. Instead of using separate service for frontend and backend, I combined frontend and backend into 1 pod using thymeleaf. So i dont have two services anymore and just one basic backend service which can be accessed directly – rakesh Apr 28 '20 at 15:24
  • If you are still able to provide more details about the previous deployments pleases share with more details: 1. `kubectl get pods,svc,ep,ingress`, 2. `kubectl describe ingress`, 3. `kubectl logs ` (while curling from inside and outside of the cluster) – Mark Apr 28 '20 at 15:46
  • @Hanx sorry, I have deleted the complete namespace and dont have those data anymore :( – rakesh Apr 29 '20 at 16:28

1 Answers1

0

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
  • 1,882
  • 11
  • 16
  • Thanks for your detailed explanation. Looks like the end point was already created and I didnt need to create it. `$ k get ep -o wide NAME ENDPOINTS AGE spring-boot-vuejs 10.1.140.79:8080 24h vuejs-frontend 10.1.196.146:8080 23h` I ssh'ed into vuejs pod and an entry in `/etc/hosts` file like `10.1.140.79 spring-boot-vuejs`. Now curl spring-boot-vuejs:8080/api/courses works like a charm but if I access the vuejs frontend pod from my browser using public IP of kubernetes cluster, the frontend pod still can reach backend pod. Getting same error – rakesh Apr 21 '20 at 17:06
  • not sure if I got you. Am I right that you have ssh'ed on Frontend and changed the `/etc/hosts` there ? So frontend can reach backend now. – Nick Apr 21 '20 at 20:44
  • Yes I ssh'ed to frontend pod, added backend service name alsong with the service IP in the `/etc/hosts` file and now I can successfully send get request to backend service – rakesh Apr 22 '20 at 17:44
  • @rakesh, it's only a "hotfix" the root cause is that you shall be able connecting to it via service. We can troubleshoot it further if you like, but I'll need an info from my last comment. Additionally it would be good if you can explain wich CNI you are using, because from what I see, there shall already be a record in DNS (service with selector) – Nick Apr 22 '20 at 17:54
  • I was using calico. Yes it was just a hotfix and I stopped looking into the issue. Thanks for your help – rakesh Apr 28 '20 at 15:22