Use Traefik as a Kubernetes Ingress Controller for your App on Civo

In the previous tutorial I showed you how to provision a Kubernetes Cluster on Civo.

In this tutorial we will deploy a application to our Kubernetes cluster which will be using Traefik that is installed by default onto your Cluster.

Traefik

Traefik is a super awesome and modern reverse proxy for microservices. By default Traefik get's installed onto your cluster which listens on port 80 and 443. Therefore we can deploy a web application to our cluster and deploy a ingress controller that will reverse proxy our connection from port 80 on the load balancer to the port of our container.

Demo Application

I have a demo application that will return the hostname of the container that will answer the request available at ruanbekker/hostname which is a golang application that is on docker hub.

Deploy the Demo

The manifest that contains a service, ingress and a deployment is available here. We will need the DNS endpoint that Civo provisioned for us that we will provide in our Ingress, which you can obtain using:

$ civo kubernetes show ${your_cluster_name} | grep 'DNS'
DNS A record : 7d91b88e-5b83-4444-a253-3a0c07b3408b.k8s.civo.com

Let's break up our manifest, the first part is our service:

apiVersion: v1
kind: Service
metadata:
  name: hostname-service
spec:
  selector:
    app: traefik
  ports:
    - protocol: TCP
      port: 80
      targetPort: 8000
      name: web

Then we have our ingress where we will need to provide our unique DNS endpoint, and as you can see we are specifying port 80 that it will associate to on our service that we also specified from our previous section:

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: hostname-ingress
  annotations:
    kubernetes.io/ingress.class: traefik
spec:
  rules:
  - host: your-unique-id.k8s.civo.com
    http:
      paths:
      - backend:
          serviceName: hostname-service
          servicePort: 80

The last section is our deployment, where we will specify our docker image, and how our deployment will look like, 1 replica, update strategy etc:

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  labels:
    app: traefik
  name: hostname
spec:
  replicas: 1
  selector:
    matchLabels:
      app: traefik
  strategy:
    rollingUpdate:
      maxSurge: 25%
      maxUnavailable: 25%
    type: RollingUpdate
  template:
    metadata:
      creationTimestamp: null
      labels:
        app: traefik
    spec:
      containers:
      - name: hostname-app
        image: ruanbekker/hostname:latest
        imagePullPolicy: IfNotPresent
        livenessProbe:
          failureThreshold: 3
          httpGet:
            path: /
            port: 8000
            scheme: HTTP
          initialDelaySeconds: 10
          periodSeconds: 10
          successThreshold: 1
          timeoutSeconds: 2
        ports:
        - containerPort: 8000
          name: http
          protocol: TCP
        readinessProbe:
          failureThreshold: 1
          httpGet:
            path: /
            port: 8000
            scheme: HTTP
          initialDelaySeconds: 10
          periodSeconds: 10
          successThreshold: 1
          timeoutSeconds: 2
        resources: {}
      dnsPolicy: ClusterFirst
      restartPolicy: Always
      schedulerName: default-scheduler
      terminationGracePeriodSeconds: 30

Once we have everything saved to disk, we can apply the deployment:

$ kubectl apply -f app.yaml
service/hostname-service created
ingress.extensions/hostname-ingress created
deployment.extensions/hostname created

View your Resources

Use kubectl to view all your resources:

$ kubectl get all
NAME                            READY   STATUS    RESTARTS   AGE
pod/hostname-77cbd5d4b9-xvn58   1/1     Running   0          43s

NAME                       TYPE        CLUSTER-IP        EXTERNAL-IP   PORT(S)   AGE
service/hostname-service   ClusterIP   192.168.199.215   <none>        80/TCP    44s
service/kubernetes         ClusterIP   192.168.128.1     <none>        443/TCP   54m

NAME                       READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/hostname   1/1     1            1           43s

NAME                                  DESIRED   CURRENT   READY   AGE
replicaset.apps/hostname-77cbd5d4b9   1         1         1       44s

As you can see our application is running with one pod, test the application by making a HTTP request to your custom DNS name, and you should see the pod name being returned:

$ curl http://7d91b88e-5b83-4444-a253-3a0c07b3408b.k8s.civo.com
Hostname: hostname-77cbd5d4b9-xvn58

Scale your Deployment:

As you can see we only have one replica in our deployment, scale your deployment to 3 replicas:

$ kubectl scale deployment.apps/hostname --replicas 3
deployment.apps/hostname scaled

View your pods:

$ kubectl get pods
NAME                        READY   STATUS    RESTARTS   AGE
hostname-77cbd5d4b9-n2pp6   1/1     Running   0          22s
hostname-77cbd5d4b9-nbdqw   1/1     Running   0          22s
hostname-77cbd5d4b9-xvn58   1/1     Running   0          5m15s

As all three pods are running, we can make three HTTP requests, and those requests will be round robin'd to each pod:

$ curl http://7d91b88e-5b83-4444-a253-3a0c07b3408b.k8s.civo.com
Hostname: hostname-77cbd5d4b9-n2pp6

$ curl http://7d91b88e-5b83-4444-a253-3a0c07b3408b.k8s.civo.com
Hostname: hostname-77cbd5d4b9-nbdqw

$ curl http://7d91b88e-5b83-4444-a253-3a0c07b3408b.k8s.civo.com
Hostname: hostname-77cbd5d4b9-xvn58

Pretty sweet right!

This is all for now, until next time!