Unable to connect to api server of react js app using kubernetes?

7/30/2019

I am basically trying to run a react js app which is mainly composed of 3 services namely postgres db, API server and UI frontend(served using nginx).Currently the app works as expected in the development mode using docker-compose but when i tried to run this in the production using kubernetes,I was not able to access the api server of the app(CONNECTION REFUSED).

Since I want to run in this in production using kubernetes, I created yaml files for each of the services and then tried running them using kubectl apply.I have also tried this with and without using the persistent volume for the api server.But none of this helped.

Docker-compose file(This works and i am able to connect to api server at port 8000)

version: "3"

services:
  pg_db:
    image: postgres
    networks: 
      - wootzinternal
    ports:
      - 5432
    environment:
      - POSTGRES_PASSWORD=password
      - POSTGRES_USER=postgres
      - POSTGRES_DB=wootz
    volumes:
      - wootz-db:/var/lib/postgresql/data
  apiserver:
    image: wootz-backend
    volumes:
      - ./api:/usr/src/app
      - /usr/src/app/node_modules
    build:
      context: ./api
      dockerfile: Dockerfile
    networks: 
      - wootzinternal
    depends_on:
      - pg_db
    ports:
      -  '8000:8000'
  ui:
    image: wootz-frontend
    volumes:
      - ./client:/usr/src/app
      - /usr/src/app/build
      - /usr/src/app/node_modules
    build:
      context: ./client
      dockerfile: Dockerfile
    networks:
      - wootzinternal
    ports:
      - '80:3000'

volumes:
  wootz-db:

networks:
  wootzinternal:
    driver: bridge

My api server yaml for running in kubernetes(This doesn't work and I cant connect to the api server at port 8000)

apiVersion: v1
kind: Service
metadata:
  name: apiserver
  labels:
    app: apiserver
spec:

  ports:
  - name: apiport
    port: 8000
    targetPort: 8000

  selector:
    app: apiserver
    tier: backend    

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: apiserver
  labels:
    app: apiserver
spec:
  selector:
    matchLabels:
      app: apiserver
      tier: backend
  strategy:
    type: Recreate
  template:
    metadata:
      labels:
        app: apiserver
        tier: backend
    spec:

      containers:
      - image: suji165475/devops-sample:corspackedapi
        name: apiserver
        env:
        - name: POSTGRES_DB_USER
          value: postgres
        - name: POSTGRES_DB_PASSWORD
          value: password
        - name: POSTGRES_DB_HOST
          value: postgres
        - name: POSTGRES_DB_PORT
          value: "5432"
        ports:
        - containerPort: 8000
          name: myport

What changes should I make to my api server yaml(kubernetes). so that I can access it on port 8000. Currently I am getting a connection refused error.

-- Vignesh Swaminathan
docker
kubernetes
reactjs

2 Answers

7/30/2019

The default service on Kubernetes is ClusterIP that is used to have service inside the cluster but not having that exposed to outside.

That is your service using the LoadBalancer type:

apiVersion: v1
kind: Service
metadata:
  name: apiserver
  labels:
    app: apiserver
spec:
  type: LoadBalancer
  ports:
  - name: apiport
    port: 8000
    targetPort: 8000
  selector:
    app: apiserver
    tier: backend

With that, you can see how the service expects to have an external IP address by running kubectl describe service apiserver

In case you want to have more control of how your requests are routed to that service you can add an Ingress in front of that same service.

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  labels:
    app: apiserver
  name: apiserver
spec:
  rules:
  - host: apiserver.example.com
    http:
      paths:
      - backend:
          serviceName: apiserver
          servicePort: 8000
        path: /*
-- wolmi
Source: StackOverflow

7/30/2019

Your service in only exposed over the internal kubernetes network.

This is because if you do not specify a spec.serviceType, the default is ClusterIP.

To expose your application you can follow at least 3 ways:

  • LoadBalancer: you can specify a spec.serviceType: LoadBalancer. A Load Balancer service expose your application on the (public) network. This work great if your cluster is a cloud service (gke, digital ocean, aks, azure, ...), the cloud will take care of providing you the public ip and routing the network traffic to all your nodes. Usually this is not the best method because a cloud Load balancer has a cost (depends on the cloud) and if you need to expose a lot of services the situation could become difficult to be maintained.

  • NodePort: you can specify a spec.serviceType: NodePort. Exposes the Service on each Node’s IP at a static port (the NodePort). You’ll be able to contact the service, from outside the cluster, by requesting <NodeIP>:<NodePort>.

  • Ingress: Ingress exposes HTTP and HTTPS routes from outside the cluster to services within the cluster. Traffic routing is controlled by rules defined on the Ingress resource. This is the most common scenario for simple http/https application. It allow you to easily manage ssl termination and routing. You need to deploy an ingress controller to make this work, like a simple nginx. All the main cloud can do this for you with a simple setting when you create the cluster

Read here for more information about services

Read here for more information about ingress

-- Federico Bevione
Source: StackOverflow