EFK Stack: Enterprise-Grade Logging and Monitoring

Elasticsearch and Kibana Deployment on Kubernetes

Deploy Elasticsearch on Kubernetes

Welcome to this comprehensive lesson on deploying Elasticsearch on a Kubernetes cluster. In this guide, you'll learn how to set up the cluster, inspect configuration files, and deploy Elasticsearch with persistent storage.

Let’s get started!

Pre-deployment Setup

Before deploying the Elasticsearch cluster, execute a few preparatory commands. Start by tainting the control plane, creating a dedicated namespace called "efk", and setting the current context to that namespace. Then, clone the repository and navigate to the Elasticsearch/Kibana folder.

kubectl taint node controlplane node-role.kubernetes.io/control-plane-:NoSchedule
kubectl create namespace efk
kubectl config set-context --current --namespace=efk
# Context "kubernetes-admin@kubernetes" modified.
git clone https://github.com/kodekloudhub/efk-stack.git
# Cloning into 'efk-stack'...
cd /root/efk-stack/elasticsearch-kibana

Exploring the Repository Files

After navigating to the proper directory, list the available files to understand the repository structure. There are five configuration files present. The three critical files for Elasticsearch are:

  • es-statefulset.yaml (defines the StatefulSet)
  • es-service.yaml (defines the Service)
  • es-pvolume.yaml (defines the Persistent Volume)
ls -lrt
# total 4
cd efk-stack/
cd /root/efk-stack/elasticsearch-kibana

ls -lrt
# total 20
# -rw-r--r-- 1 root  root   184 Aug  6 14:18 kibana-service.yaml
# -rw-r--r-- 1 root  root   354 Aug  6 14:18 kibana-deployment.yaml
# -rw-r--r-- 1 root  root  1195 Aug  6 14:18 es-statefulset.yaml
# -rw-r--r-- 1 root  root   299 Aug  6 14:18 es-service.yaml
# -rw-r--r-- 1 root  root   185 Aug  6 14:18 es-pvolume.yaml

Inspecting the Elasticsearch StatefulSet

The es-statefulset.yaml file contains the configuration for the Elasticsearch StatefulSet. This file includes metadata, pod specifications, and the Docker image version (8.13.0). It exposes ports 9200 and 9300 and sets essential environment variables, such as running in single-node mode and disabling x-pack security for demonstration purposes.

selector:
  matchLabels:
    app: elasticsearch
template:
  metadata:
    labels:
      app: elasticsearch
  spec:
    containers:
    - name: elasticsearch
      image: docker.elastic.co/elasticsearch/elasticsearch:8.13.0
      ports:
      - containerPort: 9200
        name: port1
      - containerPort: 9300
        name: port2
      env:
      - name: discovery.type
        value: single-node
      - name: xpack.security.enabled
        value: "false"
      volumeMounts:
      - name: es-data
        mountPath: /usr/share/elasticsearch/data
    initContainers:
    - name: fix-permissions
      image: busybox
      command: ["sh", "-c", "chown -R 1000:1000 /usr/share/elasticsearch/data"]
      securityContext:
        privileged: true
      volumeMounts:
      - name: es-data
        mountPath: /usr/share/elasticsearch/data
    volumeClaimTemplates:
    - metadata:
        name: es-data
      spec:
        accessModes: ["ReadWriteOnce"]
        resources:
          requests:
            storage: 1Gi

Later in the same file, the persistent storage size is updated along with similar configurations. Note that the x-pack security is disabled, and the volume mount ensures persistent data storage across pod restarts.

metadata:
  labels:
    app: elasticsearch
spec:
  containers:
    - name: elasticsearch
      image: docker.elastic.co/elasticsearch/elasticsearch:8.13.0
      ports:
        - containerPort: 9200
          name: port1
        - containerPort: 9300
          name: port2
      env:
        - name: discovery.type
          value: single-node
        - name: xpack.security.enabled
          value: "false"
      volumeMounts:
        - name: es-data
          mountPath: /usr/share/elasticsearch/data
  initContainers:
    - name: fix-permissions
      image: busybox
      command: ["sh", "-c", "chown -R 1000:1000 /usr/share/elasticsearch/data"]
      securityContext:
        privileged: true
      volumeMounts:
        - name: es-data
          mountPath: /usr/share/elasticsearch/data
  volumeClaimTemplates:
    - metadata:
        name: es-data
      spec:
        accessModes: ["ReadWriteOnce"]
        resources:
          requests:
            storage: 5Gi

Note

For enhanced security in production environments, explore additional configuration options to enable robust authentication and secure data communication.

Volume Mount and Persistent Storage

The StatefulSet configures an "es-data" volume mount where Elasticsearch stores its data. This mount is defined via a Persistent Volume Claim, ensuring that data persists even if the pod is restarted or recreated.

metadata:
  labels:
    app: elasticsearch
spec:
  containers:
    - name: elasticsearch
      image: docker.elastic.co/elasticsearch/elasticsearch:8.13.0
      ports:
        - containerPort: 9200
          name: port1
        - containerPort: 9300
          name: port2
      env:
        - name: discovery.type
          value: single-node
        - name: xpack.security.enabled
          value: "false"
      volumeMounts:
        - name: es-data
          mountPath: /usr/share/elasticsearch/data
  initContainers:
    - name: fix-permissions
      image: busybox
      command: ["sh", "-c", "chown -R 1000:1000 /usr/share/elasticsearch/data"]
      securityContext:
        privileged: true
      volumeMounts:
        - name: es-data
          mountPath: /usr/share/elasticsearch/data
  volumeClaimTemplates:
    - metadata:
        name: es-data
      spec:
        accessModes: ["ReadWriteOnce"]
        resources:
          requests:
            storage: 5Gi

The Persistent Volume (defined in es-pvolume.yaml) is configured to use a hostPath at "/data/elasticsearch" with a storage capacity of 5Gi and access mode "ReadWriteOnce".

apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv-elasticsearch
spec:
  capacity:
    storage: 5Gi
  accessModes:
    - ReadWriteOnce
  hostPath:
    path: /data/elasticsearch

Defining the Elasticsearch Service

The es-service.yaml file defines the Elasticsearch Service, which exposes ports 9200 and 9300. It leverages NodePort and ensures consistent metadata with the StatefulSet for proper traffic routing.

apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv-elasticsearch
spec:
  capacity:
    storage: 5Gi
  accessModes:
    - ReadWriteOnce
  hostPath:
    path: /data/elasticsearch
---
apiVersion: v1
kind: Service
metadata:
  name: elasticsearch
  namespace: efk
spec:
  selector:
    app: elasticsearch
  ports:
  - port: 9200
    targetPort: 9200
    protocol: TCP
    name: http
  - port: 9300
    targetPort: 9300
    protocol: TCP
    name: nodePort

Deploying the Elasticsearch Stack

After reviewing all configuration files, deploy the Elasticsearch stack by applying the Persistent Volume, StatefulSet, and Service configurations. First, confirm that all necessary files are present:

# List the files to ensure they are present
ls -lrt
# total 20
# -rw-r--r--  1 root root  184 Aug  6 14:18 kibana-service.yaml
# -rw-r--r--  1 root root  354 Aug  6 14:18 kibana-deployment.yaml
# -rw-r--r--  1 root root 1195 Aug  6 14:18 es-statefulset.yaml
# -rw-r--r--  1 root root  209 Aug  6 14:18 es-service.yaml
# -rw-r--r--  1 root root  105 Aug  6 14:18 es-pvolume.yaml

Apply the configuration files with the following commands:

kubectl apply -f es-pvolume.yaml
kubectl apply -f es-statefulset.yaml
kubectl apply -f es-service.yaml
# service/elasticsearch created

Next, monitor the status of the Elasticsearch pod:

kubectl get pods
# NAME             READY   STATUS              RESTARTS   AGE
kubectl get pods -w
# NAME             READY   STATUS    RESTARTS   AGE
# elasticsearch-0  1/1     Running   0          52s

To further troubleshoot or verify logs, run:

kubectl logs -f <pod-name>

An example snippet from the Elasticsearch pod logs might be:

{"elasticsearch.cluster.name":"docker-cluster"}
{"@timestamp":"2024-08-06T14:26:59.586Z","log.level":"INFO","message":"loaded module [wildcard]","ecs.version":"1.2.0","service.name":"ES_ECS","event.dataset":"elasticsearch.server"}
...

If no errors are reported, Elasticsearch is running correctly.

Final Verification

Elasticsearch is now deployed in the "efk" namespace on Kubernetes. In the next lesson, we will deploy Kibana and demonstrate how to verify the Elasticsearch cluster status via the Kibana UI.

Thank you for following along. See you in the next lesson!

Watch Video

Watch video content

Practice Lab

Practice lab

Previous
Deploying Elasticsearch as a Cluster within Kubernetes