Friday, June 18, 2021

Kubernetes for Developers #17: Expose service using Kubernetes Ingress

In the previous article(Kubernetes for Developers #16: Kubernetes Service Types - ClusterIP, NodePort, LoadBalancer and ExternalName) we discussed “LoadBalancer” service type would be the most preferable technique to expose service outside the cluster. However, it requires one LoadBalancer per service with public IP address. It is cost inefficient if you have bunch of services needs to be exposed outside the cluster.

We can solve this problem by implementing single Kubernetes Ingress resource with multiple service mapping. 

K8 Ingress works based on URL based HTTP routing. So, we can map multiple services to multiple HTTP URLs. When a client sends an HTTP request to the Ingress, the URL host and path in the request determine which service the request is supposed to navigate.

Kubernetes Ingress configuration has two parts.

1. Ingress Resource: It is YAML manifest file which contain set of HTTP routing rules mapped to services

2. Ingress Controller: It is K8 Pod running inside the cluster. It is responsible to process Ingress Resource YAML file and route the request to appropriate service. Ingress controller Pods are not started automatically with a cluster. Different K8 environments use different implementations of the controller. 

Note: DNS name should resolve to the IP address of Ingress controller to access K8 service from the ingress controller.

As per diagram,
  • when you initiate a http call from the browser (i.e. shop.com/cart), it performs DNS lookup and returns a IP address of the Ingress controller. So, make sure that DNS name should map to IP address of the Ingress controller.
  • Browser sends HTTP request to the Ingress controller, it determines the service which is mapped to the given http URL based on HTTP headers
  • Ingress controller find the Pod IPs through Endpoints associated with the service
  • HTTP request will be forwarded to one of the Pod. 
  • Ingress controller uses the service to find Pod IPs, then the controller will process the request. 
Enable the Nginx Ingress controller

1. run the following kubectl command to enable Nginx Ingress controller on Docker Desktop

$ kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v0.47.0/deploy/static/provider/cloud/deploy.yaml


run the following command if you are using minikube
$ minikube addons enable ingress

2. run the following kubectl command to check the “ingress-nginx-controller” Pod running status

$ kubectl get pods -n ingress-nginx
NAME                                        READY   STATUS      RESTARTS   AGE
ingress-nginx-controller-84dcb9867d-dqc9h   1/1     Running     0          11h


Create Kubernetes Deployment

Before creating an Ingress, first create two different versions of helloworld app using K8 Deployment and service

apiVersionapps/v1
kindDeployment
metadata:
  namehello-v1-deployment
spec:
  replicas1
  selector:
    matchLabels:
      appv1-web
  template:
    metadata:
      labels:
        appv1-web
    spec:
      containers:
        - namehello-v1
          imagegcr.io/google-samples/hello-app:1.0
          ports:
            - containerPort8080
---
apiVersionv1
kindService
metadata:
  namehello-v1-service
spec:
  typeClusterIP
  selector:
    appv1-web
  ports:
    - protocolTCP
      port8080
      targetPort8080

// save above yaml manifest as hello-v1.yaml and run below command
$ kubectl apply -f hello-v1.yaml
deployment.apps/hello-v1-deployment created
service/hello-v1-service created


apiVersionapps/v1
kindDeployment
metadata:
  namehello-v2-deployment
spec:
  replicas1
  selector:
    matchLabels:
      appv2-web
  template:
    metadata:
      labels:
        appv2-web
    spec:
      containers:
        - namehello-v2
          imagegcr.io/google-samples/hello-app:2.0
          ports:
            - containerPort8080
---
apiVersionv1
kindService
metadata:
  namehello-v2-service
spec:
  typeClusterIP
  selector:
    appv2-web
  ports:
    - protocolTCP
      port8080
      targetPort8080



// save above yaml manifest as hello-v2.yaml and run below command
$ kubectl apply -f hello-v2.yaml
deployment.apps/hello-v2-deployment created
service/hello-v2-service created

Create an Ingress YAML manifest to expose multiple services on single host

apiVersionextensions/v1beta1
kindIngress
metadata:
  namehello-ingress
spec:
  rules:
    - hostshop.com
      http:
        paths:
          - path/product
            backend:
              serviceNamehello-v1-service
              servicePort8080
          - path/order
            backend:
              serviceNamehello-v2-service
              servicePort8080

// create an ingress resource
$ kubectl apply -f hello-ingress.yaml
ingress.extensions/hello-ingress created

// get an ingress details
$ kubectl get ingress
NAME            CLASS    HOSTS      ADDRESS     PORTS   AGE
hello-ingress   <none>   shop.com   localhost   80      73s

// open windows host file (C:\Windows\System32\drivers\etc) and map shop.com to localhost
127.0.0.1 shop.com

// make curl command to shop.com/product to get hello-v1 app details
$ curl shop.com/product
Hello, world!
Version: 1.0.0
Hostname: hello-v1-deployment-855c95579b-d99pp

// make curl command to shop.com/order to get hello-v2 app details
$ curl shop.com/order
Hello, world!
Version: 2.0.0
Hostname: hello-v2-deployment-5fc58f68df-hwgxx


Create an Ingress YAML manifest to expose multiple services on sub domains
apiVersionextensions/v1beta1
kindIngress
metadata:
  namehello-ingress
spec:
  rules:
    - hostproduct.shop.com
      http:
        paths:
          - path/
            backend:
              serviceNamehello-v1-service
              servicePort8080
    - hostorder.shop.com
      http:
        paths:
          - path/
            backend:
              serviceNamehello-v2-service
              servicePort8080


// create an ingress resource to map multiple sub domains
$ kubectl apply -f hello-multi-domain-ingress.yaml
ingress.extensions/hello-ingress created

// get an ingress details
$ kubectl get ingress
NAME            CLASS    HOSTS                             ADDRESS   PORTS   AGE
hello-ingress   <none>   product.shop.com,order.shop.com             80      6s

// open windows host file (C:\Windows\System32\drivers\etc) and map shop.com to localhost
127.0.0.1 product.shop.com
127.0.0.1 order.shop.com

// make curl command to product.shop.com to get hello-v1 app details
$ curl product.shop.com
Hello, world!
Version: 1.0.0
Hostname: hello-v1-deployment-855c95579b-d99pp

// make curl command to order.shop.com to get hello-v2 app details
$ curl order.shop.com
Hello, world!
Version: 2.0.0
Hostname: hello-v2-deployment-5fc58f68df-hwgxx

Kubernetes for Developers Journey.

Happy Coding :)

No comments:

Post a Comment