What is Elasticsearch?
Elasticsearch is a distributed, RESTful search and analytics engine built on top of Apache LuceneApache Lucene is a high-performance, full-text search library written in Java. Elasticsearch wraps Lucene and adds distribution, a REST API, JSON-based queries, and cluster management on top of it. You never interact with Lucene directly — ES handles that for you.. It stores data as JSON documents, indexes them in near real-time, and lets you run powerful searches, aggregations, and analytics across massive datasets.
Why Use Elasticsearch?
🔍 Search
Full-text search with relevance scoring, fuzzy matching, autocomplete, and support for dozens of languages and analyzers.
📈 Observability
Store and query logs, metrics, and traces. The Elastic Stack (ELK) is the backbone of many observability platforms worldwide.
🛡️ Security Analytics
SIEM capabilities, threat detection, anomaly detection, and compliance auditing powered by real-time data indexing.
The Elastic Stack at a Glance
| Component | Role | What It Does |
|---|---|---|
| Elasticsearch | Storage & Search Engine | Indexes, stores, and retrieves JSON documents. The core brain. |
| Kibana | Visualization UI | Dashboards, Dev Tools console, index management, and more. |
| Logstash | Data Pipeline | Ingests data from many sources, transforms it, and ships to ES. |
| Beats / Elastic Agent | Lightweight Shippers | Collect data at the edge — Filebeat for logs, Metricbeat for metrics, etc. |
Core Concepts
Before diving into administration, you need to internalize these building blocks. They come up repeatedly in the certification exam.
A cluster is a collection of one or more nodes that together hold your entire data and provide federated indexing and search capabilities. Every cluster has a unique name (default: elasticsearch). A node joins a cluster by its cluster name.
A single running instance of Elasticsearch. Nodes can have different rolesNode Roles:
• master — manages cluster state
• data — holds shards, runs queries
• ingest — runs ingest pipelines
• ml — machine learning
• coordinating — routes requests
• transform — runs transforms
In production, you typically separate master-eligible nodes from data nodes for stability.: master, data, ingest, coordinating, and more.
An index is a collection of documents that share similar characteristics. It's analogous to a "database" in relational terms. Each index has a mappingMappings define the schema for documents in an index: which fields exist, their data types (text, keyword, integer, geo_point, etc.), and how they should be analyzed. Mappings can be explicit (you define them) or dynamic (ES infers types automatically). that defines the structure of documents within it.
The basic unit of information. A JSON object that gets indexed. For example, a single log entry, a product record, or a user profile. Each document lives in an index and has a unique _id.
An index is split into primary shards distributed across nodes. Each primary shard can have zero or more replica shards for fault tolerance and read throughput. By default, an index has 1 primary shard and 1 replica.
The data structure that makes search fast. Instead of mapping documents → words, it maps words → documents. When you search for "kubernetes", Elasticsearch looks up the term in the inverted index and instantly knows which documents contain it.
Kubernetes Basics
To use ECK, you need a working understanding of Kubernetes. Here's a crash course on the concepts that matter most for running Elasticsearch.
Key Kubernetes Objects for Elasticsearch
| Object | What It Is | Why It Matters for ES |
|---|---|---|
| Pod | Smallest deployable unit; wraps one or more containers | Each ES node runs as a Pod |
| StatefulSet | Manages pods with stable identity and persistent storage | ES is stateful — ECK creates StatefulSets under the hood |
| Service | Stable network endpoint for a set of pods | Exposes ES cluster API (port 9200) and inter-node transport (9300) |
| PersistentVolumeClaim | Request for storage | Each ES data node needs persistent disk for indices |
| ConfigMap / Secret | Configuration and sensitive data | ES passwords, TLS certs, elasticsearch.yml overrides |
| Namespace | Virtual cluster within a cluster | Isolate your Elastic stack from other workloads |
| CRDCustom Resource Definition (CRD) CRDs extend the Kubernetes API with new object types. ECK registers CRDs like Elasticsearch, Kibana, Beat, etc. so you can manage Elastic resources with simple YAML manifests just like native K8s objects. | Extends K8s API with custom objects | ECK adds Elasticsearch, Kibana, and Agent CRDs |
| OperatorOperator Pattern An operator is a controller that watches custom resources and automates application-specific operations (deploy, upgrade, backup, scale). The ECK operator watches your Elasticsearch CRDs and automatically manages StatefulSets, Services, TLS certificates, users, and rolling upgrades. | Application-aware controller | ECK operator manages the entire ES lifecycle |
Local Setup with Docker
The fastest way to learn is to run Elasticsearch locally. Below are two paths: a simple Docker Compose setup (no K8s) for quick exploration, and a K3d/Kind approach for practicing with ECK.
This gets Elasticsearch + Kibana running in under 2 minutes. Great for learning queries, mappings, and ingestion.
Create docker-compose.yml
# docker-compose.yml
version: "3.8"
services:
elasticsearch:
image: docker.elastic.co/elasticsearch/elasticsearch:8.17.0
container_name: es-node
environment:
- discovery.type=single-node
- xpack.security.enabled=false
- "ES_JAVA_OPTS=-Xms1g -Xmx1g"
ports:
- "9200:9200"
volumes:
- es-data:/usr/share/elasticsearch/data
kibana:
image: docker.elastic.co/kibana/kibana:8.17.0
container_name: kibana
environment:
- ELASTICSEARCH_HOSTS=http://elasticsearch:9200
ports:
- "5601:5601"
depends_on:
- elasticsearch
volumes:
es-data:
driver: local
Start the Stack
# Start in detached mode
docker compose up -d
# Verify Elasticsearch is running
curl http://localhost:9200
# Open Kibana in your browser
# http://localhost:5601
Verify It Works
# You should see a JSON response with cluster info:
# {
# "name": "es-node",
# "cluster_name": "docker-cluster",
# "version": { "number": "8.17.0", ... },
# "tagline": "You Know, for Search"
# }
# Check cluster health
curl http://localhost:9200/_cluster/health?pretty
sudo sysctl -w vm.max_map_count=262144 for Elasticsearch to start properly.
For practicing ECK and Kubernetes-based Elasticsearch management. This mirrors a real production setup on your laptop.
Install Prerequisites
# Install k3d (lightweight K8s using Docker)
curl -s https://raw.githubusercontent.com/k3d-io/k3d/main/install.sh | bash
# Install kubectl
# macOS:
brew install kubectl
# Linux:
curl -LO "https://dl.k8s.io/release/$(curl -L -s \
https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
chmod +x kubectl && sudo mv kubectl /usr/local/bin/
# Install Helm
curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash
Create a K3d Cluster
# Create cluster with enough memory
k3d cluster create elastic-lab \
--agents 2 \
--port "9200:9200@loadbalancer" \
--port "5601:5601@loadbalancer"
# Verify
kubectl get nodes
Install ECK Operator
# Install ECK CRDs
kubectl create -f https://download.elastic.co/downloads/eck/2.14.0/crds.yaml
# Install ECK Operator
kubectl apply -f https://download.elastic.co/downloads/eck/2.14.0/operator.yaml
# Watch the operator come up
kubectl -n elastic-system logs -f statefulset.apps/elastic-operator
kind create cluster or minikube start --memory=8192 instead of k3d. The ECK installation steps remain the same.
kubectl Cheatsheet
The essential commands you'll use daily when managing Elasticsearch on Kubernetes. Bookmark this section.
Core Commands
# Get resources
kubectl get pods # List pods
kubectl get pods -o wide # Pods with node info
kubectl get pods,services,configmaps # Multiple types
kubectl get elasticsearch # ECK custom resources
# Describe (detailed info)
kubectl describe pod elasticsearch-es-main-0
# Logs
kubectl logs elasticsearch-es-main-0 # Current logs
kubectl logs elasticsearch-es-main-0 -f # Stream / follow
kubectl logs elasticsearch-es-main-0 -c elasticsearch # Specific container
# Events (scheduler decisions)
kubectl get events --sort-by=.metadata.creationTimestamp
# Exec into a pod
kubectl exec -it elasticsearch-es-main-0 -c elasticsearch -- bash
# Port forward
kubectl port-forward service/quickstart-es-http 9200
kubectl port-forward service/quickstart-kb-http 5601
# Copy files
kubectl cp my-pod:/tmp/data.json ./local-data.json
# Resource usage
kubectl top pods
kubectl top nodes
# Context management
kubectl config current-context
kubectl config use-context elastic-lab
kubectl config set-context --current --namespace=elastic-system
ECK-Specific Commands
# Check ECK operator logs
kubectl -n elastic-system logs -f statefulset.apps/elastic-operator
# List all Elastic resources
kubectl get elasticsearch,kibana,beat,agent --all-namespaces
# Get the elastic user password
kubectl get secret quickstart-es-elastic-user -o go-template='{{.data.elastic | base64decode}}'
# Check cluster health via API
kubectl port-forward svc/quickstart-es-http 9200 &
curl -u "elastic:$PASSWORD" -k https://localhost:9200/_cluster/health?pretty
# Explain a custom resource
kubectl explain elasticsearch.spec.nodeSets
Welcome to Exploring ECK!
Elastic Cloud on Kubernetes (ECK) is the official Kubernetes operator from Elastic. Built on the Operator PatternThe Operator Pattern
Operators encode human operational knowledge into software. Instead of an admin manually running upgrades, scaling nodes, and configuring TLS, the ECK operator watches your desired state (YAML) and continuously reconciles the actual cluster to match it. It handles rolling upgrades, certificate rotation, user management, and more — automatically., it automates deploying, managing, and operating the entire Elastic Stack on Kubernetes.
What ECK Automates
Deployment & Upgrades — Rolling upgrades with zero downtime. Change the version number in YAML and ECK handles the rest.
TLS Everywhere — Auto-generates and rotates self-signed certificates for HTTP and transport layers.
User Management — Creates the elastic superuser and stores credentials in Kubernetes Secrets.
Scaling — Add or remove nodes by changing a number. ECK rebalances shards automatically.
Persistent Storage — Manages PersistentVolumeClaims for each data node.
Health Monitoring — Watches cluster health and reports status via the Elasticsearch custom resource.
kubectl create (for CRDs) and kubectl apply (for stack resources).
Installing the ECK Operator
Install CRDs
# Use 'create' (not apply) for CRDs
kubectl create -f https://download.elastic.co/downloads/eck/2.14.0/crds.yaml
create instead of apply?
CRDs should use create to avoid issues during operator upgrades. This is a declarative vs imperative distinction that prevents losing control of managed resources during version transitions.
Install the Operator
kubectl apply -f https://download.elastic.co/downloads/eck/2.14.0/operator.yaml
Verify Installation
# Check operator is running
kubectl -n elastic-system get pods
# NAME READY STATUS RESTARTS AGE
# elastic-operator-0 1/1 Running 0 30s
# Watch operator logs
kubectl -n elastic-system logs -f statefulset.apps/elastic-operator
Add the Elastic Helm Repo
helm repo add elastic https://helm.elastic.co
helm repo update
Install ECK Operator via Helm
helm install elastic-operator elastic/eck-operator \
--namespace elastic-system \
--create-namespace
Deploy Elasticsearch on Kubernetes
With ECK installed, deploying an Elasticsearch cluster is a single YAML file. Here's a development-friendly single-node setup and a production-grade multi-node topology.
# elasticsearch-dev.yaml
apiVersion: elasticsearch.k8s.elastic.co/v1
kind: Elasticsearch
metadata:
name: quickstart
spec:
version: 8.17.0
nodeSets:
- name: default
count: 1
config:
node.store.allow_mmap: false # needed for Docker/K3d
podTemplate:
spec:
containers:
- name: elasticsearch
resources:
requests:
memory: 2Gi
cpu: 500m
limits:
memory: 2Gi
cpu: 1
# Apply it
kubectl apply -f elasticsearch-dev.yaml
# Watch it come up
kubectl get elasticsearch
# NAME HEALTH NODES VERSION PHASE AGE
# quickstart green 1 8.17.0 Ready 2m
# Get the password
PASSWORD=$(kubectl get secret quickstart-es-elastic-user \
-o go-template='{{.data.elastic | base64decode}}')
echo $PASSWORD
# Test the connection
kubectl port-forward svc/quickstart-es-http 9200 &
curl -u "elastic:$PASSWORD" -k https://localhost:9200
# elasticsearch-prod.yaml
apiVersion: elasticsearch.k8s.elastic.co/v1
kind: Elasticsearch
metadata:
name: production
spec:
version: 8.17.0
nodeSets:
# Dedicated master nodes
- name: masters
count: 3
config:
node.roles: ["master"]
podTemplate:
spec:
containers:
- name: elasticsearch
resources:
requests: { memory: 2Gi, cpu: 1 }
limits: { memory: 2Gi, cpu: 2 }
volumeClaimTemplates:
- metadata:
name: elasticsearch-data
spec:
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 10Gi
# Data nodes
- name: data
count: 3
config:
node.roles: ["data", "ingest"]
podTemplate:
spec:
containers:
- name: elasticsearch
resources:
requests: { memory: 4Gi, cpu: 2 }
limits: { memory: 4Gi, cpu: 4 }
volumeClaimTemplates:
- metadata:
name: elasticsearch-data
spec:
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 100Gi
# Coordinating nodes
- name: coordinating
count: 2
config:
node.roles: ["ingest"]
podTemplate:
spec:
containers:
- name: elasticsearch
resources:
requests: { memory: 2Gi, cpu: 1 }
limits: { memory: 2Gi, cpu: 2 }
Deploy Kibana
# kibana.yaml
apiVersion: kibana.k8s.elastic.co/v1
kind: Kibana
metadata:
name: quickstart
spec:
version: 8.17.0
count: 1
elasticsearchRef:
name: quickstart # Must match your Elasticsearch resource name
# Apply
kubectl apply -f kibana.yaml
# Access Kibana
kubectl port-forward svc/quickstart-kb-http 5601
# Open https://localhost:5601
# Login: elastic / (password from previous section)
ECK Configuration Deep Dive
ECK exposes Elasticsearch configuration through the CRD spec. Here are the key areas you need to master.
Any elasticsearch.yml setting can be specified under spec.nodeSets[].config:
nodeSets:
- name: data
config:
node.roles: ["data", "ingest"]
cluster.routing.allocation.awareness.attributes: zone
indices.memory.index_buffer_size: 20%
ECK automatically sets heap to 50% of the container memory limit. To override:
podTemplate:
spec:
containers:
- name: elasticsearch
env:
- name: ES_JAVA_OPTS
value: "-Xms4g -Xmx4g"
resources:
limits:
memory: 8Gi
nodeSets:
- name: data
volumeClaimTemplates:
- metadata:
name: elasticsearch-data
spec:
accessModes: ["ReadWriteOnce"]
storageClassName: fast-ssd # Your StorageClass
resources:
requests:
storage: 200Gi
ECK cannot resize existing PVCs. If you need more storage, you must rely on your StorageClass supporting volume expansion, or migrate data.
ECK auto-generates self-signed certs. To use your own:
spec:
http:
tls:
certificate:
secretName: my-custom-cert # K8s Secret with tls.crt and tls.key
To disable TLS (development only):
spec:
http:
tls:
selfSignedCertificate:
disabled: true
Control how rolling upgrades proceed:
spec:
updateStrategy:
changeBudget:
maxSurge: -1 # Unbounded — can create new pods first
maxUnavailable: 1 # Only 1 pod down at a time
This ensures minimal disruption during version upgrades. The cluster health may briefly turn yellow but remains available.
ECK Operator YAML — Line-by-Line Breakdown
When you run kubectl apply -f operator.yaml, you're deploying a large all-in-one manifest that creates roughly 10 Kubernetes resources. This section breaks down every single resource, every key-value pair, and explains why each piece exists. Understanding this is essential for both the certification and real-world troubleshooting.
--- markers. Each --- denotes a separate Kubernetes resource. They are applied in order: namespace first, then roles, then the operator itself. We'll walk through each one.
1. Namespace — elastic-system
apiVersion: v1
kind: Namespace
metadata:
name: elastic-system
labels:
name: elastic-system
| Key | Value | Explanation |
|---|---|---|
apiVersion: v1 | v1 | The API versionapiVersion tells Kubernetes which API group and version to use for this resource. v1 is the core "stable" API group. Other resources use groups like apps/v1, rbac.authorization.k8s.io/v1, etc. If you use the wrong apiVersion, Kubernetes won't recognize your YAML. for core Kubernetes objects like Namespaces, Pods, and Services. v1 means this is part of the stable core API. |
kind: Namespace | Namespace | A NamespaceNamespaces are virtual clusters within a physical Kubernetes cluster. They provide isolation for resources — pods, services, and secrets in one namespace are invisible to other namespaces by default. Think of them as "folders" that organize your cluster. Common examples: default, kube-system, elastic-system. is a virtual partition of the cluster. This creates a dedicated home for all ECK operator resources, keeping them isolated from your application workloads. |
metadata.name | elastic-system | The name of the namespace. All ECK components (the operator pod, its secrets, its service account, webhook service) will live here. |
metadata.labels | name: elastic-system | Labels are key-value tags for organizing and selecting resources. This label lets you query all resources in this namespace easily: kubectl get all -l name=elastic-system. |
default or observability), and the operator will still manage them because it has cluster-wide permissions.
2. ServiceAccount — elastic-operator
apiVersion: v1
kind: ServiceAccount
automountServiceAccountToken: true
metadata:
name: elastic-operator
namespace: elastic-system
labels:
control-plane: elastic-operator
app.kubernetes.io/version: "3.0.0"
| Key | Value | Explanation |
|---|---|---|
kind: ServiceAccount | — | A ServiceAccountServiceAccount is the identity a Pod uses to interact with the Kubernetes API. When the operator pod needs to create a StatefulSet, read a Secret, or update an Elasticsearch custom resource, it authenticates as this ServiceAccount. Without it, the pod would use the default service account, which typically has no permissions. provides an identity for the operator pod. It's like a "username" the operator uses when talking to the Kubernetes API server. |
automountServiceAccountToken | true | Automatically mounts the service account's API token into the pod at /var/run/secrets/kubernetes.io/serviceaccount/token. The operator needs this token to authenticate every API call it makes (creating pods, reading secrets, etc.). |
metadata.namespace | elastic-system | The ServiceAccount lives in the same namespace as the operator. ServiceAccounts are namespace-scoped resources. |
labels.control-plane | elastic-operator | A common labeling convention. control-plane identifies this as part of the operator's control infrastructure (not a user workload). Used by selectors throughout the manifest. |
labels.app.kubernetes.io/version | "3.0.0" | A standard Kubernetes label from the recommended label setRecommended Labels Kubernetes has a set of standard labels: • app.kubernetes.io/name — app name• app.kubernetes.io/version — app version• app.kubernetes.io/component — role in architecture• app.kubernetes.io/managed-by — tool managing itThese make it easy to identify and query resources uniformly across tools like Helm, kubectl, and monitoring systems.. Tracks which ECK version deployed this resource. Helpful for auditing and upgrades. |
3. Secret — elastic-webhook-server-cert
apiVersion: v1
kind: Secret
metadata:
name: elastic-webhook-server-cert
namespace: elastic-system
labels:
control-plane: elastic-operator
app.kubernetes.io/version: "3.0.0"
| Key | Value | Explanation |
|---|---|---|
kind: Secret | — | A SecretKubernetes Secrets store sensitive data like passwords, TLS certificates, and API tokens. They are base64-encoded (not encrypted by default!) and can be mounted as files or environment variables in pods. In production, enable encryption at rest with EncryptionConfiguration. stores sensitive data. This one holds the TLS certificate and private key the webhook server uses for HTTPS. |
name | elastic-webhook-server-cert | Initially created empty. The operator generates and populates this Secret at startup with a self-signed TLS cert. The webhook service needs HTTPS because the Kubernetes API server only sends webhook requests over TLS. |
4. ConfigMap — elastic-operator (Operator Settings)
This is the operator's main configuration file. It controls how the ECK operator behaves — logging, reconciliation speed, certificate lifetimes, telemetry, and more.
apiVersion: v1
kind: ConfigMap
metadata:
name: elastic-operator
namespace: elastic-system
data:
eck.yaml: |-
log-verbosity: 0
metrics-port: 0
metrics-secure: false
container-registry: docker.elastic.co
max-concurrent-reconciles: 3
ca-cert-validity: 8760h
ca-cert-rotate-before: 24h
cert-validity: 8760h
cert-rotate-before: 24h
disable-config-watch: false
exposed-node-labels: [topology.kubernetes.io/.*,failure-domain.beta.kubernetes.io/.*]
set-default-security-context: auto-detect
kube-client-timeout: 60s
elasticsearch-client-timeout: 180s
disable-telemetry: false
distribution-channel: all-in-one
validate-storage-class: true
enable-webhook: true
webhook-name: elastic-webhook.k8s.elastic.co
webhook-port: 9443
operator-namespace: elastic-system
enable-leader-election: true
elasticsearch-observation-interval: 10s
ubi-only: false
| Setting | Value | What It Does & Why |
|---|---|---|
log-verbosity | 0 |
Controls how chatty the operator logs are. 0 = standard info-level logging. Increase to 1 or 2 for debug output when troubleshooting. Higher values produce significantly more log lines. |
metrics-port | 0 |
Port for exposing Prometheus-compatible metrics. 0 means metrics are disabled. Set to a port like 8080 if you want to scrape operator performance metrics with Prometheus. |
metrics-secure | false |
Whether the metrics endpoint requires TLS. Only relevant if metrics-port is non-zero. |
container-registry | docker.elastic.co |
The container registryContainer Registry A registry is where container images are stored and distributed. docker.elastic.co is Elastic's official registry. In air-gapped or enterprise environments, you'd change this to your private registry (e.g., my-registry.company.com/elastic) and mirror the images there. where the operator pulls Elastic Stack images (Elasticsearch, Kibana, Beats, etc.). Change this if you use a private/mirrored registry. |
max-concurrent-reconciles | 3 |
How many reconciliation loopsReconciliation Loop The core of the Operator Pattern. The operator continuously compares the desired state (your YAML) with the actual state (what's running). If they differ, it takes action to bring reality in line with your spec. Each reconcile handles one Elasticsearch resource. With max-concurrent-reconciles: 3, three different ES clusters can be reconciled simultaneously. can run at the same time. If you manage dozens of Elasticsearch clusters, increase this to speed up processing. Too high a value may overwhelm the K8s API server. |
ca-cert-validity | 8760h |
How long the operator's internal CA certificate is valid. 8760h = 1 year. The operator uses this CA to sign TLS certificates for Elasticsearch nodes and the webhook. |
ca-cert-rotate-before | 24h |
How long before expiry the CA cert gets rotated. The operator will generate a new CA 24 hours before the old one expires — ensuring no gap in TLS coverage. |
cert-validity | 8760h |
How long individual node/transport TLS certificates are valid (1 year). These are the certs used by each Elasticsearch pod for HTTP and inter-node encryption. |
cert-rotate-before | 24h |
Rotate individual certs 24 hours before expiry. The operator handles this seamlessly — pods get new certs without restart through Kubernetes Secret updates. |
disable-config-watch | false |
When false, the operator watches this ConfigMap for changes and reloads configuration without a restart. Set to true only if you want to require a pod restart for config changes. |
exposed-node-labels | [topology.kubernetes.io/.*, |
Which Kubernetes node labelsExposed Node Labels Elasticsearch can use Kubernetes node labels for shard allocation awareness — for example, routing primary and replica shards to different availability zones. This setting controls which K8s node labels are exposed to Elasticsearch's node.attr.* settings. The regex patterns match zone/region topology labels. are passed through to Elasticsearch pods as node attributes. Critical for zone-aware shard allocation in multi-AZ clusters. |
set-default-security-context | auto-detect |
Whether to set a SecurityContextSecurity Context A SecurityContext defines privilege and access settings for a pod or container: running as non-root, dropping Linux capabilities, read-only filesystems, etc. auto-detect means ECK checks if the cluster needs one (e.g., OpenShift has strict SCCs) and sets it appropriately. on managed pods. auto-detect = ECK checks if the platform requires it (like OpenShift's Security Context Constraints) and applies it automatically. |
kube-client-timeout | 60s |
Timeout for the operator's HTTP calls to the Kubernetes API server. If your K8s API is slow (large clusters, heavy load), you might need to increase this. |
elasticsearch-client-timeout | 180s |
Timeout for the operator's HTTP calls to Elasticsearch clusters it manages. Set to 3 minutes because some ES operations (like shard allocation changes) can take time. |
disable-telemetry | false |
When false, ECK sends anonymous usage statistics to Elastic (cluster count, version info). No personal data. Set to true for air-gapped or privacy-conscious environments. |
distribution-channel | all-in-one |
Identifies how the operator was installed. all-in-one = via the single YAML manifest. Alternatives: helm, community-operators (OLM). Used in telemetry only. |
validate-storage-class | true |
When true, the operator checks that the StorageClass referenced in your Elasticsearch PVC templates actually exists in the cluster before deploying. Prevents cryptic failures. |
enable-webhook | true |
Enables the validating admission webhookValidating Webhook A webhook that intercepts CREATE and UPDATE requests to the K8s API. Before an Elasticsearch resource is saved, the webhook validates the YAML spec: checks for invalid node roles, incompatible settings, misconfigured volume claims, etc. If validation fails, the request is rejected with an error before anything is applied. This prevents misconfigurations from reaching the operator.. The webhook catches invalid configurations (bad node roles, incorrect settings) before they're applied to the cluster. Strongly recommended. |
webhook-name | elastic-webhook.k8s.elastic.co |
The name of the ValidatingWebhookConfiguration resource. Must match the name in the webhook configuration at the bottom of the manifest. |
webhook-port | 9443 |
The port the webhook HTTPS server listens on inside the operator pod. The webhook Service routes port 443 → this port (9443). |
operator-namespace | elastic-system |
Tells the operator which namespace it's running in. Used to find its own resources (secrets, configmaps). |
enable-leader-election | true |
Enables leader electionLeader Election When you run multiple operator replicas for high availability, only one should actively reconcile resources at a time (the "leader"). The others remain on standby. Leader election uses a Kubernetes Lease resource — whichever replica acquires the lease becomes the active leader. If it crashes, another replica takes over within seconds.. Critical if running multiple operator replicas for HA. Uses a Kubernetes Lease object so only one operator instance is active at a time. |
elasticsearch-observation-interval | 10s |
How often the operator polls each Elasticsearch cluster's health status. Every 10 seconds it checks _cluster/health to update the .status field of the Elasticsearch custom resource. |
ubi-only | false |
If true, the operator only uses UBI-based imagesUBI (Universal Base Image)Red Hat's UBI is a freely redistributable container base image. Some organizations (especially government/military) require all containers to be based on UBI for compliance reasons. When ubi-only: true, ECK pulls Elastic Stack images tagged with -ubi (e.g., elasticsearch:8.17.0-ubi). These are identical functionally but built on a RHEL base. from the container registry. Required for OpenShift environments with strict compliance requirements. |
5. ClusterRole — elastic-operator (Permissions)
This is the most important resource to understand. It defines exactly what the operator is allowed to do in your cluster. Every permission is here for a specific reason.
RBAC has three pieces:
1. Subject — who (ServiceAccount, User, Group)
2. Role/ClusterRole — what they can do (rules)
3. RoleBinding/ClusterRoleBinding — connects who to what
A
Role is namespace-scoped. A ClusterRole is cluster-wide. Since the operator manages resources across all namespaces, it needs a ClusterRole.. A ClusterRole defines permissions at the cluster level (all namespaces). Each rule says: "for these API groups, for these resource types, allow these actions."
- apiGroups: [""]
resources: [pods, events, persistentvolumeclaims,
secrets, services, configmaps]
verbs: [get, list, watch, create, update, patch, delete]
- apiGroups: ["apps"]
resources: [deployments, statefulsets, daemonsets]
verbs: [get, list, watch, create, update, patch, delete]
- apiGroups: ["policy"]
resources: [poddisruptionbudgets]
verbs: [get, list, watch, create, update, patch, delete]
| Resource | Why the Operator Needs It |
|---|---|
| pods | Creates, monitors, and deletes Elasticsearch, Kibana, and other Elastic pods. Reads pod status to track health. |
| events | Creates Kubernetes events to report what it's doing (e.g., "Starting rolling upgrade", "Scaling data nodes"). |
| persistentvolumeclaims | Manages storage for Elasticsearch data nodes. Each data node gets its own PVC for index storage. |
| secrets | Stores and manages TLS certificates, the elastic user password, internal transport keys, and webhook certs. |
| services | Creates Kubernetes Services to expose Elasticsearch (port 9200) and inter-node transport (port 9300). |
| configmaps | Manages Elasticsearch configuration (elasticsearch.yml) and Kibana settings for each deployment. |
| statefulsets | The primary workload type for Elasticsearch. StatefulSets provide stable pod names, ordered deployment, and persistent storage. |
| deployments | Used for Kibana, APM Server, and Enterprise Search — stateless components that don't need StatefulSet semantics. |
| daemonsets | Used for Beats and Elastic Agent — components that need to run on every node for log/metric collection. |
| poddisruptionbudgets | PDBsPodDisruptionBudgets (PDBs) A PDB limits how many pods of a set can be down simultaneously during voluntary disruptions (node drains, upgrades). The operator creates PDBs for Elasticsearch to prevent Kubernetes from evicting too many data nodes at once, which could cause data loss or a red cluster. protect ES pods during node maintenance. Prevents K8s from draining too many ES nodes simultaneously. |
- apiGroups: ["authorization.k8s.io"]
resources: [subjectaccessreviews]
verbs: [create]
- apiGroups: ["coordination.k8s.io"]
resources: [leases]
verbs: [create]
- apiGroups: ["coordination.k8s.io"]
resources: [leases]
resourceNames: [elastic-operator-leader]
verbs: [get, watch, update]
| Permission | Why |
|---|---|
| subjectaccessreviews | Lets the operator check if it has permission to perform an action. Used for self-authorization checks before attempting operations. |
| leases (create) | Creates the leader election Lease object. Only the first replica to acquire this lease becomes the active operator. |
| leases (get/watch/update) | Specifically for the lease named elastic-operator-leader. The active leader renews this lease periodically. If it fails to renew (crash), another replica takes over. |
The operator needs permissions for every Elastic CRD it manages. Each follows the same pattern:
- apiGroups: ["elasticsearch.k8s.elastic.co"]
resources: [elasticsearches, elasticsearches/status, elasticsearches/finalizers]
verbs: [get, list, watch, create, update, patch]
| Sub-Resource | Purpose |
|---|---|
elasticsearches | The main custom resource — your Elasticsearch cluster spec. The operator reads your desired state from this. |
elasticsearches/status | The status subresource where the operator writes health, phase (Ready/ApplyingChanges), version, and node count. |
elasticsearches/finalizers | FinalizersKubernetes Finalizers Finalizers are hooks that run before a resource is deleted. When you delete an Elasticsearch CR, the operator's finalizer ensures it cleanly removes dependent resources (StatefulSets, Services, Secrets) before the CR disappears. Without finalizers, you could end up with orphaned resources. The blockOwnerDeletion note in the YAML refers to OpenShift-specific behavior with owner references. ensure clean deletion. When you kubectl delete elasticsearch quickstart, the operator cleans up all child resources before the CR is removed. |
The same pattern repeats for every Elastic component the operator manages:
| API Group | Resource | Component |
|---|---|---|
elasticsearch.k8s.elastic.co | elasticsearches | Elasticsearch clusters |
kibana.k8s.elastic.co | kibanas | Kibana instances |
apm.k8s.elastic.co | apmservers | APM Server |
beat.k8s.elastic.co | beats | Filebeat, Metricbeat, etc. |
agent.k8s.elastic.co | agents | Elastic Agent |
enterprisesearch.k8s.elastic.co | enterprisesearches | Enterprise Search |
maps.k8s.elastic.co | elasticmapsservers | Elastic Maps Server |
logstash.k8s.elastic.co | logstashes | Logstash |
stackconfigpolicy.k8s.elastic.co | stackconfigpolicies | Stack-wide config policies |
autoscaling.k8s.elastic.co | elasticsearchautoscalers | ES autoscaling rules |
- apiGroups: ["storage.k8s.io"]
resources: [storageclasses]
verbs: [get, list, watch]
- apiGroups: ["admissionregistration.k8s.io"]
resources: [validatingwebhookconfigurations]
verbs: [get, list, watch, create, update, patch, delete]
- apiGroups: [""]
resources: [nodes, endpoints]
verbs: [get, list, watch]
| Resource | Why |
|---|---|
| storageclasses (read-only) | Validates that StorageClasses referenced in your PVC templates exist before deploying (the validate-storage-class: true setting). |
| validatingwebhookconfigurations | Manages the webhook configuration itself — creates it, updates its CA bundle when certs rotate, and cleans up on uninstall. |
| nodes (read-only) | Reads node labels (like availability zone) to pass to Elasticsearch for zone-aware shard allocation. |
| endpoints (read-only) | Watches Service endpoints to track which ES pods are ready and discoverable. |
6. Aggregate ClusterRoles — elastic-operator-view & elastic-operator-edit
These are not for the operator itself — they are for your team. They use Kubernetes role aggregationRole Aggregation
Kubernetes has built-in ClusterRoles: view, edit, and admin. When you add the label rbac.authorization.k8s.io/aggregate-to-view: "true" to a ClusterRole, its rules are automatically merged into the built-in view role. This means anyone with the view role can now also view Elasticsearch resources — no extra RoleBindings needed. so team members can work with Elastic resources using standard K8s roles.
| ClusterRole | Aggregates Into | Permissions |
|---|---|---|
elastic-operator-view | view, edit, admin | get, list, watch on all Elastic CRDs — team members with "view" access can see your Elasticsearch clusters, Kibana instances, etc. |
elastic-operator-edit | edit, admin | create, delete, patch, update on all Elastic CRDs — team members with "edit" access can deploy and modify Elastic resources. |
7. ClusterRoleBinding — Connects Identity to Permissions
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: elastic-operator
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: elastic-operator # The ClusterRole defined above
subjects:
- kind: ServiceAccount
name: elastic-operator # The ServiceAccount defined above
namespace: elastic-system
This is the glue that connects the ServiceAccount (identity, resource #2) to the ClusterRole (permissions, resource #5). Without this binding, the operator pod would have zero permissions and fail immediately on startup.
8. Service — elastic-webhook-server
apiVersion: v1
kind: Service
metadata:
name: elastic-webhook-server
namespace: elastic-system
spec:
ports:
- name: https
port: 443
targetPort: 9443
selector:
control-plane: elastic-operator
| Key | Value | Explanation |
|---|---|---|
port: 443 | — | The port the K8s API server connects to when sending webhook requests. HTTPS on the standard port. |
targetPort: 9443 | — | Routes to port 9443 inside the operator pod, where the webhook HTTPS server is actually listening (matching webhook-port in the ConfigMap). |
selector | control-plane: elastic-operator | Selects pods with this label — routes traffic to the operator pod. This label was set on the StatefulSet's pod template. |
9. StatefulSet — The Operator Pod Itself
This is the heart of the deployment — the actual container that runs the ECK operator code.
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: elastic-operator
namespace: elastic-system
spec:
selector:
matchLabels:
control-plane: elastic-operator
serviceName: elastic-operator
replicas: 1
| Key | Value | Explanation |
|---|---|---|
kind: StatefulSet | — | A StatefulSetWhy StatefulSet for the operator? The operator uses a StatefulSet (not a Deployment) because it provides a stable pod name ( elastic-operator-0). This matters for leader election and for the webhook certificate, which includes the pod's stable DNS name. A Deployment would give random pod names that change on restart. ensures the operator pod has a stable identity. This matters for leader election and consistent webhook addressing. |
replicas: 1 | — | Runs a single operator instance. For HA, increase to 2 or 3 — leader election ensures only one is active. |
serviceName | elastic-operator | Provides a headless service for the StatefulSet (stable DNS for pods). |
Pod Template — Annotations
template:
metadata:
annotations:
"co.elastic.logs/raw": "[{\"type\":\"container\",...}]"
"checksum/config": 3fdaff4a979089797cb469...
| Annotation | Purpose |
|---|---|
co.elastic.logs/raw | Tells Filebeat/Elastic Agent (if deployed) how to parse the operator's logs. It renames fields like error → error.message and source → event.source to avoid conflicts with the Elastic Common Schema (ECS). |
checksum/config | A SHA256 hash of the ConfigMap content. When the ConfigMap changes, this checksum changes, which triggers a pod restart. This is a common Kubernetes pattern to ensure pods pick up config changes. |
Pod Template — Security
spec:
terminationGracePeriodSeconds: 10
serviceAccountName: elastic-operator
automountServiceAccountToken: true
securityContext:
runAsNonRoot: true
containers:
- name: manager
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop: [ALL]
readOnlyRootFilesystem: true
runAsNonRoot: true
| Setting | What & Why |
|---|---|
terminationGracePeriodSeconds: 10 | Gives the operator 10 seconds to shut down cleanly when deleted. The operator saves its state and releases the leader lease during this window. |
serviceAccountName | Links this pod to the ServiceAccount with all the RBAC permissions defined earlier. |
runAsNonRoot: true | The pod and container must run as a non-root user. Security hardening — even if the container image has a root user, K8s will refuse to start it. |
allowPrivilegeEscalation: false | Prevents the process from gaining more privileges than its parent. Blocks exploit techniques that try to escalate to root. |
capabilities.drop: [ALL] | Drops all Linux capabilities (like NET_RAW, SYS_ADMIN). The operator doesn't need any special kernel privileges. This is the most restrictive setting possible. |
readOnlyRootFilesystem: true | The container filesystem is mounted read-only. Prevents malicious code from writing to the container. The operator writes only to /tmp (mounted separately for certs). |
Container — Image, Args, Env, Resources
containers:
- image: "docker.elastic.co/eck/eck-operator:3.0.0"
imagePullPolicy: IfNotPresent
name: manager
args: ["manager", "--config=/conf/eck.yaml"]
env:
- name: OPERATOR_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: POD_IP
valueFrom:
fieldRef:
fieldPath: status.podIP
- name: WEBHOOK_SECRET
value: elastic-webhook-server-cert
resources:
limits: { cpu: 1, memory: 1Gi }
requests: { cpu: 100m, memory: 150Mi }
| Setting | Explanation |
|---|---|
image | The ECK operator container image, version 3.0.0, from Elastic's official registry. |
imagePullPolicy: IfNotPresent | Only pulls the image if it's not already cached on the node. Speeds up restarts and avoids unnecessary network calls. |
args: ["manager", "--config=..."] | Starts the operator binary in "manager" mode (as opposed to "webhook-only" mode) and points it to the ConfigMap-mounted config file. |
OPERATOR_NAMESPACE | Injected from the Downward APIKubernetes Downward API The Downward API exposes pod and container metadata to the running container as environment variables or files. fieldRef: metadata.namespace injects the pod's namespace. fieldRef: status.podIP injects the pod's IP. The pod doesn't need to "know" these values in advance — K8s fills them in automatically at runtime.. Tells the operator which namespace it's in, so it can find its own resources. |
POD_IP | The operator's own IP address. Used for the webhook server to bind to the correct network interface. |
WEBHOOK_SECRET | Name of the Secret where the webhook TLS cert is stored. The operator reads and writes certs to this Secret. |
resources.requests | 100m CPU (0.1 core) and 150Mi memory — the minimum guaranteed. The scheduler uses requests to place the pod. |
resources.limits | 1 CPU and 1Gi memory — the maximum. If the operator exceeds the memory limit, K8s kills the pod (OOMKilled). CPU is throttled, not killed. |
Volume Mounts
volumeMounts:
- mountPath: "/conf"
name: conf
readOnly: true
- mountPath: /tmp/k8s-webhook-server/serving-certs
name: cert
readOnly: true
volumes:
- name: conf
configMap:
name: elastic-operator
- name: cert
secret:
defaultMode: 420
secretName: elastic-webhook-server-cert
| Volume | Source | What Gets Mounted |
|---|---|---|
conf → /conf | ConfigMap: elastic-operator | The eck.yaml config file. Mounted read-only. The operator reads its settings from here on startup (and watches for changes). |
cert → /tmp/k8s-webhook-server/serving-certs | Secret: elastic-webhook-server-cert | The TLS cert and key for the webhook HTTPS server. defaultMode: 420 (octal 0644) means the cert files are readable by the container process. |
10. ValidatingWebhookConfiguration — Request Interceptor
This resource tells the Kubernetes API server: "Before accepting any CREATE or UPDATE to an Elastic custom resource, send it to the webhook service for validation first."
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingWebhookConfiguration
metadata:
name: elastic-webhook.k8s.elastic.co
webhooks:
- clientConfig:
service:
name: elastic-webhook-server
namespace: elastic-system
path: /validate-elasticsearch-k8s-elastic-co-v1-elasticsearch
failurePolicy: Ignore
name: elastic-es-validation-v1.k8s.elastic.co
matchPolicy: Exact
admissionReviewVersions: [v1, v1beta1]
sideEffects: None
rules:
- apiGroups: ["elasticsearch.k8s.elastic.co"]
apiVersions: ["v1"]
operations: ["CREATE", "UPDATE"]
resources: ["elasticsearches"]
| Key | What It Does |
|---|---|
clientConfig.service | Points to the webhook Service in elastic-system. The K8s API server sends HTTPS requests to this service when someone creates/updates an Elastic resource. |
path | Each Elastic resource type has its own validation endpoint (path). For example, /validate-elasticsearch-k8s-elastic-co-v1-elasticsearch handles Elasticsearch v1 resources, /validate-kibana-k8s-elastic-co-v1-kibana handles Kibana, etc. |
failurePolicy: Ignore | If the webhook is unreachable (operator pod is down, restarting), Kubernetes allows the request through anyway. The alternative is Fail, which would block all Elastic resource changes if the operator is down. Ignore is safer for availability. |
matchPolicy: Exact | Only intercepts requests that exactly match the specified API group and version. No wildcards. |
admissionReviewVersions | Supports both v1 and v1beta1 admission review formats for backward compatibility with older K8s clusters. |
sideEffects: None | Declares that this webhook has no side effects — it only validates, never modifies resources or external state. This is important for K8s to know it can safely retry webhook calls. |
rules | Match conditions: intercept only CREATE and UPDATE operations on the specified resource types. DELETE and GET are not intercepted. |
Summary — How All 10 Resources Work Together
The flow is: you write Elasticsearch YAML → the webhook validates it → Kubernetes saves it → the operator pod (running as the ServiceAccount with ClusterRole permissions) detects the change → reads the ConfigMap for its settings → creates StatefulSets, Services, Secrets, and PDBs to make your cluster real.
kubectl create (for CRDs) vs kubectl apply (for the operator). You should also be able to troubleshoot operator issues by checking its logs: kubectl -n elastic-system logs -f statefulset.apps/elastic-operator.
Cluster Administration
Essential Elasticsearch APIs for managing your cluster. Practice these in Kibana Dev Tools.
Health & Status
# Cluster health (green/yellow/red)
GET _cluster/health
# Node info
GET _cat/nodes?v
# Shard allocation
GET _cat/shards?v
# Indices overview
GET _cat/indices?v&s=index
# Pending tasks
GET _cluster/pending_tasks
Index Management
# Create an index with settings and mappings
PUT /my-index
{
"settings": {
"number_of_shards": 3,
"number_of_replicas": 1
},
"mappings": {
"properties": {
"title": { "type": "text" },
"status": { "type": "keyword" },
"timestamp": { "type": "date" },
"count": { "type": "integer" }
}
}
}
# Create an index template
PUT _index_template/logs-template
{
"index_patterns": ["logs-*"],
"template": {
"settings": {
"number_of_shards": 2,
"number_of_replicas": 1
},
"mappings": {
"properties": {
"message": { "type": "text" },
"@timestamp": { "type": "date" },
"level": { "type": "keyword" }
}
}
}
}
# Index Lifecycle Management (ILM) policy
PUT _ilm/policy/logs-policy
{
"policy": {
"phases": {
"hot": { "actions": { "rollover": { "max_size": "50GB", "max_age": "1d" }}},
"warm": { "min_age": "7d", "actions": { "shrink": { "number_of_shards": 1 }}},
"cold": { "min_age": "30d", "actions": { "freeze": {} }},
"delete": { "min_age": "90d", "actions": { "delete": {} }}
}
}
}
Setting Up Data Ingestion
Getting data into Elasticsearch is fundamental. Here are the main approaches, from simplest to most powerful.
# Index a single document
POST /my-index/_doc
{
"title": "Getting Started with ES",
"status": "published",
"timestamp": "2026-04-01T12:00:00Z",
"count": 42
}
# Index with a specific ID
PUT /my-index/_doc/1
{
"title": "ECK Tutorial",
"status": "draft",
"timestamp": "2026-04-01T14:00:00Z",
"count": 7
}
# Bulk index multiple documents
POST _bulk
{ "index": { "_index": "my-index" } }
{ "title": "Doc 1", "status": "active", "timestamp": "2026-04-01T10:00:00Z" }
{ "index": { "_index": "my-index" } }
{ "title": "Doc 2", "status": "active", "timestamp": "2026-04-01T11:00:00Z" }
{ "index": { "_index": "my-index" } }
{ "title": "Doc 3", "status": "archived", "timestamp": "2026-03-01T09:00:00Z" }
_bulk endpoint rather than individual index calls whenever you have more than a handful of documents. Each line must be on its own line (NDJSON format).
Process documents before indexing with built-in processors:
# Create an ingest pipeline
PUT _ingest/pipeline/my-pipeline
{
"description": "Extract timestamp and add geo data",
"processors": [
{
"date": {
"field": "raw_timestamp",
"formats": ["yyyy-MM-dd HH:mm:ss"],
"target_field": "@timestamp"
}
},
{
"geoip": {
"field": "client_ip",
"target_field": "geo"
}
},
{
"remove": {
"field": "raw_timestamp"
}
}
]
}
# Use the pipeline when indexing
POST /my-index/_doc?pipeline=my-pipeline
{
"raw_timestamp": "2026-04-01 12:30:00",
"client_ip": "8.8.8.8",
"message": "User login"
}
Deploy Filebeat as a DaemonSet to collect container logs from every node:
# filebeat.yaml (ECK managed)
apiVersion: beat.k8s.elastic.co/v1beta1
kind: Beat
metadata:
name: filebeat
spec:
type: filebeat
version: 8.17.0
elasticsearchRef:
name: quickstart
daemonSet:
podTemplate:
spec:
containers:
- name: filebeat
volumeMounts:
- name: varlog
mountPath: /var/log
readOnly: true
volumes:
- name: varlog
hostPath:
path: /var/log
config:
filebeat.inputs:
- type: container
paths:
- /var/log/containers/*.log
For complex ETL pipelines with multiple inputs/outputs:
# logstash.conf
input {
beats { port => 5044 }
tcp { port => 5000 codec => json }
}
filter {
if [type] == "syslog" {
grok {
match => { "message" => "%{SYSLOGTIMESTAMP:timestamp} %{SYSLOGHOST:host} %{DATA:program}: %{GREEDYDATA:msg}" }
}
}
mutate {
remove_field => ["agent", "ecs"]
}
}
output {
elasticsearch {
hosts => ["https://quickstart-es-http:9200"]
index => "logs-%{+YYYY.MM.dd}"
user => "elastic"
password => "${ES_PASSWORD}"
ssl_certificate_verification => false
}
}
Monitoring & Logging
Essential Monitoring APIs
# Cluster health
GET _cluster/health
# Node stats (CPU, memory, disk, JVM)
GET _nodes/stats
# Index stats
GET /my-index/_stats
# Hot threads (find slow queries)
GET _nodes/hot_threads
# Task management (long-running operations)
GET _tasks?actions=*search&detailed
# Shard allocation explanation
GET _cluster/allocation/explain
Kibana Stack Monitoring
Enable monitoring in your ECK Elasticsearch resource to see cluster dashboards in Kibana:
spec:
monitoring:
metrics:
elasticsearchRefs:
- name: quickstart # Send metrics to same cluster (or a dedicated monitoring cluster)
logs:
elasticsearchRefs:
- name: quickstart
Security Configuration
ECK Security (Enabled by Default)
ECK automatically enables security with TLS on both HTTP and transport layers. Key things it manages:
# ECK creates these automatically:
# - Self-signed CA certificate
# - Node transport certificates
# - HTTP certificates
# - elastic superuser with random password
# Retrieve the elastic user password:
kubectl get secret quickstart-es-elastic-user \
-o go-template='{{.data.elastic | base64decode}}'
# Create additional users via the API:
POST _security/user/my-app-user
{
"password": "secure-password-here",
"roles": ["reader"],
"full_name": "App Service Account"
}
# Create a role
POST _security/role/reader
{
"indices": [
{
"names": ["logs-*"],
"privileges": ["read", "view_index_metadata"]
}
]
}
Elastic Certified Engineer — Exam Topics
The exam is hands-on and performance-based. You complete real-world tasks on live Elasticsearch clusters in a proctored environment. The only resource allowed during the exam is the official Elastic documentation.
Exam Domain Breakdown
| Domain | Key Skills |
|---|---|
| Data Management | Define indices, index templates, dynamic templates, ILM policies, data streams, component templates |
| Searching Data | Term/phrase queries, boolean queries, async search, aggregations (metric, bucket, pipeline, sub-aggs), cross-cluster search, runtime fields |
| Developing Search Apps | Highlighting, sorting, pagination, search templates |
| Data Processing | Ingest pipelines, processors (grok, date, geoip, script, etc.), enrich policies, reindex API, update by query |
| Cluster Management | Node roles, shard allocation, cluster settings, snapshots and restore, cross-cluster replication, diagnostics |
Study Checklist
Track your progress through each exam topic. Click items to mark them complete. Your progress is saved in this session.
Data Management
- Create an index with custom settings, mappings, and aliases
- Define and use index templates with patterns
- Create and use component templates
- Define dynamic templates for automatic field mapping
- Set up an ILM policy (hot → warm → cold → delete)
- Create a data stream with matching index template
- Use the Reindex API to migrate data between indices
- Use Update By Query to modify documents in place
- Configure nested object relationships in mappings
Searching Data
- Write term-level queries (term, range, exists, wildcard)
- Write full-text queries (match, multi_match, match_phrase)
- Build bool queries with must, should, filter, must_not
- Execute metric aggregations (avg, sum, min, max, cardinality)
- Execute bucket aggregations (terms, date_histogram, range)
- Write pipeline aggregations (derivative, cumulative_sum)
- Build nested sub-aggregations
- Set up and use async search
- Configure and query across multiple clusters
- Define and use runtime fields in search
Search Applications & Data Processing
- Implement search highlighting
- Sort results by field, score, geo_distance
- Implement pagination (from/size and search_after)
- Create and test ingest pipelines
- Use grok, date, geoip, set, rename, and script processors
- Set up an enrich policy and processor
Cluster Management & ECK
- Diagnose and fix yellow/red cluster health
- Configure shard allocation awareness and filtering
- Set up snapshot repository and take/restore snapshots
- Configure cross-cluster replication (CCR)
- Deploy Elasticsearch on Kubernetes with ECK
- Manage ECK upgrades and scaling operations
- Configure node roles and resource allocation
- Set up security: users, roles, TLS