x300n
x300n

Reputation: 331

Connecting Frontend and Backend in Kubernetes

My frontend is setup as:

this.http.post<any>(`${environment.apiUrl}/auth/login`, {email, password})

Where apiUrl: 'http://backend/api'

I built the frontend in a container and exposed it to a loadbalancer service and I am trying to hook it up through a ClusterIP service to a backend on port 3000.

Frontend YAML:

apiVersion: v1
kind: Service
metadata:
  name: frontend
spec:
  selector:
    tier: frontend
  ports:
    - port: 80
      targetPort: 80
  type: LoadBalancer
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: frontend
spec:
  selector:
    matchLabels:
      tier: frontend
  replicas: 1
  template:
    metadata:
      labels:
        tier: frontend
    spec:
      containers:
      - name: frontend
        image: <Image>
        imagePullPolicy: Always
        ports:
        - containerPort: 80

Backend YAML:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: backend
spec:
  selector:
    matchLabels:
      app: app
      tier: backend
  replicas: 1
  template:
    metadata:
      labels:
        app: app
        tier: backend
    spec:
      containers:
      - name: frontend-container
        image: <Image>
        ports:
        - containerPort: 3000
---
apiVersion: v1
kind: Service
metadata:
  name: backend
spec:
  selector:
    app: app
    tier: backend
  ports:
  - protocol: TCP
    port: 80
    targetPort: 3000

As explained in the doc here.

But it doesn't work when I try to access it from the browser, I receive Unknown Error!!

enter image description here

enter image description here

Here are screenshots from inside the frontend making sure it is able to reach the backend internally.

enter image description here

I don't understand where I went wrong here. I am thinking the apiUrl var set to http://backend is not being translated correctly because if I changed that to a loadbalancer IP and rebuilt the image, exposed the backend to a LB service instead of ClusterIP. It does work.

But obviously I don't want to expose my backend to a LB service.

Any idea?

Upvotes: 2

Views: 10773

Answers (3)

Himanshu Mamodiya
Himanshu Mamodiya

Reputation: 31

We can use nginx reverse proxy as well . In which backend-service needs not to expose using ingress or load balancer. Below steps works fine for me

  1. For example: replace http://api-service/api/getsomething to
    /api/getsomething

    /api/getsomething - this will tell the browser that it will send the request to the same server that served your frontend app (nginx in this case)

    Then via nginx server the call can be forwarder to your api using the K8S
    DNS. (It is called reverse proxy)

  2. sample docker file :

     ### STAGE 1: Build ###
     FROM node:16 as build
    
     # Create app directory
     WORKDIR /app
    
     # Install app dependencies
     # A wildcard is used to ensure both package.json AND package-lock.json are copied
     # where available (npm@5+)
     COPY package*.json ./
     RUN npm install
    
     # Bundle app source
     COPY . .
    
    
     RUN npm run build
    
     ###STAGE 2: Run ###
     FROM nginx:alpine
     RUN rm -rf /usr/share/nginx/html/* && rm -rf /etc/nginx/conf.d/default.conf && rm -rf /etc/nginx/nginx.conf
     COPY nginx.conf /etc/nginx
     COPY --from=build /app/dist/angular-frontend /usr/share/nginx/html
    
     #Optional to mention expose as it will be taken by nginx sever , port 80 wil be taken from nginx server
     EXPOSE 80
    
  3. sample nginx config file :

    worker_processes  1;
    events {
        worker_connections  1024;
    }
    http {
        #upstream local {
          #server localhost:5000;
        #}
    upstream backend {
      server backend-service:80;
    }
    server {
        listen 80;
    
        #server_name  localhost;
        server_name  backend-service;
        root   /usr/share/nginx/html;
        index  index.html index.htm;
        include /etc/nginx/mime.types;
        gzip on;
        gzip_min_length 1000;
        gzip_proxied expired no-cache no-store private auth;
        gzip_types text/plain text/css application/json application/javascript application/x-javascript text/xml application/xml application/xml+rss text/javascript;
    
        location / {
            try_files $uri $uri/ /index.html;
        }
    
        location /api/ {
            proxy_pass http://backend;
        }
    
        #location /api/v1/ {
            #proxy_pass http://local;
        #}
    
    }
    

    }

Note: This worked fine with k8s integration . But for local testing i used wsl2 in windows machine and and once replaced k8s backend-service config with localhost backend container . I got below error : *3 connect() failed (111: Connection refused) while connecting to upstream, client: 172.17.0.1,

I think there is an issue with wsl2 integration as mentioned here . https://github.com/Budibase/budibase/issues/4996

But works fine with k8s .

Upvotes: 3

Emre Odabaş
Emre Odabaş

Reputation: 499

As @Elgarni said, clients' browser could not access your cluster, so http://backend/api is not resolvable outside to cluster.
If you defined ingress, use kubectl get ingress command and learn your external IP. then replace your ${environment.apiUrl} to http://$EXTERNAL_IP/api/ or define DNS record for your external IP and reach via your defined domain.

Upvotes: 1

Elgarni
Elgarni

Reputation: 256

Look at the following:

outside world  | k8s cluster
               | 
Browser  -->   | Nginx-pod --> backend-pod
               |
               |

The url http://backend/api is only resolvable within the cluster, but your browser is in the outside world, so it does not know what this url is.

You ideally would use an ingress to manage routes to cluster pods.

Upvotes: 3

Related Questions