How to install and run Gatus for health check monitoring in Kubernetes

Gatus is a health dashboard that gives you the ability to monitor your services using HTTP, ICMP, TCP, and even DNS queries as well as evaluate the result of said queries by using a list of conditions on values like the status code, the response time, the certificate expiration, the body and many others. The icing on top is that each of these health checks can be paired with alerting via Slack, PagerDuty, Discord, Twilio and more.

In this guide, we will configure Gatus as a health dashboard tool using Kubernetes.

Checkout How to install and configure Gatus for health check monitoring Using Docker Compose.

Prerequisites

  • You have a cluster running with access to create resources
  • You have kubectl installed locally

I assume that you have a kubernetes cluster up and running with kubectl setup on your workstation. If not please checkout these guides:

Latest Gatus is available as a docker image in its official docker hub account. We will use that image for the setup.

Setting up Kubernetes Manifests

Once you have the prerequisites in place, we can create kubernetes resource manifests.

Namespace

In Kubernetes, a namespace provides a mechanism for isolating groups of resources within a single cluster. Names of resources need to be unique within a namespace, but not across namespaces. Namespace-based scoping is applicable only for namespaced objects (e.g. Deployments, Services, etc) and not for cluster-wide objects (e.g. StorageClass, Nodes, PersistentVolumes, etc).

Let us create a namespace for our gatus resources. Save the following in namespace.yaml:

---
apiVersion: v1
kind: Namespace
metadata:
  name: gatus

Then execute the following command to create a new namespace named gatus.

kubectl apply -f namespace.yaml

Create a Config Map To Externalize Gatus Configurations

All configurations for Gatus are part ofconfig.yaml file that defines the endpoints to be monitored and the alert channels. This config file will be specified when starting the application.

A ConfigMap is an API object used to store non-confidential data in key-value pairs. Pods can consume ConfigMaps as environment variables, command-line arguments, or as configuration files in a volume. We sill specify our configfile map as a configmap and pass to the deployment as a configuration file in volume.

Create a file called config-map.yaml and add the following file contents:

apiVersion: v1
kind: ConfigMap
metadata:
  labels:
    app.kubernetes.io/instance: gatus
    app.kubernetes.io/name: gatus
  name: gatus-config
data:
  config.yaml: |-
    alerting:
      slack:
        webhook-url: "https://hooks.slack.com/services/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"
        default-alert:
          enabled: true
          description: "Health check failed"
          send-on-resolved: true
          failure-threshold: 3
          success-threshold: 2

    endpoints:
    - name: Application One
      url: https://app-one.citizix.co/healthz
      interval: 30s
      conditions:
        - "[STATUS] == 200"
        - "[RESPONSE_TIME] < 1000"
      alerts:
      - type: slack
        failure-threshold: 3
        success-threshold: 2

    - name: Application Two
      url: https://app-two.citizix.co/healthz
      interval: 30s
      conditions:
        - "[STATUS] == 200"
        - "[RESPONSE_TIME] < 1000"
      alerts:
      - type: slack
        failure-threshold: 3
        success-threshold: 2

    storage:
      type: postgres
      path: "postgres://user:password@db0.dbs.com:5432/gatus?sslmode=disable"

In the above defined configurations, we are defining slack webhook for alert notifications when thresholds defined trigger an error. We are also defining two endpoints for app one and app two. Finally we are persisting the data in postgres.

Execute the following command to create the config map in Kubernetes.

kubectl create -f config-map.yaml

Create a Gatus Deployment

Deployment provides declarative updates for Pods and ReplicaSets. You describe a desired state in a Deployment, and the Deployment Controller changes the actual state to the desired state at a controlled rate. You can define Deployments to create new ReplicaSets, or to remove existing Deployments and adopt all their resources with new Deployments.

In our case, we will use the docker-hub provided image and mounting the predefined configmap as a volume mounted in /config.

Save the following content to deployment.yaml.

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: gatus
  labels:
    app: gatus
spec:
  replicas: 1
  selector:
    matchLabels:
      app: gatus
  template:
    metadata:
      labels:
        app: gatus
    spec:
      containers:
      - name: gatus
        image: twinproduction/gatus:latest
        ports:
        - containerPort: 8080
          name: http
          protocol: TCP
        volumeMounts:
        - name: gatus-config
          mountPath: /config
      volumes:
      - name: gatus-config
        configMap:
          defaultMode: 420
          name: gatus-config

Create a deployment on monitoring namespace using the above file.

kubectl create -f deployment.yaml 

You can check the created deployment using the following command.

kubectl get deployments --namespace=gatus
kubectl get pods --namespace=gatus

Connecting To Gatus Dashboard

You can view the deployed Gatus dashboard in three different ways.

  1. Using Kubectl port forwarding
  2. Exposing the Gatus deployment as a service with NodePort or a Load Balancer.
  3. Adding an Ingress object if you have an Ingress controller deployed.

Using Kubectl port forwarding

Using kubectl port forwarding, you can access a pod from your local workstation using a selected port on your localhost. This method is primarily used for debugging purposes.

First, get the Gatus pod name.

kubectl get pods --namespace=gatus

The output will look like the following.

➜ kubectl get pods --namespace=gatus
NAME                   READY   STATUS    RESTARTS   AGE
gatus-b8895b7b-bpmfn   1/1     Running   0          30m

Execute the following command with your pod name to access Gatus from localhost port 8080.

Note: Replace gatus-b8895b7b-bpmfn with your pod name.

kubectl port-forward gatus-b8895b7b-bpmfn 8080:8080 -n gatus

Now, if you access http://localhost:8080 on your browser, you will get the Gatus home page.

Exposing Gatus as a Service [NodePort & LoadBalancer]

To access the Gatus dashboard over a IP or a DNS name, you need to expose it as a Kubernetes service.

Create a file namedservice.yaml and copy the following contents. We will expose Gatus on all kubernetes node IP’s on port 40000.

Note: If you are on AWS, Azure, or Google Cloud, You can use Loadbalancer type, which will create a load balancer and automatically points it to the Kubernetes service endpoint.

---
apiVersion: v1
kind: Service
metadata:
  name: gatus
  labels:
    app: gatus
    namespace: gatus
spec:
  selector:
    app: gatus
  type: NodePort
  ports:
    - name: gatus
      protocol: TCP
      port: 8080
      targetPort: http
      nodePort: 40000

Create the service using the following command.

kubectl create -f service.yaml --namespace=gatus

Once created, you can access the Gatus dashboard using any of the Kubernetes nodes IP on port 40000. If you are on the cloud, make sure you have the right firewall rules to access port 40000 from your workstation.

Exposing Gatus Using Ingress

If you have an existing ingress controller setup, you can create an ingress object to route the Gatus DNS to the Gatus backend service.

Also, you can add SSL for Gatus in the ingress layer. You can refer to the Kubernetes ingress TLS/SSL Certificate guide for more details.

Here is a sample ingress object.

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    kubernetes.io/ingress.class: nginx
  labels:
    app.kubernetes.io/instance: gatus
    app.kubernetes.io/name: gatus
  name: gatus
  namespace: gatus
spec:
  rules:
  - host: gatus.citizix.com
    http:
      paths:
      - backend:
          service:
            name: gatus
            port:
              number: 8080
        path: /
        pathType: ImplementationSpecific

Using Kustomize

Kustomize introduces a template-free way to customize application configuration that simplifies the use of off-the-shelf applications. Now, built into kubectl as apply -k.

In our case, to avoid multiple kubectl apply -f <filename> we can use kustomize to define all the resources then apply as one. Save the following as kustomization.yaml.

---
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

namespace: gatus

resources:
  - namespace.yaml
  - configmap.yaml
  - deployment.yaml
  - service.yaml
  - ingress.yaml

Then apply using this command:

➜ kubectl apply -k .
namespace/gatus unchanged
configmap/gatus-config unchanged
service/gatus unchanged
deployment.apps/gatus unchanged
ingress.networking.k8s.io/gatus unchanged

Conclusion

In this article, we learnt how to set up Gatus on Kubernetes.

comments powered by Disqus
Built with Hugo
Theme Stack designed by Jimmy