How I expose my applications on Kubernetes with Ingress and a domain
Tags: devops, kubernetes, gcp, beginners
Published: 2019-12-28 03:20:07

My intention of writing this post is to share with you things that I learned today and hope that might help some guy on the Internet just like me searching for a quick way to do something rather than reading a lot of dry text.

#Motivation
The demand emerges when there is a fact that I have multiple applications running on my Kubernetes cluster, I have only one domain though. That is where Kubernetes Ingress resource comes into play. 

#Prerequisites
For the sake of simplicity and focusing on Ingress resource, I will assume that you are familiar with Kubernetes resource objects like: Deployment, Service,... and having control over your cluster with **kubectl**.

#Let's do it
For demonstration purpose, I am going to spin up two applications,  **portfolio** and **healthinsight** respectively. To achieve that, I simply create two deployments with one replica each, and also two services in order to keep track of IP of the pods created and destroy frequently.
If not mentioned otherwise, all resources are deployed on **default** namespace.

Yaml file for **portfolio** app
```yaml
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: portfolio
  namespace: default
spec:
  selector:
    matchLabels:
      run: portfolio
  template:
    metadata:
      labels:
        run: portfolio
    spec:
      containers:
      - image: gcr.io/phuong-devops/portfolio:v2
        imagePullPolicy: IfNotPresent
        name: portfolio
        ports:
        - containerPort: 3000
          protocol: TCP
      imagePullSecrets:
      - name: gcr-key
---
apiVersion: v1
kind: Service
metadata:
  name: portfolio
  namespace: default
spec:
  ports:
  - port: 3000
    protocol: TCP
    targetPort: 3000
  selector:
    run: portfolio
  type: NodePort
```
YAML file for **healthinsight** app
```yaml
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: healthinsight-app
  namespace: default
spec:
  selector:
    matchLabels:
      run: healthinsight-app
  template:
    metadata:
      labels:
        run: healthinsight-app
    spec:
      containers:
        - image: gcr.io/phuong-devops/healthinsight-frontend:v1
          name: healthinsight-app
          ports:
            - containerPort: 80
              protocol: TCP
      imagePullSecrets:
        - name: gcr-key
---
apiVersion: v1
kind: Service
metadata:
  name: healthinsight-app
  namespace: default
spec:
  ports:
  - port: 3001
    protocol: TCP
    targetPort: 80
  selector:
    run: healthinsight-app
  type: NodePort
```

Deploying these two applications is easy as a piece of cake.

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/89pwc6m1i7zsipn78uhl.gif)

The problem is our application is unreachable from the external network (Internet), so I deploy an Ingress resource on our Kubernetes cluster so as to it routes the traffic from Internet to our pods (applications). 
*Keep in mind that you have to setup an Ingress Controller to satisfy Ingress Resource. Only creating Ingress Resource below has no effect.*

There are a bunch of Controller that may fit your preferences, take a look at [here](https://kubernetes.io/docs/concepts/services-networking/ingress-controllers/). For demonstration purpose, I will pick **Nginx Ingress Controller**, you could easily have your Nginx controller installed on your cluster after following the official documentation [here](https://kubernetes.github.io/ingress-nginx/)

###So what exactly Ingress do?

Ingress exposed HTTP and HTTPS routes from outside the cluster to services within cluster. Traffic routing is controlled by rules defined on the Ingress resource.

An Ingress can be configured to give Services externally-reachable URL, load balance, terminate SSL/TLS, and offer name based virtual hosting.

The below diagram illustrates our implementation.

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/9r2o9vqlakzmwyh0dwqr.png)

I am going to deploy our Ingress resource configured to satisfy above demand.

```yaml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  annotations:
    kubernetes.io/ingress.class: "nginx"
  name: cluster-ingress
  namespace: default
spec:
  rules:
  - host: hi.phuonghau.com
    http:
      paths:
      - backend:
          serviceName: healthinsight-app
          servicePort: 3001
  - host: phuonghau.com
    http:
      paths:
      - backend:
          serviceName: portfolio
          servicePort: 3000
```

Check out if our Ingress resource deployment works fine.

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/45emom63d9fcr0p43h79.gif)

###DNS
It is just not enough, we need to explicitly configure our domain DNS to navigate to our server cluster IP.

**Note**:
When we expose our applications on cluster on a domain name, we need the external IP address of an application to be static that does not change. So that the domain can correctly navigate to our clusters.

I am using GoDaddy for example, the steps are not the same if you are using other domain broker services, but the terms is applicable.

To reiterate, I want **phuonghau.com** to points to **portfolio** service and **hi.phuonghau.com** to point to **health insight** service.

Simply add an A record pointing to cluster IP (phuonghau.com points to clusterIP), and a CName *hi* points to phuonghau.com. Check the brief differences between an A record and Cname at [here](https://support.dnsimple.com/articles/differences-a-cname-records/)

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/im747lqn1otr8hnynlxb.png)
It could take couple of minutes for your DNS configuration propagate over global.

###Tadaaa
Now we can access multiple services on our Kubernetes cluster with only one domain.
![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/u6t8d1e7eunq0wxfz2st.gif)

#Conclusion
With Kubernetes Ingress we are able to expose many applications to outside  on the Internet with ease, those above steps is basically describe practical steps. The official document still the best place which we should take a glance at. Any feedback on this article is more than welcome.Thanks for reading.