Sitemap
SagarChoudhary

SagarChoudhary

CKA Certified | AWS Certified Solution Architect Associate | Certified Terraform Associate | DevOps

Deploying EFK Stack on Kubernetes using ArgoCD: A Complete Guide

4 min readApr 28, 2025

--

Press enter or click to view image in full size

Introduction

“In a Kubernetes world where hundreds of pods are running, centralized logging becomes essential. In this blog, I’ll walk you through setting up a robust EFK (Elasticsearch, Filebeat, Logstash, Kibana) stack on Kubernetes.”

Why Not Just Prometheus and Grafana? Why EFK?

You might wonder — “We already have Grafana and Prometheus for monitoring in Kubernetes. Why do we need EFK?”

The answer is simple: they solve different problems.

  • Prometheus + Grafana are primarily for metrics — numbers like CPU usage, memory consumption, request counts, and system health over time.
  • EFK (Elasticsearch + Filebeat + Kibana) is for logs — actual text logs generated by your applications and pods, which help you troubleshoot and debug issues.
  • Prometheus tells you that something is wrong.
  • EFK tells you why it is wrong.
Press enter or click to view image in full size

Architecture Diagram

Press enter or click to view image in full size

📄Filebeat

Purpose:

  • Filebeat is a lightweight log shipper.
  • It runs as a DaemonSet on every Kubernetes node, reading log files from pods.
  • It collects these logs and forwards them to Logstash (or directly to Elasticsearch if Logstash is not used).

Why Filebeat?

  • Very lightweight and efficient.
  • Designed for shipping logs with minimal CPU and memory overhead.

🔄 Logstash

Purpose:

  • Logstash processes and transforms logs before sending them to Elasticsearch.
  • It can filter, enrich, parse, and reformat log data.
  • Acts as a powerful middle layer between Filebeat and Elasticsearch.

Why Logstash?

  • Allows complex processing (like JSON parsing, masking sensitive data, adding fields).
  • Supports building custom pipelines to make logs structured and easier to search.

📚 Elasticsearch

Purpose:

  • Elasticsearch is a distributed search and analytics engine.
  • It stores logs and provides fast searching, aggregation, and querying capabilities.

Why Elasticsearch?

  • Scalable and powerful for large volumes of logs.
  • Enables quick retrieval and filtering of log data.

📊 Kibana

Purpose:

  • Kibana provides a visual dashboard to explore, analyze, and visualize the log data stored in Elasticsearch.
  • Users can create charts, graphs, and custom dashboards based on log queries.

Why Kibana?

  • Makes logs human-friendly.
  • Provides visual insights and helps troubleshoot issues with beautiful dashboards and searches.

Step 1: Create secrets

apiVersion: v1
data:
password: your_password_in_base_64
username: your_password_in_base_64 (defalut elastic)
kind: Secret
metadata:
name: elasticsearch-master-new-credentials
namespace: efk
type: Opaque

Step 2: Setup the filebeats

Get SagarChoudhary’s stories in your inbox

Join Medium for free to get updates from this writer.

below this the applicationset.yaml

apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: efk-filebeat
namespace: argocd
spec:
generators:
- list:
elements:
- name: filebeat
namespace: efk
chart: filebeat
version: 8.5.1
path: filebeat
template:
metadata:
name: '{{name}}-new-{{namespace}}'
spec:
project: default
sources:
- repoURL: https://helm.elastic.co
chart: '{{chart}}'
targetRevision: '{{version}}'
helm:
values: |
filebeatConfig:
filebeat.yml: |
filebeat.inputs:
- type: container
paths:
- /var/log/containers/*.log
processors:
- add_kubernetes_metadata:
host: ${NODE_NAME}
matchers:
- logs_path:
logs_path: "/var/log/containers/"
output.logstash:
hosts: ["logstash-efk-logstash:5044"]
destination:
server: https://kubernetes.default.svc
namespace: '{{namespace}}'
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true
- ServerSideApply=true

Step 3: Setup the logstash

apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: efk-stack-logstash
namespace: argocd
spec:
generators:
- list:
elements:
- name: logstash
namespace: efk
chart: logstash
version: 8.5.1
path: logstash
template:
metadata:
name: '{{name}}-{{namespace}}'
spec:
project: default
sources:
- repoURL: https://helm.elastic.co
chart: '{{chart}}'
targetRevision: '{{version}}'
helm:
values: |
logstashPipeline:
logstash.conf: |
input {
beats {
port => 5044
}
}
output {
elasticsearch {
hosts => ["https://elasticsearch-master:9200"]
ssl => true
cacert => "/usr/share/logstash/config/certs/ca.crt"
user => "${username}"
password => "${password}"
}
}
service:
annotations: {}
type: ClusterIP
loadBalancerIP: ""
ports:
- name: beats
port: 5044
protocol: TCP
targetPort: 5044
- name: http
port: 8080
protocol: TCP
targetPort: 8080
extraVolumes:
- name: elasticsearch-certs
secret:
secretName: elasticsearch-master-certs
extraVolumeMounts:
- name: elasticsearch-certs
mountPath: /usr/share/logstash/config/certs
readOnly: true
envFrom:
- secretRef:
name: elasticsearch-master-new-credentials
destination:
server: https://kubernetes.default.svc
namespace: '{{namespace}}'
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true
- ServerSideApply=true

Step 4: Setup the ElasticSearch

apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: efk-stack-elasticsearch
namespace: argocd
spec:
generators:
- list:
elements:
- name: ealasticsearch
namespace: efk
chart: elasticsearch
version: 8.5.1
valuesFile: elasticsearch/values.yaml
path: elasticsearch
template:
metadata:
name: '{{name}}-{{namespace}}'
spec:
project: default
sources:
- repoURL: https://helm.elastic.co
chart: '{{chart}}'
targetRevision: '{{version}}'
helm:
parameters:
- name: nameOverride
value: 'elasticsearch'
- name: secret.enabled
value: 'false'
values: |
extraEnvs:
- name: ELASTIC_PASSWORD
valueFrom:
secretKeyRef:
name: elasticsearch-master-new-credentials
key: password
destination:
server: https://kubernetes.default.svc
namespace: '{{namespace}}'
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true
- ServerSideApply=true

Step 5: Setup the Kibana

apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: efk-stack-kibana
namespace: argocd
spec:
generators:
- list:
elements:
- name: kibana
namespace: efk
chart: kibana
version: 8.5.1
path: kibana
template:
metadata:
name: '{{name}}-{{namespace}}'
spec:
project: default
sources:
- repoURL: https://helm.elastic.co
chart: '{{chart}}'
targetRevision: '{{version}}'
helm:
values: |
# elasticsearchCredentialSecret: elasticsearch-master-new-credentials
ingress:
enabled: true
className: "nginx"
pathtype: ImplementationSpecific
annotations: {}
kubernetes.io/ingress.class: nginx
# kubernetes.io/tls-acme: "true"
hosts:
- host: hostname.com
paths:
- path: /
destination:
server: https://kubernetes.default.svc
namespace: '{{namespace}}'
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true
- ServerSideApply=true

Apply all the application Set
by using “kubectl apply -f filename”

Enjoy your EFK Stack is up and running on K8s with ArgoCD.

Thanks for reading the blog.

--

--

Written by SagarChoudhary

CKA Certified | AWS Certified Solution Architect Associate | Certified Terraform Associate | DevOps