Friday, 30 May 2025

Introduction to Elastic Agents


Elastic Agents are unified, lightweight software components developed by Elastic to collect, ship, and (optionally) protect data—including logs, metrics, traces, and security events—from your infrastructure to the Elastic Stack (Elasticsearch, Kibana, etc.)


Elastic Agents are not strictly required components in every Elastic Stack deployment, but they play a crucial role in certain scenarios. Here's an explanation based on use cases:


Key Functions of Elastic Agents (When Elastic Agents Are Required?)

  • Unified Data Collection:

    • They provide a single, centralized solution to collect  various types of observability and security data from hosts, containers, and Kubernetes clusters (logs, metrics, traces, and security data)
    • They replace individual Beats (e.g., Filebeat, Metricbeat) for streamlined data ingestion.
  • Kubernetes Monitoring: 
    • When deployed on Kubernetes (often as a DaemonSet), Elastic Agent runs on every node, collecting:
      • System metrics (CPU, memory, disk, etc.)
      • Kubernetes resource metrics (pods, nodes, deployments)
      • Logs from nodes and containers
      • Security posture and events
  • Fleet Management:

    • Elastic Agents can be centrally managed using Elastic Fleet, allowing you to configure, update, and monitor all agents and their integrations from a single Kibana interface
    • Elastic Agents are required when using Fleet, the centralized management interface in Kibana.
    • Fleet allows you to:
      • Manage agent configurations from a single UI.
      • Deploy updates and policies at scale.
      • Monitor agent health and performance.

  • Endpoint Security:
    • Elastic Agents are necessary for using endpoint Security features, like malware detection, endpoint protection, and threat monitoring, host intrusion detection, and Kubernetes Security Posture Management (KSPM)


When Elastic Agents Are Not Required:

  1. Traditional Beats Usage:

    • If you are already using specific Beats (e.g., Filebeat, Metricbeat, Heartbeat) for data collection and do not need unified management, Elastic Agents are optional.
    • Beats can ship data directly to Elasticsearch or Logstash without requiring Fleet or Elastic Agents.
  2. Direct Data Ingestion:

    • If you are ingesting data directly into Elasticsearch via APIs, custom applications, or third-party tools, Elastic Agents are not needed.
  3. Standalone Elastic Stack:

    • For use cases focused purely on search, analytics, or visualization where data is ingested manually or through custom integrations, Elastic Agents are unnecessary.


Key Considerations:

  • Unified Management: Elastic Agents with Fleet simplify large-scale deployments and are recommended for environments with many data sources.
  • Compatibility: Elastic is gradually consolidating data collection around Elastic Agents, so they are the future-proof choice for managing observability and security data.
  • Flexibility: You can still mix and match Elastic Agents and Beats, depending on your requirements.

How Elastic Agents Work in Kubernetes

Deployment

Typically deployed as a DaemonSet so that each Kubernetes node runs an agent instance, ensuring complete coverage for data collection.

Leader Election

One agent may be elected as a leader to handle cluster-wide metrics (like Kubernetes events), while others focus on node-specific data.

Data Flow

Data collected by agents is shipped to Elasticsearch for storage and analysis, and visualized in Kibana


---

In summary, Elastic Agents are not mandatory for all Elastic Stack setups, but they are highly beneficial for unified data collection, centralized management, and security monitoring. 

How to deploy Elastic stack via Elastic Cloud on Kubernetes (ECK)




Elastic Cloud on Kubernetes (ECK):
  • Kubernetes operator
  • Automates the deployment, provisioning, management, and orchestration of Elastic applications on Kubernetes, including:
    • Elasticsearch
    • Kibana
    • APM Server
    • Beats
    • Elastic Agent
    • Elastic Maps Server
    • Logstash



To install Elasticsearch cluster on the existing k8s cluster, we can use ECK Helm charts from "https://helm.elastic.co" repository. These charts need to be installed in the particular order:

  • eck-operator-crds
  • eck-operator
  • eck-elasticsearch
  • eck-kibana
  • eck-fleet-server
  • eck-agent
  • eck-apm-server



Prerequisites


  • AWS EKS cluster with addons
  • User with associated arn:aws:eks::aws:cluster-access-policy/AmazonEKSClusterAdminPolicy

eck-operator-crds



ECK relies on a set of Custom Resource Definitions (CRDs) to define how applications are deployed. CRDs are global (not namespace-specific) resources, shared across the entire Kubernetes cluster, so installing them requires specific permissions (e.g. in AWS EKS, the installer might have role with this associated policy: arn:aws:eks::aws:cluster-access-policy/AmazonEKSClusterAdminPolicy).

This chart installs Elastic Custom Resource Definitions (CRDs). When we install ECK (Elastic's operator for managing Elasticsearch, Kibana, Beats, APM, etc. on Kubernetes), it defines several CRDs. The main kinds include (with their CRD Names and Descriptions):

  • Elasticsearch
    • elasticsearches.elasticsearch.k8s.elastic.co
    • Manages Elasticsearch clusters
  • Kibana
    • kibanas.kibana.k8s.elastic.co
    • Manages Kibana instances
  • ApmServer
    • apmservers.apm.k8s.elastic.co
    • Manages APM Servers
  • Beat
    • beats.beat.k8s.elastic.co
    • Manages Beats (Filebeat, Metricbeat, etc.) agents
  • EnterpriseSearch
    • enterprisesearches.enterprisesearch.k8s.elastic.co
    • Manages Enterprise Search instances

To list all CRDs installed by the "eck-operator-crds" Helm chart:

% kubectl get crd | grep elastic
agents.agent.k8s.elastic.co                             2025-05-15T11:37:50Z
apmservers.apm.k8s.elastic.co                           2025-05-15T11:37:50Z
beats.beat.k8s.elastic.co                               2025-05-15T11:37:50Z
elasticmapsservers.maps.k8s.elastic.co                  2025-05-15T11:37:50Z
elasticsearchautoscalers.autoscaling.k8s.elastic.co     2025-05-15T11:37:50Z
elasticsearches.elasticsearch.k8s.elastic.co            2025-05-15T11:37:50Z
enterprisesearches.enterprisesearch.k8s.elastic.co      2025-05-15T11:37:50Z
kibanas.kibana.k8s.elastic.co                           2025-05-15T11:37:50Z
logstashes.logstash.k8s.elastic.co                      2025-05-15T11:37:50Z
stackconfigpolicies.stackconfigpolicy.k8s.elastic.co    2025-05-15T11:37:50Z


Note that this chart only installs CRDs, not resources of these types! If we deploy only resources of types Agent, APM Server, Elasticsearch and Kibana, the command which lists all resources of Elastic CRD types would return something like this:


% kubectl get elastic -n elastic-system
NAME                                              HEALTH   AVAILABLE   EXPECTED   VERSION   AGE
agent.agent.k8s.elastic.co/my-fleet-agent          green    6           6          9.0.1     28h
agent.agent.k8s.elastic.co/my-fleet-server         green    1           1          9.0.1     2d17h

NAME                                           HEALTH   NODES   VERSION   AGE
apmserver.apm.k8s.elastic.co/my-apm-server     green    1       9.0.1     7h39m

NAME                                                            HEALTH   NODES   VERSION   PHASE   AGE
elasticsearch.elasticsearch.k8s.elastic.co/my-elasticsearch     green    9       9.0.1     Ready   10d

NAME                                       HEALTH   NODES   VERSION   AGE
kibana.kibana.k8s.elastic.co/my-kibana     green    1       9.0.1     10d


The most common resource managed by the ECK operator is Elasticsearch, which represents an Elasticsearch cluster within your Kubernetes environment. The correct command to list all Elasticsearch clusters managed by the operator is:

% kubectl get elasticsearch -n elastic-system

NAME               HEALTH   NODES   VERSION   PHASE   AGE
my-elasticsearch   green    9       9.0.1     Ready   1m




eck-operator




Installs the ECK Operator, which is the official Kubernetes operator from Elastic which helps us deploy and manage (orchestrate) Elastic applications on Kubernetes including:
  • Elasticsearch
  • Kibana
  • APM Server
  • Enterprise Search
  • Beats
  • Elastic Agent
  • Elastic Maps Server

A namespace elastic-system is created where ECK operator runs. 

The "elastic-system" namespace in Elastic Cloud on Kubernetes (ECK) is where the ECK operator itself is deployed. While the operator resides in this namespace, it's recommended to deploy your application workloads (like Elasticsearch and Kibana) in a separate, dedicated namespace, not within elastic-system or the default namespace. elastic-system namespace is used to isolate the ECK operator from accidental deletion and to manage its resources. Deploying workloads in elastic-system could lead to conflicts or accidental deletion of the operator resources. Using a separate namespace provides better organization and isolation. 

Monitoring the operator


eck-elasticsearch


This chart creates an Elasticsearch cluster.

In an Elasticsearch cluster, all Elasticsearch nodes provide the REST API. These nodes are the fundamental building blocks of the cluster and handle data storage, indexing, and search operations. The REST API is exposed on a specific port (usually 9200) and provides a standardized way to interact with the cluster. Elasticsearch uses a RESTful API, which means that requests are sent using standard HTTP methods (GET, POST, PUT, DELETE). The REST API allows you to perform tasks like adding or removing nodes, managing indices, and configuring various cluster settings. You can use the REST API to perform searches, retrieve data, and interact with the documents stored in Elasticsearch. The REST API is accessible to any client that can make HTTP requests, allowing us to integrate with various tools, applications, and programming languages. 

Elasticsearch clusters have a designated master node that is responsible for managing the cluster state and performing certain critical operations. However, it's not a single, dedicated master node in the traditional sense. 

Master-eligible nodes: All nodes in an Elasticsearch cluster are master-eligible by default, meaning any of them can potentially become the master node. 

Elected master: Only one node is actively the master node at any given time. This node is elected from the master-eligible nodes using a distributed consensus algorithm. 

Role of the master: The master node manages the cluster state, which includes:
  • Creating or deleting indexes. 
  • Tracking which nodes are part of the cluster. 
  • Allocating shards to different nodes. 
  • Updating and propagating the cluster state across the cluster. 
Master node elections: If the current master node fails or becomes unavailable, a new master node is automatically elected from the remaining master-eligible nodes, ensuring that the cluster can continue operating. 

High availability: Using dedicated master nodes and a sufficient number of master-eligible nodes ensures high availability, even if one or more nodes fail. 

In essence, while all nodes can potentially be the master, only one is actively managing the cluster at any given time. This ensures that the cluster remains stable and functional, even if the master node fails, as a new one will be elected quickly. 

---
When the Elasticsearch resource is created, a default user named elastic is created automatically, and is assigned the superuser role.

Its password can be retrieved in a Kubernetes secret, whose name is based on the Elasticsearch resource name: <elasticsearch-name>-es-elastic-user.

This user is used for accessing Elasticsearch down the line e.g. if using Elasticsearch Terraform provider. Credentials can be stored in AWS Secrets Manager.
---

When this chart is deployed, ECK Operator automatically creates a Kubernetes service object:
  • By default, its name follows this format: <elasticsearch_cluster_name>-es-http
  • Its roles are:
    • Primary access point: It acts as the main endpoint for clients (such as applications, users, or other services) to interact with the Elasticsearch cluster using the REST API.
    • Handles authentication and TLS: The service is secured by default with TLS and basic authentication, managed by the ECK operator.
    • Traffic distribution: It routes incoming HTTP (REST API) traffic to all Elasticsearch nodes in our cluster, unless we create custom services for more granular routing (for example, to target only data or ingest nodes). 
  • Its type is ClusterIP, meaning it is accessible only within the Kubernetes cluster (from other pods or nodes that are part of the same cluster) unless otherwise configured
  • The service listens on port 9200 (the default Elasticsearch HTTP port) and load-balances requests to the Elasticsearch pods
How to access this service?

Within the Kubernetes cluster we need to use the service DNS name:

https://<elasticsearch_cluster_name>-es-http.<namespace>:9200

For example, if our cluster is named elasticsearch and in the elastic-system namespace:

https://elasticsearch-es-http.elastic-system:9200

We can use the user mentioned above (elastic) that ECK automatically created must provide:
  • The CA certificate (to trust the service’s TLS certificate)
  • The elastic user password (stored in a Kubernetes secret) 
Example:

NAME=elasticsearch
NAMESPACE=elastic-system

kubectl get secret "$NAME-es-http-certs-public" \
-n $NAMESPACE \
-o go-template='{{index .data "tls.crt" | base64decode }}' \
> tls.crt

PW=$(\
kubectl get secret "$NAME-es-elastic-user" \
-n $NAMESPACE \
-o go-template='{{.data.elastic | base64decode }}')

curl \
--cacert tls.crt \
-u elastic:$PW \
https://$NAME-es-http.$NAMESPACE:9200/

To access it from outside the cluster we need to change the service type to LoadBalancer or use an Ingress to expose it externally. 

When using LoadBalancer, the service will get an external IP address, and we can access it via https://<external-ip>:9200

We need to be sure to secure access appropriately, as this exposes our Elasticsearch cluster to external networks.

---

When Elasticsearch is created, we can create Elastic Serverless Forwarder.


eck-kibana



Installs Kibana.
Creates Kubernetes service object. Its name follows this format: <kibana_name>-kb-http.

To expose this service externally, we can create an Ingress.


Now, when Kibana is installed, we can crate:
  • snapshot repositories. They can be S3-backed.
  • Kibana users. Each user is assigned a set of predefined Kibana roles.
  • Index lifecycle rules
  • Component templates (which reference those lifecycle rules) 


eck-fleet-server


Creates Kubernetes service object. Its name follows this pattern: <fleet_server_name>-agent-http.

To expose this service externally, we can create Fleet Server Ingress.


After Fleet Server is crated, we can install:
  • Fleet Integrations, like:
    • system
    • fleet_server
    • elastic_agent
    • kibana
    • elasticsearch
    • kubernetes
    • apm
    • aws
  • Fleet Agent Policies
    • Fleet Server can have its own policy
      • e.g. sys_monitoring can be disabled while monitor_logs and monitor_metrics enabled
    • Fleet Agents have their own policy
      • e.g. all monitoring types enabled
  • Fleet Integration Policies
    • They define:
      • which agent policy should be associated with which integration
      • inputs

eck-agent



This Helm chart deploys:
  • Elastic Agent Custom Resource
    • The chart creates one or more Elastic Agent custom resources (Agent), which are Kubernetes objects managed by the ECK operator.
    • These resources define how Elastic Agents are deployed, configured, and connected to your Elasticsearch and Kibana instances.
  • Associated Kubernetes Resources
    • The Agent custom resource triggers the ECK operator to create the necessary Kubernetes resources, such as:
      • Pods/DaemonSets: Runs the Elastic Agent containers on your nodes. Elastic Agents are typically deployed as pods (usually via a DaemonSet or Deployment) in a namespace such as kube-system or elastic-agent. These pods execute the Elastic Agent binary, which collects data and communicates with the Fleet Server.
      • ConfigMaps/Secrets: Stores configuration and credentials for the agents.
      • ServiceAccounts, Roles, RoleBindings: Manages permissions for the agents to interact with the Kubernetes API if needed.
  • Fleet Integration (Optional)
    • The chart can configure Elastic Agents to enroll with Elastic Fleet, allowing for centralized management of agent policies and integrations.

We can specify the mode of Agent to use. Only set to "fleet" when Fleet Server is enabled. Default value is:

mode: "fleet"

Both `mode: fleet` and `fleetServerEnabled: true` need to be set for Fleet Server to be enabled. By default, the Agent does NOT act as the Fleet Server:

fleetServerEnabled: false

We need to provide a DaemonSet, StatefulSet, or Deployment specification for Agent.

Some Elastic Agent features, such as the Kubernetes integration, require that Agent Pods interact with Kubernetes APIs. This functionality requires specific permissions. This is why Elastic Agent runs on behalf of its own service account. Its default value is elastic-agent:

serviceAccount:
  name: elastic-agent


We also need to provide policyID which determines into which Agent Policy this Agent will be enrolled. Default value is:

policyID: eck-agent


---

Typical Use Cases

  • Observability: Collect logs, metrics, and traces from Kubernetes workloads and nodes.
  • Security: Use Elastic Agent for security monitoring and data shipping.
  • Fleet Management: Centrally manage agent configurations using Elastic Fleet.

Example: What we might see deployed

An Agent resource in your chosen namespace (e.g., elastic-agent).
One or more Elastic Agent pods (as a DaemonSet or Deployment, depending on configuration).
Supporting Kubernetes resources for configuration and permissions.

How to Verify

After installing the chart (e.g., with helm install elastic-agent elastic/eck-agent -n elastic-agent --create-namespace), we can check:

kubectl get agent -n elastic-agent
kubectl get pods -n elastic-agent

If we installed the Helm chart in the elastic-system namespace, we might have see the output like here: 

% kubectl get agent -n elastic-system
NAME                 HEALTH   AVAILABLE   EXPECTED   VERSION   AGE
my-agent             green    6           6          9.0.1     47h
my-fleet-server      green    1           1          9.0.1     3d12h


To find all agent pods and their labels:

% kubectl get pods --show-labels -n elastic-system | grep agent 

The command above lists all pods with agent in their name and/or label and their labels which are:
  • common.k8s.elastic.co/type=agent <-- this shows that pod is running Agent (of Elastic CRD type)
  • agent.k8s.elastic.co/name=<helm_installation_name>-eck-agent
  • agent.k8s.elastic.co/version=version set int version attribute in chart values
Now when we know pods' labels, we can target only that we are interested in. For example, we want to check the status of all Elastic Agent pods:

% kubectl get pods -l common.k8s.elastic.co/type=agent -n elastic-system -o wide


The Elastic Agent pods running in your Kubernetes cluster and the agents listed in Kibana’s Fleet UI are directly related (each pod running ok in cluster represents a healthy Agent in Kibana) but represent different layers of abstraction (Kubernetes vs Fleet Layer). This applies both for Elastic Fleet Server Agent and regular Elastic Agents.

Agents in Kibana UI (Fleet Layer)

Agents registered with Fleet Server and visible in Kibana’s Fleet > Agents UI. These represent logical agents managed by Fleet, regardless of their deployment method (Kubernetes, VMs, etc.).

Statuses:
  • Online: Agent is actively communicating with Fleet Server.
  • Offline: Agent has not checked in with Fleet Server recently (default: 2 minutes).

TODO: Why Some Agents Appear Offline in Kibana?

In Kibana UI we can see that each agent has its associated Agent Policy. Elastic Agent policies are central configurations that define what data Elastic Agents should collect, how they should collect it, and where to send it. Each Elastic Agent can only be enrolled in a single policy, which contains a set of integration policies specifying the configuration for each type of data input (such as logs, metrics, security events, etc.)

Elastic Agent policy revisions are version numbers that track changes made to an Elastic Agent policy over time. Each time we update a policy—such as adding or removing integrations, changing configuration settings, or modifying outputs—the policy’s revision number is incremented. This revision number is included in the policy sent to each enrolled Elastic Agent, allowing both Fleet and the agents themselves to know which version of the policy is currently applied.

Who manages policy revisions?
  • Fleet (in Kibana) manages policy revisions automatically. When you make any change to an agent policy through the Fleet UI or API, Fleet increments the revision number and distributes the updated policy to all agents enrolled in that policy.
  • Users do not manually set or manage the revision number; it is handled by the Fleet management system.
Purpose and Benefits
  • Change tracking: The revision number helps track when and how a policy has changed. Each agent reports which policy revision it is using, making it easy to see if agents are up to date.
  • Troubleshooting: If agents are not behaving as expected, the revision number can help correlate issues with recent policy changes.
  • Auditability: While the revision number itself does not provide a full change history, it signals that a change has occurred. (Note: The Fleet UI does not currently provide a detailed revision history with user attribution)
Rolling out new policy versions

When we change an Elastic Agent policy (which increments its version number), the updated policy is rolled out immediately to all agents enrolled in that policy. Fleet distributes the new policy as soon as we save our changes, and agents will attempt to fetch and apply the updated configuration right away.

Immediate distribution: 
Any changes to a policy or its integrations are immediately sent to all enrolled agents.

Agent update timing: 
Agents regularly check in with Fleet Server. Upon their next check-in, they detect the new policy revision and apply it, usually within a few seconds to a couple of minutes.

Status indication: 
While the policy is being applied, the agent status in the Fleet UI may briefly show as "Updating" before returning to "Healthy" once the new policy is active.

No manual intervention required: 
We do not need to manually trigger the rollout; it is automatic and managed by Fleet.

Policy changes are automatically and quickly rolled out to all affected Elastic Agents, ensuring configurations stay consistent and up to date across your infrastructure



eck-apm-server


Creates Kubernetes service which name follows this format: <apm_server_name>-apm-http

To expose this service externally, we can crate APM Server Ingress.

...



How to test ECK cluster health?



If we've set in Route53 a record that resolves elasticsearch.mycorp.com into Elasticsearch Load Balancer DNS name, we can use:

% curl -u ‘user:pass’ -X GET 'https://elasticsearch.mycorp.com:443/_cluster/health?pretty'
{
  "cluster_name" : "elasticsearch-prod",
  "status" : "green",
  "timed_out" : false,
  "number_of_nodes" : 9,
  "number_of_data_nodes" : 9,
  "active_primary_shards" : 106,
  "active_shards" : 212,
  "relocating_shards" : 0,
  "initializing_shards" : 0,
  "unassigned_shards" : 0,
  "unassigned_primary_shards" : 0,
  "delayed_unassigned_shards" : 0,
  "number_of_pending_tasks" : 0,
  "number_of_in_flight_fetch" : 0,
  "task_max_waiting_in_queue_millis" : 0,
  "active_shards_percent_as_number" : 100.0
}


Verify that all instances of any of elastic CRDs is in green state:

% kubectl get elastic -n elastic-system


Check indices. Verify that each index has health=green and status=open and that has 1 primary and 1 replica shard.


Check shards. Verify that each shard has state=STARTED.





---

Friday, 16 May 2025

How to use Helm charts

Case study: we want to install Elasticsearch via Helm chart. 

From  Elastic Stack Helm chart | Elastic Docs we can see that Elastic offers a repository of Helm charts: https://helm.elastic.co

Inspecting the local Helm repositories


Before adding some repo to our local system, we can check if that repo has already been added:

% helm repo list

NAME    URL
stable  https://charts.helm.sh/stable
bitnami https://charts.bitnami.com/bitnami

Each entry includes:
  • NAME: The local alias you’ve given to the repo.
  • URL: The actual remote chart repository URL.

Adding a new Helm repository


We first need to add Elastic Helm repository to our local Helm repository list:

% helm repo add elastic https://helm.elastic.co

We can choose an arbitrary local name for the repository we're adding. We used elastic as repository is provided by Elastic.


The next step is to update information of available charts locally from all added chart repositories, or from the one we've just added:

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

helm repo update basically downloads all Helm charts from a given repo to our local registry.


To update repo index (fetch latest chart versions) for all local repositories:

% helm repo update


Inspecting charts in a local Helm repository


Let's now list all charts in elastic repository:

% helm search repo elastic
NAME                          CHART VERSION APP VERSION DESCRIPTION                                       
elastic/eck-elasticsearch    0.15.0                    Elasticsearch managed by the ECK operator         
elastic/elastic-agent        9.0.1        9.0.1      Elastic-Agent Helm Chart                          
elastic/elasticsearch        8.5.1        8.5.1      Official Elastic helm chart for Elasticsearch     
elastic/apm-attacher          1.1.3                    A Helm chart installing the Elastic APM Kuberne...
elastic/apm-server            8.5.1        8.5.1      Official Elastic helm chart for Elastic APM Server
elastic/eck-agent            0.15.0                    Elastic Agent managed by the ECK operator         
elastic/eck-apm-server        0.15.0                    Elastic APM Server managed by the ECK operator    
elastic/eck-beats            0.15.0                    Elastic Beats managed by the ECK operator         
elastic/eck-enterprise-search 0.15.0                    Elastic Enterprise Search managed by the ECK op...
elastic/eck-fleet-server      0.15.0                    Elastic Fleet Server as an Agent managed by the...
elastic/eck-kibana            0.15.0                    Kibana managed by the ECK operator                
elastic/eck-logstash          0.15.0                    Logstash managed by the ECK operator              
elastic/eck-operator          3.0.0        3.0.0      Elastic Cloud on Kubernetes (ECK) operator        
elastic/eck-operator-crds    3.0.0        3.0.0      ECK operator Custom Resource Definitions          
elastic/eck-stack            0.15.0                    Elastic Stack managed by the ECK Operator         
elastic/filebeat              8.5.1        8.5.1      Official Elastic helm chart for Filebeat          
elastic/kibana                8.5.1        8.5.1      Official Elastic helm chart for Kibana            
elastic/kube-state-metrics    5.30.1        2.15.0      Install kube-state-metrics to generate and expo...
elastic/logstash              8.5.1        8.5.1      Official Elastic helm chart for Logstash          
elastic/metricbeat            8.5.1        8.5.1      Official Elastic helm chart for Metricbeat        
elastic/pf-host-agent        8.14.3        8.14.3      Hyperscaler software efficiency. For everybody.   
elastic/profiling-agent      9.0.0        9.0.0      Hyperscaler software efficiency. For everybody.   
elastic/profiling-collector  9.0.0        9.0.0      Universal Profiling. Hyperscaler software effic...
elastic/profiling-symbolizer 9.0.0        9.0.0      Universal Profiling. Hyperscaler software effic...



Another way of checking all charts is to download index.yaml file from the remote repository. It contains information of ALL versions of ALL charts in the repo:


% curl https://helm.elastic.co/index.yaml
...
  - apiVersion: v2
    appVersion: 8.15.0
    created: "2024-08-08T09:05:09.582088545Z"
    description: 'Universal Profiling. Hyperscaler software efficiency. For everybody. '
    digest: 9f6a78ed179cda2792259ad7c73db32c2753bf5e3317135fca52fbfb48a8063c
    icon: https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt6ec3007768940247/63337a1f4d11fa0cfdb55244/illustration-deployment-3-arrows.png
    kubeVersion: '>= 1.22.0-0'
    name: profiling-symbolizer
    urls:
    - https://helm.elastic.co/helm/profiling-symbolizer/profiling-symbolizer-8.15.0.tgz
    version: 8.15.0
  - apiVersion: v2
    appVersion: 8.14.3
    created: "2024-07-11T13:35:06.289007371Z"
    description: 'Universal Profiling. Hyperscaler software efficiency. For everybody. '
    digest: 9d1656e80f9c96c3cf7fa2d0692c7318e34e20ff6ad1da13a6b4dae1c82bc990
    icon: https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt6ec3007768940247/63337a1f4d11fa0cfdb55244/illustration-deployment-3-arrows.png
    kubeVersion: '>= 1.22.0-0'
    name: profiling-symbolizer
    urls:
    - https://helm.elastic.co/helm/profiling-symbolizer/profiling-symbolizer-8.14.3.tgz
    version: 8.14.3
...

To see only versions of some particular chart e.g. eck-elasticsearch:

% curl -s https://helm.elastic.co/index.yaml | grep eck-elasticsearch
  eck-elasticsearch:
    name: eck-elasticsearch
    - https://helm.elastic.co/helm/eck-elasticsearch/eck-elasticsearch-0.15.0.tgz
    name: eck-elasticsearch
    - https://helm.elastic.co/helm/eck-elasticsearch/eck-elasticsearch-0.14.1.tgz
    name: eck-elasticsearch
    - https://helm.elastic.co/helm/eck-elasticsearch/eck-elasticsearch-0.14.0.tgz
    name: eck-elasticsearch
    - https://helm.elastic.co/helm/eck-elasticsearch/eck-elasticsearch-0.13.0.tgz
    name: eck-elasticsearch
    - https://helm.elastic.co/helm/eck-elasticsearch/eck-elasticsearch-0.12.1.tgz
    name: eck-elasticsearch
    - https://helm.elastic.co/helm/eck-elasticsearch/eck-elasticsearch-0.12.0.tgz
    name: eck-elasticsearch
    - https://helm.elastic.co/helm/eck-elasticsearch/eck-elasticsearch-0.11.0.tgz
    name: eck-elasticsearch
    - https://helm.elastic.co/helm/eck-elasticsearch/eck-elasticsearch-0.10.0.tgz
    name: eck-elasticsearch
    - https://helm.elastic.co/helm/eck-elasticsearch/eck-elasticsearch-0.9.1.tgz
    name: eck-elasticsearch
    - https://helm.elastic.co/helm/eck-elasticsearch/eck-elasticsearch-0.9.0.tgz
    name: eck-elasticsearch
    - https://helm.elastic.co/helm/eck-elasticsearch/eck-elasticsearch-0.8.0.tgz
    name: eck-elasticsearch
    - https://helm.elastic.co/helm/eck-elasticsearch/eck-elasticsearch-0.7.0.tgz
    name: eck-elasticsearch
    - https://helm.elastic.co/helm/eck-elasticsearch/eck-elasticsearch-0.7.0-SNAPSHOT.tgz
    name: eck-elasticsearch
    - https://helm.elastic.co/helm/eck-elasticsearch/eck-elasticsearch-0.6.0.tgz
    name: eck-elasticsearch
    - https://helm.elastic.co/helm/eck-elasticsearch/eck-elasticsearch-0.4.0.tgz
    name: eck-elasticsearch
    - https://helm.elastic.co/helm/eck-elasticsearch/eck-elasticsearch-0.3.0.tgz
    name: eck-elasticsearch
    - https://helm.elastic.co/helm/eck-elasticsearch/eck-elasticsearch-0.2.0.tgz
    name: eck-elasticsearch
    - https://helm.elastic.co/helm/eck-elasticsearch/eck-elasticsearch-0.1.1.tgz
    name: eck-elasticsearch
    - https://helm.elastic.co/helm/eck-elasticsearch/eck-elasticsearch-0.1.0.tgz
    - condition: eck-elasticsearch.enabled
      name: eck-elasticsearch
    - condition: eck-elasticsearch.enabled
      name: eck-elasticsearch
    ...

As the response is YAML document, we can use yq tool to extract exactly what we need:

% curl -s https://helm.elastic.co/index.yaml | yq '.entries | to_entries | .[].value[] | select(.name == "eck-elasticsearch") | "Name: " + .name + "\nVersion: " + .version + "\n\n"'

Name: eck-elasticsearch
Version: 0.15.0

Name: eck-elasticsearch
Version: 0.14.1

Name: eck-elasticsearch
Version: 0.14.0

Name: eck-elasticsearch
Version: 0.13.0

Name: eck-elasticsearch
Version: 0.12.1

...


Let's say we want to install elastic/eck-elasticsearch chart (note that elastic is the local name for elastic chart repo and eck-elasticsearch is the name of the chart). How can we find its default values?

% helm show values elastic/eck-elasticsearch 
---
# Default values for eck-elasticsearch.
# This is a YAML-formatted file.

# Overridable names of the Elasticsearch resource.
# By default, this is the Release name set for the chart,
# followed by 'eck-elasticsearch'.
#
# nameOverride will override the name of the Chart with the name set here,
# so nameOverride: quickstart, would convert to '{{ Release.name }}-quickstart'
#
# nameOverride: "quickstart"
#
# fullnameOverride will override both the release name, and the chart name,
# and will name the Elasticsearch resource exactly as specified.
#
# fullnameOverride: "quickstart"

# Version of Elasticsearch.
#
version: 9.0.0

# Elasticsearch Docker image to deploy
#
# image:

# Labels that will be applied to Elasticsearch.
#
labels: {}

# Annotations that will be applied to Elasticsearch.
#
annotations: {}

# Settings for configuring Elasticsearch users and roles.
# ref: https://www.elastic.co/guide/en/cloud-on-k8s/current/k8s-users-and-roles.html
#
auth: {}

# Settings for configuring stack monitoring.
# ref: https://www.elastic.co/guide/en/cloud-on-k8s/current/k8s-stack-monitoring.html
#
monitoring: {}
  # metrics:
  #   elasticsearchRefs:
  #   - name: monitoring
  #     namespace: observability
  # logs:
  #   elasticsearchRefs:
  #   - name: monitoring
  #     namespace: observability
...
...
 
We can save this document into a local yaml file which we can then modify and adjust to our needs:

% helm show values elastic/eck-elasticsearch > eck-elasticsearch-values.yaml


Export only overrides:

helm get values tempo -n grafana-tempo -o yaml > tempo-values.yaml

Export full computed values:

helm get values tempo -n grafana-tempo --all -o yaml > tempo-values-full.yaml

The --all version includes defaults Helm is currently using

If Terraform shows drift, switch to the --all version


How to find what is the latest version of some chart?


Example: We want to find the latest version of chart "tempo" from repository "https://grafana.github.io/helm-charts".

1. Add the Grafana Helm repo (if not already added)

% helm repo add grafana https://grafana.github.io/helm-charts
"grafana" has been added to your repositories

2. Update local index of charts

% helm repo update grafana

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

3. List all versions of the tempo chart

% helm search repo grafana/tempo --versions
NAME                            CHART VERSION   APP VERSION     DESCRIPTION                                       
grafana/tempo                   1.24.4          2.9.0           Grafana Tempo Single Binary Mode                  
grafana/tempo                   1.24.3          2.9.0           Grafana Tempo Single Binary Mode                  
grafana/tempo                   1.24.2          2.9.0           Grafana Tempo Single Binary Mode                  
...                
grafana/tempo                   0.6.0           v0.6.0          Grafana Tempo Single Binary Mode                  
grafana/tempo                   0.5.0           v0.5.0          Grafana Tempo Single Binary Mode                  
grafana/tempo-distributed       1.61.3          2.9.0           Grafana Tempo in MicroService mode                
grafana/tempo-distributed       1.61.2          2.9.0           Grafana Tempo in MicroService mode                    
...              
grafana/tempo-distributed       0.6.0           0.6.0           Grafana Tempo in MicroService mode                
grafana/tempo-vulture           0.10.1          2.9.0           Grafana Tempo Vulture - A tool to monitor Tempo...
...
grafana/tempo-vulture           0.1.0           0.7.0           Grafana Tempo Vulture - A tool to monitor Tempo...

How to find which resources will Helm chart deploy?


We have few options:

1) Dry-run install the chart and inspect output


% helm install my-fleet-server elastic/eck-fleet-server --dry-run --debug

This will render the templates using default values (or our custom --values file) and print all the generated Kubernetes YAML to stdout.

We need to look for Look for: Deployment, Service, Secret, ConfigMap, Pod or any custom resources (Agent, etc.).

2) Download the chart locally and inspect the templates


% helm pull elastic/eck-fleet-server --untar
% cd eck-fleet-server

Now we can inspect the files under templates/ and values.yaml.

We'll see:
  • All the resource templates (deployment.yaml, service.yaml, etc.)
  • Which fields can be customized.

3) Search the Helm chart source code on GitHub

We can inspect:
  • templates/ folder – actual YAML templates
  • values.yaml – configurable inputs
  • Chart.yaml – metadata


Installing Helm chart


To deploy Helm chart into the Kubernetes cluster by using our own values:

% helm install \
   my-elasticsearch \
   elastic/eck-elasticsearch \
   -f eck-elasticsearch-values.yaml \
   -n elastic-system \
   --create-namespace

We chose to deploy it in a custom namespace which we named elastic-system.


By default, helm install installs the chart into the Kubernetes cluster our kubectl is currently configured to use. Helm relies on the kubeconfig file (typically located at ~/.kube/config) to know which cluster to interact with.

helm install:
  • Reads the kubeconfig file used by kubectl.
  • Connects to the current Kubernetes context (cluster and namespace).
  • Installs the Helm chart to that cluster, unless you override the context or namespace.


We can control the target cluster and namespace using the following:

helm install my-release elastic/eck-elasticsearch --kube-context=my-cluster-context


To list contexts:

kubectl config get-contexts


To switch context:

kubectl config use-context my-cluster-context


Before we attempt to target a remote Kubernetes cluster, we need to ensure that:
  • Our ~/.kube/config contains valid credentials and cluster info.
  • We can interact with it using kubectl (test with kubectl get nodes or kubectl get pods).


To remove the repo from the local system:

% helm repo remove elastic

---

Friday, 28 March 2025

Automatic Component Template Matching for Custom Component Templates in Elasticsearch




Index templates in Elasticsearch specify index mappings, settings, and aliases.

Component templates are building blocks for constructing index templates.

An index template can be composed of multiple component templates. To use a component template, specify it in an index template’s composed_of list. 

Both index and component templates can be managed (created by Elasticsearch by default) and custom (created later, by users).


Automatic Component Template Matching


Key Mechanism: Custom Template Integration


Elasticsearch uses a pattern-based auto-matching for component templates. Component templates with a shared prefix can be automatically applied to matching index templates. This is different from manual explicit addition to composed_of.


Matching Rules


Component templates are matched based on their naming prefix. Index templates with similar prefixes automatically incorporate these component templates. The matching is done through an intelligent, behind-the-scenes process.


Example Scenario


Any index template whose name starts with "traces-" will automatically pick up the managed component templates "traces@settings" and "traces@mappings", as well as the custom component template "traces@custom" if it exists. This behavior is based on Elasticsearch's composable index template system and naming conventions.

Elasticsearch automatically creates managed index templates for various data types, including traces. These templates typically include references to managed component templates like "traces@settings" and "traces@mappings". The managed index templates also include a reference to a custom component template named "traces@custom" by default, even if it doesn't exist initially.

Automatic Pickup: When we create a custom component template named traces@custom, it is automatically integrated into the existing index template without requiring manual addition to the composed_of list.

When a new index matching the pattern defined in the index template (e.g., traces-*) is created, Elasticsearch applies all the referenced component templates, including the custom one.

Component Template: traces@custom

Matching Index Templates:

- traces-apm.sampled
- traces-apm.rum
- traces-apm.backend
- traces-...

How Auto-Matching Works


When a component template is created with a specific prefix, Elasticsearch scans existing index templates. It automatically adds the component template to index templates with matching prefixes. This happens without manually updating the composed_of list.

The automatic prefix-based matching applies to:
  • Elasticsearch-managed (built-in) templates (e.g., metrics, logs, APM templates)
  • User-created managed index templates (created via _index_template API)
It does NOT apply to legacy index templates created with the older _template API.

So when we added traces@custom and saw it automatically applied to multiple index templates like traces-apm.sampled, we were seeing the matching against Elasticsearch's managed templates and user-created managed templates.

When a component template is created (e.g., traces@custom):
  • Elasticsearch scans ALL existing index templates
  • Automatically adds the component template to matching index templates
  • Matching is based on prefix, regardless of template origin.

Naming Convention Impact


Prefix matching is crucial.

traces@custom will match templates starting with traces-.
metrics@custom would match metrics- prefixed templates.

Prefix-based matching is a system-wide feature, not limited to custom or user-created templates. It applies uniformly across all managed index templates.

This system allows for easy customization of index settings and mappings without modifying the managed templates directly. It's important to note that while custom templates are automatically picked up, they must still be created manually if you want to add custom configurations.

---

Friday, 28 February 2025

Introduction to GitHub CLI

 


git CLI client can perform some usual tasks with the repo like creating it, cloning, commiting and pushing updates etc but some of the common actions are specific to git repository provider like GitHub or GitLab and can't be done with git client only. Such actions are creating a pull request, checking assigned issues, review requests, adding a comment to pull request etc. This article is a short intro into GitHub's CLI client, gh.

Installation


To install it on Mac:

% brew install gh 

No admin (sudo) permissions are required. 

To verify installation:

% gh
Work seamlessly with GitHub from the command line.

USAGE
  gh <command> <subcommand> [flags]

CORE COMMANDS
  auth:        Authenticate gh and git with GitHub
  browse:      Open repositories, issues, pull requests, and more in the browser
  codespace:   Connect to and manage codespaces
  gist:        Manage gists
  issue:       Manage issues
  org:         Manage organizations
  pr:          Manage pull requests
  project:     Work with GitHub Projects.
  release:     Manage releases
  repo:        Manage repositories

GITHUB ACTIONS COMMANDS
  cache:       Manage GitHub Actions caches
  run:         View details about workflow runs
  workflow:    View details about GitHub Actions workflows

ALIAS COMMANDS
  co:          Alias for "pr checkout"

ADDITIONAL COMMANDS
  alias:       Create command shortcuts
  api:         Make an authenticated GitHub API request
  attestation: Work with artifact attestations
  completion:  Generate shell completion scripts
  config:      Manage configuration for gh
  extension:   Manage gh extensions
  gpg-key:     Manage GPG keys
  label:       Manage labels
  ruleset:     View info about repo rulesets
  search:      Search for repositories, issues, and pull requests
  secret:      Manage GitHub secrets
  ssh-key:     Manage SSH keys
  status:      Print information about relevant issues, pull requests, and notifications across repositories
  variable:    Manage GitHub Actions variables

HELP TOPICS
  actions:     Learn about working with GitHub Actions
  environment: Environment variables that can be used with gh
  exit-codes:  Exit codes used by gh
  formatting:  Formatting options for JSON data exported from gh
  mintty:      Information about using gh with MinTTY
  reference:   A comprehensive reference of all gh commands

FLAGS
  --help      Show help for command
  --version   Show gh version

EXAMPLES
  $ gh issue create
  $ gh repo clone cli/cli
  $ gh pr checkout 321

LEARN MORE
  Use `gh <command> <subcommand> --help` for more information about a command.
  Read the manual at https://cli.github.com/manual
  Learn about exit codes using `gh help exit-codes`


Setting up authentication with GitHub


In GitHub website, to to Settings >> Developer Settings >> Personal access tokens and create a token with desired permissions. Copy its value and add the following environment variable to your personal settings of the terminal you use:

export GH_TOKEN=<github_personal_access_token_value>

% vi ~/.zshrc
% source ~/.zshrc

% vi ~/.bash_profile
% source ~/.bash_profile

To verify it, execute this in each terminal:

% echo $GH_TOKEN 

The output should be <github_personal_access_token_value>.


Checking the status across multiple repositories 

To check the status of the GitHub account repositories

% gh status
Assigned Issues
...
Assigned Pull Requests
...
Review Requests
...
Mentions
...
Repository Activity
...


Working with Pull Requests

Here are some common commands used to manage pull requests but make sure you are in the directory which is a GitHub repository otherwise gh will emit the error like:

failed to run git: fatal: not a git repository (or any of the parent directories): .git


To view all pull requests in a repository:

% gh pr list

It lists all open pull requests in the current repository. Use --state closed or --state all to see merged/closed PRs.

To view a specific pull request:

% gh pr view <PR_NUMBER>

or

% gh pr view <PR_URL>

It displays details of a specific PR, including description, status, and mergeability.

To open a pull request in the browser:

% gh pr view <PR_NUMBER> --web

It opens the PR page in your default web browser.

To show PRs created by you:

% gh pr list --author @me

To show PRs assigned to you:

% gh pr list --assignee @me


Working with GitHub Workflows


The main command for working with workflows is - workflow. Let's see the list of its subcommands:


% gh workflow                               
List, view, and run workflows in GitHub Actions.

USAGE
  gh workflow <command> [flags]

AVAILABLE COMMANDS
  disable:     Disable a workflow
  enable:      Enable a workflow
  list:        List workflows
  run:         Run a workflow by creating a workflow_dispatch event
  view:        View the summary of a workflow

FLAGS
  -R, --repo [HOST/]OWNER/REPO   Select another repository using the [HOST/]OWNER/REPO format

INHERITED FLAGS
  --help   Show help for command


To show all workflows and their IDs in the current repository:

gh workflow list

NAME                      STATE   ID       
my-workflow               active  131118881
...

To see the details of some workflow:

% gh workflow view my-workflow
my-workflow - my-workflow.yaml
ID: 131118881

Total runs 2
Recent runs
   TITLE        WORKFLOW     BRANCH                    EVENT              ID         
✓  my-workflow  my-workflow  project/app-upgrade/test  workflow_dispatch  13543363356
X  my-workflow  my-workflow  project/app-upgrade/test  workflow_dispatch  13158297800

To see more runs for this workflow, try: gh run list --workflow my-workflow.yaml
To see the YAML for this workflow, try: gh workflow view my-workflow.yaml --yaml

To run a workflow by creating a workflow_dispatch event:

% gh workflow run <workflow.yml> --ref <branch_name>

After triggering the workflow, you can check the status with:

% gh run list

Or check the logs of a specific run:

% gh run watch

If your workflow requires inputs, pass them using --json:

% gh workflow run build.yml --ref main --json '{"environment":"staging"}'

To see more details of a specific run:

% gh run view <run_id>

To cancel a running workflow:

% gh run cancel <run_id>


Working with GitHub Workflow Runs



% gh run 
List, view, and watch recent workflow runs from GitHub Actions.

USAGE
  gh run <command> [flags]

AVAILABLE COMMANDS
  cancel:      Cancel a workflow run
  delete:      Delete a workflow run
  download:    Download artifacts generated by a workflow run
  list:        List recent workflow runs
  rerun:       Rerun a run
  view:        View a summary of a workflow run
  watch:       Watch a run until it completes, showing its progress

FLAGS
  -R, --repo [HOST/]OWNER/REPO   Select another repository using the [HOST/]OWNER/REPO format

INHERITED FLAGS
  --help   Show help for command



% gh run list --help 
List recent workflow runs.

Note that providing the `workflow_name` to the `-w` flag will not fetch disabled workflows.
Also pass the `-a` flag to fetch disabled workflow runs using the `workflow_name` and the `-w` flag.

For more information about output formatting flags, see `gh help formatting`.

USAGE
  gh run list [flags]

ALIASES
  gh run ls

FLAGS
  -a, --all               Include disabled workflows
  -b, --branch string     Filter runs by branch
  -c, --commit SHA        Filter runs by the SHA of the commit
      --created date      Filter runs by the date it was created
  -e, --event event       Filter runs by which event triggered the run
  -q, --jq expression     Filter JSON output using a jq expression
      --json fields       Output JSON with the specified fields
  -L, --limit int         Maximum number of runs to fetch (default 20)
  -s, --status string     Filter runs by status: {queued|completed|in_progress|requested|waiting|pending|action_required|cancelled|failure|neutral|skipped|stale|startup_failure|success|timed_out}
  -t, --template string   Format JSON output using a Go template; see "gh help formatting"
  -u, --user string       Filter runs by user who triggered the run
  -w, --workflow string   Filter runs by workflow

INHERITED FLAGS
      --help                     Show help for command
  -R, --repo [HOST/]OWNER/REPO   Select another repository using the [HOST/]OWNER/REPO format

JSON FIELDS
  attempt, conclusion, createdAt, databaseId, displayTitle, event, headBranch,
  headSha, name, number, startedAt, status, updatedAt, url, workflowDatabaseId,
  workflowName

LEARN MORE
  Use `gh <command> <subcommand> --help` for more information about a command.
  Read the manual at https://cli.github.com/manual
  Learn about exit codes using `gh help exit-codes`

bojan@admins-MacBook-Pro.local /Users/bojan/repos/CheckpointGG/infra-elastic [project/elastic-upgrade/test]
% gh run list --json --help
Unknown JSON field: "--help"
Available fields:
  attempt
  conclusion
  createdAt
  databaseId
  displayTitle
  event
  headBranch
  headSha
  name
  number
  startedAt
  status
  updatedAt
  url
  workflowDatabaseId
  workflowName

---