name: logstash-openshift description: Manage Logstash pipelines deployed in OpenShift using ConfigMaps. Use for pipeline configuration, deployment, troubleshooting, and maintenance of Logstash in containerized OpenShift environments.
Logstash on OpenShift
Guide for managing Logstash pipelines in OpenShift using ConfigMap-based configuration management.
Architecture Overview
Deployment Pattern
- Logstash Pods: Run as Deployments or StatefulSets in OpenShift
- Pipeline Configuration: Stored in ConfigMaps
- Secrets: Sensitive credentials (passwords, API keys) stored in OpenShift Secrets
- Persistent Storage: Optional PVCs for file-based plugins or dead letter queues
Typical Structure
ConfigMap: logstash-pipeline
├── input.conf (Input plugins configuration)
├── filter.conf (Filter/transformation logic)
└── output.conf (Output destinations)
ConfigMap: logstash-patterns (optional)
└── custom.patterns (Grok patterns)
Secret: logstash-credentials
├── elasticsearch-password
├── kafka-keystore
└── api-tokens
ConfigMap Management
Creating Pipeline ConfigMap
# Create from local files
oc create configmap logstash-pipeline \
--from-file=input.conf \
--from-file=filter.conf \
--from-file=output.conf \
-n <namespace>
# Create from YAML manifest
cat <<EOF | oc apply -f -
apiVersion: v1
kind: ConfigMap
metadata:
name: logstash-pipeline
namespace: logging
data:
input.conf: |
input {
beats {
port => 5044
}
kafka {
bootstrap_servers => "kafka-cluster:9092"
topics => ["logs"]
codec => json
}
}
filter.conf: |
filter {
if [type] == "syslog" {
grok {
match => { "message" => "%{SYSLOGLINE}" }
}
date {
match => [ "timestamp", "MMM dd HH:mm:ss" ]
}
}
# Remove fields
mutate {
remove_field => ["@version", "host"]
}
}
output.conf: |
output {
elasticsearch {
hosts => ["https://elasticsearch:9200"]
index => "logstash-%{[@metadata][beat]}-%{+YYYY.MM.dd}"
user => "\${ELASTICSEARCH_USER}"
password => "\${ELASTICSEARCH_PASSWORD}"
ssl => true
cacert => "/etc/logstash/certs/ca.crt"
}
# Dead letter queue for failed events
if "_grokparsefailure" in [tags] {
file {
path => "/var/log/logstash/failed-%{+YYYY-MM-dd}.log"
codec => json_lines
}
}
}
EOF
Updating Pipeline Configuration
# Edit ConfigMap directly
oc edit configmap logstash-pipeline -n <namespace>
# Update from file
oc create configmap logstash-pipeline \
--from-file=filter.conf \
--dry-run=client -o yaml | oc apply -f -
# Patch specific key
oc patch configmap logstash-pipeline -n <namespace> \
--type merge \
-p '{"data":{"filter.conf":"<new-content>"}}'
Reloading Configuration
Logstash supports automatic config reload, but for OpenShift:
# Force pod restart to pick up new ConfigMap
oc rollout restart deployment/logstash -n <namespace>
# Or delete pods to trigger recreation
oc delete pod -l app=logstash -n <namespace>
# Watch rollout status
oc rollout status deployment/logstash -n <namespace> --watch
Deployment Configuration
Logstash Deployment YAML
apiVersion: apps/v1
kind: Deployment
metadata:
name: logstash
namespace: logging
spec:
replicas: 2
selector:
matchLabels:
app: logstash
template:
metadata:
labels:
app: logstash
spec:
containers:
- name: logstash
image: docker.elastic.co/logstash/logstash:8.11.0
ports:
- containerPort: 5044
name: beats
protocol: TCP
- containerPort: 9600
name: http
protocol: TCP
env:
- name: ELASTICSEARCH_USER
valueFrom:
secretKeyRef:
name: logstash-credentials
key: elasticsearch-user
- name: ELASTICSEARCH_PASSWORD
valueFrom:
secretKeyRef:
name: logstash-credentials
key: elasticsearch-password
- name: LS_JAVA_OPTS
value: "-Xmx1g -Xms1g"
- name: PIPELINE_WORKERS
value: "2"
- name: PIPELINE_BATCH_SIZE
value: "125"
resources:
requests:
memory: "1.5Gi"
cpu: "500m"
limits:
memory: "2Gi"
cpu: "1000m"
volumeMounts:
- name: pipeline-config
mountPath: /usr/share/logstash/pipeline
readOnly: true
- name: logstash-config
mountPath: /usr/share/logstash/config/logstash.yml
subPath: logstash.yml
readOnly: true
- name: patterns
mountPath: /usr/share/logstash/patterns
readOnly: true
- name: certs
mountPath: /etc/logstash/certs
readOnly: true
livenessProbe:
httpGet:
path: /
port: 9600
initialDelaySeconds: 60
periodSeconds: 30
readinessProbe:
httpGet:
path: /
port: 9600
initialDelaySeconds: 30
periodSeconds: 10
volumes:
- name: pipeline-config
configMap:
name: logstash-pipeline
- name: logstash-config
configMap:
name: logstash-config
- name: patterns
configMap:
name: logstash-patterns
optional: true
- name: certs
secret:
secretName: elasticsearch-certs
Main Configuration (logstash.yml)
apiVersion: v1
kind: ConfigMap
metadata:
name: logstash-config
namespace: logging
data:
logstash.yml: |
http.host: "0.0.0.0"
path.config: /usr/share/logstash/pipeline/*.conf
config.reload.automatic: true
config.reload.interval: 30s
# Performance tuning
pipeline.workers: 2
pipeline.batch.size: 125
pipeline.batch.delay: 50
# Monitoring
monitoring.enabled: false
# Dead letter queue
dead_letter_queue.enable: true
dead_letter_queue.max_bytes: 1gb
# Logging
log.level: info
path.logs: /usr/share/logstash/logs
Pipeline Development Best Practices
Input Configuration
input {
# Beats input for log shippers
beats {
port => 5044
ssl => true
ssl_certificate => "/etc/logstash/certs/server.crt"
ssl_key => "/etc/logstash/certs/server.key"
}
# Kafka for high-throughput scenarios
kafka {
bootstrap_servers => "${KAFKA_BROKERS}"
topics => ["application-logs", "system-logs"]
group_id => "logstash-consumer"
consumer_threads => 2
codec => json
auto_offset_reset => "latest"
}
# HTTP input for webhooks
http {
port => 8080
codec => json
}
}
Filter Configuration
filter {
# Parse JSON if string
if [message] =~ /^\{.*\}$/ {
json {
source => "message"
target => "parsed"
}
}
# Grok parsing for unstructured logs
grok {
match => {
"message" => [
"%{TIMESTAMP_ISO8601:timestamp} %{LOGLEVEL:level} %{GREEDYDATA:message}",
"%{SYSLOGLINE}"
]
}
tag_on_failure => ["_grokparsefailure"]
}
# Date parsing
date {
match => [ "timestamp", "ISO8601", "yyyy-MM-dd HH:mm:ss" ]
target => "@timestamp"
}
# Enrich with Kubernetes metadata
if [kubernetes] {
mutate {
add_field => {
"namespace" => "%{[kubernetes][namespace]}"
"pod" => "%{[kubernetes][pod_name]}"
"container" => "%{[kubernetes][container_name]}"
}
}
}
# Conditional processing
if [level] == "ERROR" or [level] == "FATAL" {
mutate {
add_tag => ["alert"]
add_field => { "severity" => "high" }
}
}
# Drop debug logs in production
if [level] == "DEBUG" and [environment] == "production" {
drop { }
}
# Clean up
mutate {
remove_field => ["@version", "host", "agent"]
}
}
Output Configuration
output {
# Main Elasticsearch output
elasticsearch {
hosts => ["${ELASTICSEARCH_HOSTS}"]
index => "logs-%{[namespace]}-%{+YYYY.MM.dd}"
user => "${ELASTICSEARCH_USER}"
password => "${ELASTICSEARCH_PASSWORD}"
ssl => true
cacert => "/etc/logstash/certs/ca.crt"
# ILM settings
ilm_enabled => true
ilm_rollover_alias => "logs"
ilm_pattern => "{now/d}-000001"
ilm_policy => "logs-policy"
}
# Send alerts to different index
if "alert" in [tags] {
elasticsearch {
hosts => ["${ELASTICSEARCH_HOSTS}"]
index => "alerts-%{+YYYY.MM.dd}"
user => "${ELASTICSEARCH_USER}"
password => "${ELASTICSEARCH_PASSWORD}"
}
}
# Forward to Kafka for further processing
if [type] == "metric" {
kafka {
bootstrap_servers => "${KAFKA_BROKERS}"
topic_id => "processed-metrics"
codec => json
}
}
# Debug output (disable in production)
if [@metadata][debug] {
stdout {
codec => rubydebug
}
}
}
Troubleshooting
Check Logstash Logs
# View pod logs
oc logs -f deployment/logstash -n <namespace>
# View logs from specific pod
oc logs logstash-pod-xyz -n <namespace>
# View logs with timestamps
oc logs --timestamps deployment/logstash -n <namespace>
# View previous pod logs (after crash)
oc logs --previous logstash-pod-xyz -n <namespace>
Common Issues
Pipeline Not Loading
# Verify ConfigMap is mounted
oc describe pod <logstash-pod> -n <namespace>
# Check ConfigMap content
oc get configmap logstash-pipeline -o yaml -n <namespace>
# Verify syntax
# Exec into pod and test
oc exec -it <logstash-pod> -n <namespace> -- bash
/usr/share/logstash/bin/logstash --config.test_and_exit -f /usr/share/logstash/pipeline/
Memory/Performance Issues
# Check resource usage
oc top pod -l app=logstash -n <namespace>
# Adjust JVM heap in deployment
# Edit LS_JAVA_OPTS environment variable
oc set env deployment/logstash LS_JAVA_OPTS="-Xmx2g -Xms2g" -n <namespace>
# Scale replicas for load distribution
oc scale deployment/logstash --replicas=3 -n <namespace>
Connection Issues
# Test connectivity from Logstash pod
oc exec -it <logstash-pod> -n <namespace> -- bash
curl -k https://elasticsearch:9200
nc -zv kafka-cluster 9092
# Check secrets are properly mounted
oc exec -it <logstash-pod> -n <namespace> -- env | grep ELASTIC
API Monitoring
# Check Logstash API (monitoring endpoint)
oc port-forward deployment/logstash 9600:9600 -n <namespace>
curl http://localhost:9600/_node/stats/pipelines?pretty
# Check pipeline status
curl http://localhost:9600/_node/pipelines?pretty
Dead Letter Queue
# Access DLQ if enabled
oc exec -it <logstash-pod> -n <namespace> -- bash
cd /usr/share/logstash/data/dead_letter_queue
ls -lh
# Replay DLQ events
/usr/share/logstash/bin/logstash -f /path/to/dlq-replay.conf
Testing Pipeline Changes
Local Testing Pattern
# 1. Extract current ConfigMap
oc get configmap logstash-pipeline -o yaml > pipeline-backup.yaml
# 2. Create test version locally
cat > test-pipeline.conf <<EOF
input {
stdin { codec => json }
}
filter {
# Your filter logic here
}
output {
stdout { codec => rubydebug }
}
EOF
# 3. Test with Docker locally
docker run --rm -it \
-v $(pwd)/test-pipeline.conf:/usr/share/logstash/pipeline/test.conf \
docker.elastic.co/logstash/logstash:8.11.0
# 4. Apply to dev namespace first
oc apply -f updated-pipeline.yaml -n logging-dev
# 5. Monitor for errors
oc logs -f deployment/logstash -n logging-dev
# 6. Promote to production after validation
oc apply -f updated-pipeline.yaml -n logging-prod
Validation Checklist
- Syntax validation passed
- Test data processed correctly
- No performance degradation
- Error handling works as expected
- Secrets/credentials properly referenced
- Index patterns follow naming convention
- Monitoring shows healthy pipeline
- Rollback plan prepared
Security Best Practices
Secrets Management
# Create secret for credentials
oc create secret generic logstash-credentials \
--from-literal=elasticsearch-user=logstash_writer \
--from-literal=elasticsearch-password='SecurePass123!' \
-n <namespace>
# Reference in deployment as environment variables
# (See deployment YAML above)
# Never put credentials in ConfigMaps
# Always use Secrets or external secret management (Vault, etc.)
Network Policies
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: logstash-netpol
namespace: logging
spec:
podSelector:
matchLabels:
app: logstash
policyTypes:
- Ingress
- Egress
ingress:
- from:
- podSelector:
matchLabels:
app: filebeat
ports:
- protocol: TCP
port: 5044
egress:
- to:
- podSelector:
matchLabels:
app: elasticsearch
ports:
- protocol: TCP
port: 9200
- to:
- podSelector:
matchLabels:
app: kafka
ports:
- protocol: TCP
port: 9092
Monitoring and Alerts
Key Metrics to Monitor
- Pipeline throughput (events/sec)
- Processing latency
- Memory and CPU usage
- Dead letter queue size
- Output connection failures
- Pod restart count
Prometheus Integration
# ServiceMonitor for Prometheus Operator
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: logstash
namespace: logging
spec:
selector:
matchLabels:
app: logstash
endpoints:
- port: http
interval: 30s
path: /_node/stats
Common Workflows
Adding a New Pipeline
- Create new ConfigMap with pipeline configuration
- Update Deployment to mount the new ConfigMap
- Apply changes and monitor rollout
- Validate data flow to outputs
Updating Existing Pipeline
- Backup current ConfigMap
- Edit ConfigMap with new configuration
- Test in non-production environment
- Rollout restart deployment
- Monitor logs for errors
- Rollback if issues detected
Debugging Parse Failures
- Check logs for grok parse failures
- Extract sample failed messages
- Test grok patterns with sample data
- Update filter configuration
- Apply and validate
Scaling Logstash
# Horizontal scaling
oc scale deployment/logstash --replicas=5 -n <namespace>
# Vertical scaling (resource limits)
oc set resources deployment/logstash \
--limits=cpu=2000m,memory=4Gi \
--requests=cpu=1000m,memory=2Gi \
-n <namespace>
Reference
Useful Commands
# Quick reference card
alias ls-config="oc get configmap logstash-pipeline -o yaml"
alias ls-logs="oc logs -f deployment/logstash"
alias ls-restart="oc rollout restart deployment/logstash"
alias ls-status="oc rollout status deployment/logstash"
alias ls-describe="oc describe deployment logstash"
alias ls-exec="oc exec -it deployment/logstash -- bash"
Documentation Links
- Logstash Reference: https://www.elastic.co/guide/en/logstash/current/index.html
- OpenShift ConfigMaps: https://docs.openshift.com/container-platform/latest/nodes/pods/nodes-pods-configmaps.html
- Logstash Performance Tuning: https://www.elastic.co/guide/en/logstash/current/performance-tuning.html
- Plugin Documentation: https://www.elastic.co/guide/en/logstash/current/input-plugins.html
Tips
- Always test configuration changes in non-production first
- Use config reload feature for minor changes
- Monitor pipeline stats via API before/after changes
- Keep pipelines modular (separate input/filter/output files)
- Document custom grok patterns in separate ConfigMap
- Use environment variables for environment-specific values
- Enable dead letter queue for critical pipelines
- Implement proper error handling and tagging
- Regular review of pipeline performance metrics
- Maintain version control for all ConfigMap configurations