Frontend can't resolve backend name within k8s cluster

10/15/2020

I'm trying to deploy a simple Angular/Express app on GKE and the http requests from the frontend can't find the name of the express app.

Here's an example of one get requests. I changed the request from 'localhost' to 'express' because that is the name of the clusterIP service setup in the cluster. Also, I'm able to curl this url from the angular pod and get json returned as expected.

getPups(){
    this.http.get<{message:string, pups: any}>("http://express:3000/pups")
    .pipe(map((pupData)=>{
        return pupData.pups.map(pup=>{
            return{
                name: pup.name, 
                breed: pup.breed, 
                quote: pup.quote, 
                id: pup._id, 
                imagePath: pup.imagePath, 
                rates: pup.rates
            }
        }); 
    }))
    
    .subscribe((transformedPups)=>{
        this.pups = transformedPups
        this.pupsUpdated.next([...this.pups])
     
    }); 
}

Here's the angular deployment.

apiVersion: apps/v1
kind: Deployment
metadata: 
  name: puprate-deployment
spec: 
  replicas: 1
  selector: 
    matchLabels: 
      component: web
  template: 
    metadata: 
      labels: 
        component: web
    spec: 
      containers: 
        - name: puprate
          image: brandonjones085/puprate
          ports: 
            - containerPort: 4200

---
apiVersion: v1
kind: Service
metadata: 
  name: puprate-cluster-ip-service
spec: 
  type: ClusterIP
  selector: 
    component: web
  ports: 
    - port: 4200
      targetPort: 4200

And the express deployment.

apiVersion: apps/v1
kind: Deployment
metadata: 
  name: express
spec: 
  replicas: 3
  selector: 
    matchLabels: 
      component: server
  template: 
    metadata: 
      labels: 
        component: server
    spec: 
      containers: 
        - name: server
          image: brandonjones085/puprate-express
          ports: 
            - containerPort: 3000


---
apiVersion: v1
kind: Service
metadata: 
  name: express
spec: 
  type: ClusterIP
  selector: 
    component: server
  ports: 
    - port: 3000
      targetPort: 3000
-- Brandon Jones
angularjs
containers
express
kubernetes

2 Answers

10/15/2020

Your frontend app is making the call from outside your cluster, and therefor needs a way to reach it. Because you are serving http, the best way to set that up will be with an ingress.

First, make sure you have an ingress controller set up in your cluster ( e.g. nginx ingress controller) https://kubernetes.github.io/ingress-nginx/deploy/#gce-gke

Then, set up your express with a service (from your question, I see you already have that set up on port 3000, that's good, though in the service I recommend to change the port to 80 - though not critical)

With that, set up your ingress:

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: express
spec:
  rules:
  - host: <a domain you own>
    http:
      paths:
      # NOTICE!! have you express app listen for that path, or set up nginx rewrite rules (I recommend the former, it's much easier to understand)
      - path: /api
        backend:
          serviceName: express
          servicePort: 3000 # or 80 if you decide to change that

Do the same for your web deployment, so you can serve your frontend directly:

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: web
spec:
  rules:
  - host: <a domain you own>
    http:
      paths:
      - path: /
        backend:
          serviceName: web
          servicePort: 4200 # or 80 if you decide to change that

Notice that both ingresses are using the same host but different paths - that's important for what's coming next

in your angular app, change that:

this.http.get<{message:string, pups: any}>("http://express:3000/pups")

to that:

this.http.get<{message:string, pups: any}>("/api/pups")

Browsers will parse that to <domain in your address bar>/api/pups

Since you are using GKE, when you set up the ingress controller you will generate a load balancer in the google cloud - make sure that <domain you own> has a DNS entry that directs there.

I'm assuming you already own a domain, but if you don't yet, just add the ip you got to your personal hosts file until you get one like so:

<ip of load balancer> <domain you want>
# for example
45.210.10.15 awesome-domain.com

So now, use the browser to go to the domain you own - you should get the frontend served to you - and since you are calling your api with an address that starts with /, your api call will go to the same host, and redirected by your ingress to your express app this time, instead of the frontend server.

-- Tom Klino
Source: StackOverflow

10/15/2020

Angular is running in your browser, not in the pod inside the cluster. The requests will originate therefore externally and the URL must point to the Ingress or LoadBalancer of your backend service.

-- Thomas
Source: StackOverflow