Anxious-Individual81
Anxious-Individual81

Reputation: 13

How can I resolve connection issues between my frontend and backend pods in Minikube?

I am trying to deploy an application to Minikube. However I am having issues connecting the frontend pod to the backend pod. Each Deployment have a ClusterIP service, and a NodePort service.

I access the frontend via browser, executing the command: minikube service frontend-entrypoint. When the frontend tries to query the backend it requests the URL: http://fastapi-cluster-ip-service:8000/api/v1/baseline/building_type?building_type=commercial, but the status response is: (failed)net::ERR_EMPTY_RESPONSE.

If I access the frontend via cmd, executing the command: kubectl exec -it react-deployment-xxxxxxxxxx-xxxxx -- sh, and execute inside it the command: curl -X GET "http://fastapi-cluster-ip-service:8000/api/v1/baseline/building_type?building_type=commercial" I get what I expect.

So, I understand that NodePorts are used to route external traffic to services inside the cluster by opening a specific port on each node in the cluster and forwarding traffic from that port to the service, and that ClusterIPs, on the other hand, are used to expose services only within the cluster and are not directly accessible from outside the cluster. What I don't understand is why when reaching the frontend via browser, the same is not able to connect internally to the backend? Once playing with the frontend I consider I am inside the cluster...

I tried to expose the cluster using other services such as Ingress or LoadBalancer, but I didn't have success connecting to the frontend, so I rollback to the NodePort solution.

References:

Files:

component_backend.yaml:

apiVersion: v1
kind: Service
metadata:
  name: backend-entrypoint
spec:
  selector:
    component: fastapi
  ports:
  - name: http2
    port: 8000
    targetPort: 8000
  type: NodePort
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: fastapi-deployment
spec:
  replicas: 1
  selector:
    matchLabels:
      component: fastapi
  template:
    metadata:
      labels:
        component: fastapi
    spec:
      containers:
      - name: fastapi-container
        image: xxx/yyy:zzz
        ports:
            - containerPort: 8000
        env:
          - name: DB_USERNAME
            valueFrom:
              configMapKeyRef:
                name: app-variables
                key: DB_USERNAME
          [...]
      imagePullSecrets:
      - name: myregistrykey
---
apiVersion: v1
kind: Service
metadata:
  name: fastapi-cluster-ip-service
spec:
  type: LoadBalancer
  selector:
    component: fastapi
  ports:
    - port: 8000
      targetPort: 8000
  externalIPs:
    - <minikube ip>

componente_frontend.yaml:

apiVersion: v1
kind: Service
metadata:
  name: frontend-entrypoint
spec:
  selector:
    component: react
  ports:
  - name: http1
    port: 3000
    targetPort: 3000
  type: NodePort
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: react-deployment
spec:
  replicas: 1
  selector:
    matchLabels:
      app: react
  template:
    metadata:
      labels:
        app: react
    spec:
      containers:
      - name: react-container
        image: xxx/yyy:zzz
        ports:
        - containerPort: 3000
        env:
          - name: BASELINE_API_URL
            valueFrom:
              configMapKeyRef:
                name: app-variables
                key: BASELINE_API_URL
      imagePullSecrets:
      - name: myregistrykey
---
apiVersion: v1
kind: Service
metadata:
  name: react-cluster-ip-service
spec:
  type: LoadBalancer
  selector:
    component: react
  ports:
    - port: 3000
      targetPort: 3000
  externalIPs:
    - <minikube ip>

BASELINE_API_URL is declared with the backend ClusterIP service name (i.e., fastapi-cluster-ip-service).

ingress_service.yaml:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: ingress-service
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /$1
spec:
  rules:
  - host: sfs.baseline
    http:
      paths:
        - path: /
          pathType: Prefix
          backend:
            service:
              name: frontend-entrypoint
              port:
                name: http1        
        - path: /api
          pathType: Prefix
          backend:
            service:
              name: backend-entrypoint
              port:
                name: http2

Upvotes: 1

Views: 768

Answers (2)

Ralle Mc Black
Ralle Mc Black

Reputation: 1203

You have to think about this: If you call the api through your browser or Postman from your host, they dont know anything about the url inside your pod. For production ingress configuration is needed, so you can call the api like:

https://api.mydomain.com/api/myroute

When you deploy the frontend the paths inside your code should be created dynamically.

Inside your code define the path with env variables and use them inside your code.

On Kubernetes define a configMap with the paths and bind it to your container. So when you call the Frontend it will have the right paths.

Your Frontend on local can be reached with the Ip address of your masternode and the nodePort.

To not use the ip address you can create an entry in your local hosts file.

nodesipaddress  mydomain.local
nodesipaddress  api.mydomain.local

so from you browser you can reach the frontend with mydomain.local:nodeportOfFrontend

And your frontend code should call the backend with api.mydomain.local:nodeportOfApi

If you enable Ingress inside your cluster and create an ingress resource in your deployment and a service of type LoadBalancer, then you can call the Frontend and api without the nodePort.

If you are getting in issues with that, please post all your kubernetes yamls. Deployments, Services, configMap and ingress if you decide to use it.

UPDATE

Check if you have ingress enabled on minikube

Modify your ingress-recource

apiVersion: networking.k8s.io/v1
   
kind: Ingress
   
metadata:
   
  name: myingress
   
  annotations:
   
    nginx.ingress.kubernetes.io/rewrite-target: /$1
   
spec:
   
  rules:
   
    - host: mydomain.local
   
      http:
   
        paths:
   
          - path: /

Im not sure if minikube supports ClusterIp

Change the type to LoadBalancer in your service:

apiVersion: v1
kind: Service
metadata:
  name: fastapi-cluster-ip-service
spec:
  type: LoadBalancer
  selector:
    component: fastapi
  ports:
    - port: 8000
      targetPort: 8000

If you verify your service:

kubectl get svc -o wide
kubectl describe services my-service

Look if there is external IP pending if so add externalIp:

  ports:
    - port: 8000
      targetPort: 8000
  externalIPs: 
    - xxx.xxx.xxx.xxx # your minikube ip

However i would try first to create a service type NodePort and then access with xxx.xxx.xxx.xxx:NodePort.

In the yamls you posted i see only the backend.

Think if you use ingress or NodePort, your code must be adapted:

Your Frontend must call the api by api ingress domain or xxx.xxx.xxx.xxx:NodePort / mydomain.local/api

Upvotes: 0

pida
pida

Reputation: 425

I think you are not understanding how the frontend part of a website works. To display the website in your browser, you actually download all the required content from the server/pod where you host the frontend.

Once the front is downloaded and displayed on your browser, now you try to hit the backend directly from your browser/computer using either an IP address or an URL.

When using an URL, you browser will try to resolve the hostname using a DNS server

So when you read a website from your browser you are not in the server/pod and you cannot resolve the URL because that URL is not mapped to any IP address (or not to your server). Also that is why it works when you go inside the pod using kubectl exec, because you are inside the network and you are using the internal DNS.

As David said, to make this work, you need to call the backend from the frontend using sone kind of ingress. And also you will need to create a DNS entry on your domain (if using an URL). If not you can directly use the IP of the pod/service.

Upvotes: 0

Related Questions