ELK on Kubernetes with Helm Charts


This post explains how to setup an ELK (Elasticsearch, Logstash, and Kibana) stack on Kubernetes using Helm Charts. We will first, setup Kubernetes cluster on Google Cloud using GKE, then install on it all the components of ELK using Helm Charts.

Setup

Setting up a k8s cluster on Google Cloud is fairly easy, we just need to follow the official documentation.

First, let’s set some global environment variables:

$ LOCATION=us-central1-a
$ CLUSTER_NAME=kubetest

By default GKE will create a k8s cluster with nodes having machine type e2-medium which is a medium-sized instance with 2 vCPUs and 4 GB of memory. We need instead to use a machine with more Memory. We can list the machine types available as follows:

$ gcloud compute machine-types list --filter="$LOCATION"

Pick a machine type with enough memory then start GKE cluster as follows:

$ gcloud container clusters create $CLUSTER_NAME \
  --zone $LOCATION \
  --node-locations $LOCATION \
  --machine-type e2-standard-4

This will create GKE cluster

NAME      LOCATION       MASTER_VERSION      MASTER_IP     MACHINE_TYPE   NODE_VERSION        NUM_NODES  STATUS
kubetest  us-central1-a  1.28.8-gke.1095000  34.72.13.154  e2-standard-4  1.28.8-gke.1095000  3          RUNNING

Later to delete the cluster, we can simply do:

$ gcloud container clusters delete $CLUSTER_NAME --location $LOCATION

Deploy with Helm Charts

In this section, we will dive in details how to deploy the different components of our ELK stack on Kubernetes using Helm charts. Before going any further, it’s important to ensure that you have Helm installed on your local machine. For details on how to install Helm on your operating system refer to the documentation.

Add Elastic Helm Charts Repository: Elastic offers official Helm charts for deploying the ELK stack components. By adding the Elastic Helm repository to your Helm configuration, you attain access to these charts.

$ helm repo add elastic https://helm.elastic.co
"elastic" has been added to your repositories

$ helm repo update
Hang tight while we grab the latest from your chart repositories...
...Successfully got an update from the "elastic" chart repository
Update Complete. ⎈Happy Helming!⎈

Create a k8s namespace where the ELK stack will be installed

$ kubectl create namespace monit
namespace/monit created

Elasticsearch

Elasticsearch is the core of the ELK stack, responsible for storing and indexing log data. When installing Elasticsearch with Helm, you can customize parameters such as the number of replicas (for high availability) and JVM heap size using Helm chart values.

$ helm install elasticsearch elastic/elasticsearch \
  --namespace monit \
  --set replicas=3 \
  --set esJavaOpts="-Xmx512m -Xms512m"

Watch all cluster members come up.

$ kubectl get pods --namespace=monit -l app=elasticsearch-master -w

After few minutes the different replicates will be ready and the Elasticsearch cluster properly running

NAME                     READY   STATUS    RESTARTS   AGE
elasticsearch-master-0   1/1     Running   0          9m20s
elasticsearch-master-1   1/1     Running   0          9m20s
elasticsearch-master-2   1/1     Running   0          9m20s
$ kubectl describe pod elasticsearch-master-0 -n monit
Events:
  Type     Reason                  Age                From                     Message
  ----     ------                  ----               ----                     -------
  Normal   Scheduled               17m                default-scheduler        Successfully assigned monit/elasticsearch-master-0 to gke-kubetest-default-pool-ddfd6147-mqrr
  Normal   SuccessfulAttachVolume  17m                attachdetach-controller  AttachVolume.Attach succeeded for volume "pvc-b3137a25-241c-4337-89c1-d6e3953440fe"
  Normal   Pulling                 17m                kubelet                  Pulling image "docker.elastic.co/elasticsearch/elasticsearch:8.5.1"
  Normal   Pulled                  17m                kubelet                  Successfully pulled image "docker.elastic.co/elasticsearch/elasticsearch:8.5.1" in 19.341s (19.341s including waiting)
  Normal   Created                 17m                kubelet                  Created container configure-sysctl
  Normal   Started                 17m                kubelet                  Started container configure-sysctl
  Normal   Pulled                  16m                kubelet                  Container image "docker.elastic.co/elasticsearch/elasticsearch:8.5.1" already present on machine
  Normal   Created                 16m                kubelet                  Created container elasticsearch
  Normal   Started                 16m                kubelet                  Started container elasticsearch
  Warning  Unhealthy               15m (x6 over 16m)  kubelet                  Readiness probe failed: Waiting for elasticsearch cluster to become ready (request params: "wait_for_status=green&timeout=1s" )
Cluster is not yet ready (request params: "wait_for_status=green&timeout=1s" )

Check cluster health using helm test:

$ helm --namespace=monit test elasticsearch
NAME: elasticsearch
LAST DEPLOYED: Tue May 28 11:53:00 2024
NAMESPACE: monit
STATUS: deployed
REVISION: 1
TEST SUITE:     elasticsearch-qsmth-test
Last Started:   Tue May 28 12:05:09 2024
Last Completed: Tue May 28 12:05:12 2024
Phase:          Succeeded

To access our Elasticsearch instance, we need to retrieve the credentials:

Retrieve elastic user’s username.

$ kubectl get secrets --namespace=monit elasticsearch-master-credentials -ojsonpath='{.data.username}' | base64 -d

Retrieve elastic user’s password.

$ kubectl get secrets --namespace=monit elasticsearch-master-credentials -ojsonpath='{.data.password}' | base64 -d

Kibana

Kibana is the visualization and dashboarding component of the ELK stack. It offers a user-friendly interface for exploring and analyzing log data stored in Elasticsearch. By installing Kibana with Helm, you can quickly deploy and configure it to connect to your Elasticsearch cluster.

$ helm install kibana elastic/kibana --namespace monit

Watch for all containers to come up:

$ kubectl get pods --namespace=monit -l release=kibana -w

Ater few seconds, Kibana will be ready

NAME                             READY   STATUS    RESTARTS   AGE
kibana-kibana-8446b87c9f-2vh8g   1/1     Running   0          76s

Check the k8s service for Kibana

$ kubectl get svc --namespace=monit -l release=kibana 
NAME            TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)    AGE
kibana-kibana   ClusterIP   10.30.38.169   <none>        5601/TCP   14m

Retrieve the kibana service account token.

$ kubectl get secrets --namespace=monit kibana-kibana-es-token -ojsonpath='{.data.token}' | base64 -d

Access Kibana

We may need to configure an Ingress to access Kibana. Otherwise, we can quickly access Kibana by using port-forwarding:

$ kubectl port-forward service/kibana-kibana :5601 --namespace monit
Forwarding from 127.0.0.1:51850 -> 5601
Forwarding from [::1]:51850 -> 5601

Then, open http://localhost:51850 in your web browser.

Logstash

Logstash is an optional component used for log ingestion, processing, and enrichment. If you have specific log processing requirements, such as parsing structured logs or applying filters, you can install Logstash using the Elastic Helm chart.

$ helm install logstash elastic/logstash --namespace monit

Check that the cluster members are up:

$ kubectl get pods --namespace=monit -l app=logstash-logstash -w

After few seconds, the logstash container will become ready:

NAME                  READY   STATUS    RESTARTS   AGE
logstash-logstash-0   1/1     Running   0          2m17s

Next steps

Once the different components of the ELK stack are properly installed, you can explore the following tasks:

That’s all folks

I hope you enjoyed this article, feel free to leave a comment or reach out on twitter @bachiirc.