elk-stack — Claude Code skill: what it does, how to install
Deploys Elasticsearch, Logstash, Kibana, and Filebeat via Docker, setting up log ingestion pipelines and lifecycle retention policies.
npx skills add BagelHole/DevOps-Security-Agent-Skills --skill elk-stack -a claude-codeWhat elk-stack does
This skill provides Docker Compose templates and configurations to run Elasticsearch 8.11.0, Logstash, Kibana, and Filebeat. It includes Logstash pipelines to parse incoming JSON payloads, extract Nginx access logs via grok, enrich client IPs with GeoIP, and filter records by trace_id.
It also configures Elasticsearch index templates and Index Lifecycle Management (ILM) for logs-*. Hot storage rolls over at 50 GB or 1 day, indexes shrink after 7 days, and delete automatically after 90 days. Aggregation queries and Kibana index pattern setups are included.
Docker and disk space are strict requirements. The default compose file disables authentication via xpack.security.enabled=false. Exposing this setup without an internal network boundary creates an immediate risk.
What it helps with
- deploy the ELK stack and Filebeat using Docker Compose
- parse structured JSON and Nginx access logs in Logstash
- enforce index retention and lifecycle policies with Elasticsearch ILM
- query error rates and aggregate logs for Kibana dashboards
Example prompts for the agent
- Generate a docker-compose.yml file for ELK 8.11.0 with Filebeat
- Configure a Logstash pipeline to parse Nginx logs and drop debug events
- Write an Elasticsearch ILM policy to delete logs after 90 days
How to install elk-stack
1Skills CLI (Vercel)
npx skills add BagelHole/DevOps-Security-Agent-Skills --skill elk-stack -a claude-code2Manually: put the files in place
~/.claude/skills/elk-stack/SKILL.mdCopy the whole skill folder; for one project use .claude/skills/elk-stack/
1Skills CLI (Vercel)
npx skills add BagelHole/DevOps-Security-Agent-Skills --skill elk-stack -a codex2Manually: put the files in place
.agents/skills/elk-stack/SKILL.mdFor all projects use ~/.agents/skills/
1Skills CLI (Vercel)
npx skills add BagelHole/DevOps-Security-Agent-Skills --skill elk-stack -a cursor2Manually: put the files in place
.cursor/skills/elk-stack/SKILL.mdCursor also reads .agents/skills/ and .claude/skills/
1GitHub CLI
gh skill install BagelHole/DevOps-Security-Agent-Skills elk-stack2Manually: put the files in place
.github/skills/elk-stack/SKILL.md1Skills CLI (Vercel)
npx skills add BagelHole/DevOps-Security-Agent-Skills --skill elk-stack -a gemini-cli2Platform CLI
gemini skills install https://github.com/BagelHole/DevOps-Security-Agent-Skills --path devops/observability/elk-stackManually: put the files in place
.devin/skills/elk-stack/SKILL.mdThe legacy .windsurf/skills/ path still works
Skills CLI (Vercel)
npx skills add BagelHole/DevOps-Security-Agent-Skills --skill elk-stack -a opencodeClaude.ai
Zip the folder and upload it in Settings → Capabilities → Skills
Step by step, with commands for each platform: How to install skills in Claude Code: five ways
Questions about elk-stack
How do I install elk-stack in Claude Code?
Run npx skills add BagelHole/DevOps-Security-Agent-Skills --skill elk-stack -a claude-code.
What does the elk-stack skill do?
It supplies configurations to deploy Elasticsearch, Logstash, Kibana, and Filebeat, along with Logstash filtering rules, index retention policies, and search queries.
What prerequisites are required?
You need Docker or server infrastructure, sufficient disk space for log storage, and network access from your log sources.
Source text
SKILL.md · MIT
---
name: elk-stack
description: Deploy and manage the ELK Stack (Elasticsearch, Logstash, Kibana) for log aggregation and analysis. Configure log pipelines, create visualizations, and implement log-based monitoring. Use when centralizing logs, implementing search functionality, or building log analytics platforms.
license: MIT
metadata:
author: devops-skills
version: "1.0"
---
# ELK Stack
Centralize and analyze logs with Elasticsearch, Logstash, and Kibana.
## When to Use This Skill
Use this skill when:
- Centralizing logs from multiple sources
- Building log search and analytics platforms
- Creating log-based dashboards and alerts
- Implementing full-text search for logs
- Processing and transforming log data
## Prerequisites
- Docker or server infrastructure
- Sufficient disk space for log storage
- Network access from log sources
## Docker Deployment
```yaml
# docker-compose.yml
version: '3.8'
services:
elasticsearch:
image: docker.elastic.co/elasticsearch/elasticsearch:8.11.0
environment:
- discovery.type=single-node
- xpack.security.enabled=false
- "ES_JAVA_OPTS=-Xms1g -Xmx1g"
ports:
- "9200:9200"
volumes:
- elasticsearch-data:/usr/share/elasticsearch/data
logstash:
image: docker.elastic.co/logstash/logstash:8.11.0
volumes:
- ./logstash/pipeline:/usr/share/logstash/pipeline
- ./logstash/config:/usr/share/logstash/config
ports:
- "5044:5044"
- "5000:5000"
depends_on:
- elasticsearch
kibana:
image: docker.elastic.co/kibana/kibana:8.11.0
ports:
- "5601:5601"
environment:
- ELASTICSEARCH_HOSTS=http://elasticsearch:9200
depends_on:
- elasticsearch
filebeat:
image: docker.elastic.co/beats/filebeat:8.11.0
user: root
volumes:
- ./filebeat/filebeat.yml:/usr/share/filebeat/filebeat.yml:ro
- /var/lib/docker/containers:/var/lib/docker/containers:ro
- /var/run/docker.sock:/var/run/docker.sock:ro
depends_on:
- logstash
volumes:
elasticsearch-data:
```
## Elasticsearch Configuration
### Index Templates
```json
PUT _index_template/logs-template
{
"index_patterns": ["logs-*"],
"template": {
"settings": {
"number_of_shards": 1,
"number_of_replicas": 1,
"index.lifecycle.name": "logs-policy"
},
"mappings": {
"properties": {
"@timestamp": { "type": "date" },
"message": { "type": "text" },
"level": { "type": "keyword" },
"service": { "type": "keyword" },
"host": { "type": "keyword" },
"trace_id": { "type": "keyword" }
}
}
}
}
```
### Index Lifecycle Management
```json
PUT _ilm/policy/logs-policy
{
"policy": {
"phases": {
"hot": {
"min_age": "0ms",
"actions": {
"rollover": {
"max_size": "50GB",
"max_age": "1d"
}
}
},
"warm": {
"min_age": "7d",
"actions": {
"shrink": { "number_of_shards": 1 },
"forcemerge": { "max_num_segments": 1 }
}
},
"cold": {
"min_age": "30d",
"actions": {
"freeze": {}
}
},
"delete": {
"min_age": "90d",
"actions": {
"delete": {}
}
}
}
}
}
```
## Logstash Pipeline
### Basic Pipeline
```ruby
# logstash/pipeline/main.conf
input {
beats {
port => 5044
}
tcp {
port => 5000
codec => json_lines
}
}
filter {
# Parse JSON logs
if [message] =~ /^\{/ {
json {
source => "message"
}
}
# Parse timestamp
date {
match => ["timestamp", "ISO8601", "yyyy-MM-dd HH:mm:ss"]
target => "@timestamp"
}
# Add environment tag
mutate {
add_field => { "environment" => "production" }
}
# Grok pattern for nginx logs
if [type] == "nginx" {
grok {
match => {
"message" => '%{IPORHOST:client_ip} - %{USER:user} \[%{HTTPDATE:timestamp}\] "%{WORD:method} %{URIPATHPARAM:request} HTTP/%{NUMBER:http_version}" %{NUMBER:status} %{NUMBER:bytes}'
}
}
}
}
output {
elasticsearch {
hosts => ["elasticsearch:9200"]
index => "logs-%{+YYYY.MM.dd}"
}
}
```
### Advanced Filtering
```ruby
filter {
# Parse application logs
grok {
match => {
"message" => "%{TIMESTAMP_ISO8601:timestamp} %{LOGLEVEL:level} \[%{DATA:service}\] %{GREEDYDATA:log_message}"
}
}
# Extract trace ID from message
if [log_message] =~ /trace_id=/ {
grok {
match => { "log_message" => "trace_id=%{UUID:trace_id}" }
}
}
# GeoIP lookup
if [client_ip] {
geoip {
source => "client_ip"
target => "geoip"
}
}
# Drop debug logs in production
if [level] == "DEBUG" and [environment] == "production" {
drop {}
}
# Enrich with lookup
translate {
field => "status"
destination => "status_description"
dictionary => {
"200" => "OK"
"404" => "Not Found"
"500" => "Internal Server Error"
}
}
}
```
## Filebeat Configuration
```yaml
# filebeat/filebeat.yml
filebeat.inputs:
- type: container
paths:
- '/var/lib/docker/containers/*/*.log'
processors:
- add_docker_metadata:
host: "unix:///var/run/docker.sock"
- type: log
enabled: true
paths:
- /var/log/nginx/*.log
tags: ["nginx"]
fields:
type: nginx
output.logstash:
hosts: ["logstash:5044"]
logging.level: info
logging.to_files: true
logging.files:
path: /var/log/filebeat
name: filebeat
keepfiles: 7
```
## Elasticsearch Queries
### Basic Queries
```json
// Search all logs
GET logs-*/_search
{
"query": {
"match_all": {}
}
}
// Search by keyword
GET logs-*/_search
{
"query": {
"match": {
"message": "error"
}
}
}
// Filter by field
GET logs-*/_search
{
"query": {
"bool": {
"must": [
{ "match": { "level": "ERROR" } },
{ "range": { "@timestamp": { "gte": "now-1h" } } }
],
"filter": [
{ "term": { "service": "api-gateway" } }
]
}
}
}
```
### Aggregations
```json
// Count by log level
GET logs-*/_search
{
"size": 0,
"aggs": {
"log_levels": {
"terms": { "field": "level" }
}
}
}
// Error rate over time
GET logs-*/_search
{
"size": 0,
"aggs": {
"errors_over_time": {
"date_histogram": {
"field": "@timestamp",
"fixed_interval": "5m"
},
"aggs": {
"error_count": {
"filter": { "term": { "level": "ERROR" } }
}
}
}
}
}
```
## Kibana Setup
### Index Patterns
1. Go to Stack Management → Index Patterns
2. Create pattern: `logs-*`
3. Set time field: `@timestamp`
### Saved Searches
Create saved searches for common queries:
- `level:ERROR` - All errors
- `service:api-gateway AND level:ERROR` - API gateway errors
- `response_time:>1000` - Slow requests
### Visualizations
Common visualization types:
- **Line Chart**: Error rate over time
- **Pie Chart**: Distribution by log level
- **Data Table**: Top error messages
- **Metric**: Total error count
### Dashboard Example
Create dashboard with:
1. Total log count (Metric)
2. Error rate trend (Line chart)
3. Logs by service (Pie chart)
4. Recent errors (Data table)
5. Log stream (Discover panel)
## Alerting
### Watcher (X-Pack)
```json
PUT _watcher/watch/error_alert
{
"trigger": {
"schedule": { "interval": "5m" }
},
"input": {
"search": {
"request": {
"indices": ["logs-*"],
"body": {
"query": {
"bool": {
"must": [
{ "match": { "level": "ERROR" } },
{ "range": { "@timestamp": { "gte": "now-5m" } } }
]
}
}
}
}
}
},
"condition": {
"compare": { "ctx.payload.hits.total.value": { "gt": 100 } }
},
"actions": {
"notify_slack": {
"webhook": {
"scheme": "https",
"host": "hooks.slack.com",
"port": 443,
"method": "post",
"path": "/services/xxx",
"body": "{\"text\": \"High error rate detected: {{ctx.payload.hits.total.value}} errors in last 5 minutes\"}"
}
}
}
}
```
## Common Issues
### Issue: High Disk Usage
**Problem**: Elasticsearch consuming too much disk
**Solution**: Implement ILM policies, reduce retention
### Issue: Slow Searches
**Problem**: Queries taking too long
**Solution**: Optimize index settings, add more shards, use filters
### Issue: Log Parsing Failures
**Problem**: Logs not parsed correctly
**Solution**: Test grok patterns, check for log format changes
### Issue: Memory Pressure
**Problem**: Elasticsearch OOM errors
**Solution**: Increase heap size (max 50% of RAM), limit field data
## Best Practices
- Implement index lifecycle management
- Use index templates for consistent mappings
- Parse logs at ingestion time
- Limit stored fields to reduce storage
- Use data streams for time-series data
- Monitor cluster health
- Implement proper security (X-Pack)
- Regular index maintenance
## Related Skills
- [loki-logging](../loki-logging/) - Alternative logging stack
- [prometheus-grafana](../prometheus-grafana/) - Metrics monitoring
- [audit-logging](../../../compliance/auditing/audit-logging/) - Compliance logging
© devops-skills · MIT · BagelHole/DevOps-Security-Agent-Skills