Elasticsearch в Kubernetes: HelmRelease, ingest pipelines и начальная настройка
Published: 2026-03-14
Elasticsearch работает на каждом кластере. Он хранит логи доступа APISIX и логи приложений от Vector. Для правильной настройки одного HelmRelease мало: нужен bootstrap-скрипт, который инициализирует ingest pipelines, шаблоны индексов и корректно выставляет количество реплик для single-node установки.
HelmRelease
Elasticsearch развёртывается из чарта, который лежит прямо в Git-репозитории:
yamlapiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
name: elasticsearch
spec:
interval: 1h
chart:
spec:
chart: ./charts/elastic/elasticsearch
version: "7.17.3"
sourceRef:
kind: GitRepository
name: flux-system
namespace: flux-system
install:
remediation:
retries: -1
upgrade:
remediation:
retries: -1
retries: -1 — бесконечные повторные попытки при ошибке. Для stateful-сервисов так сделано намеренно: временная задержка при создании PVC не должна навсегда ломать релиз.
Патчи по окружениям
Базовый HelmRelease не содержит конфигурации хранилища или hostname:
yaml# projects/dev/kustomization/hub/patches/elasticsearch.yaml
apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
name: elasticsearch
namespace: dev
spec:
values:
master:
persistence:
storageClass: local-path
resources:
requests:
memory: "4Gi"
cpu: "500m"
limits:
memory: "6Gi"
esConfig:
elasticsearch.yml: |
xpack.security.enabled: true
xpack.monitoring.enabled: false
ingress:
hosts:
- host: elasticsearch.dev.example.com
paths:
- path: /
На YC-кластерах вместо local-path используется yc-network-ssd.
Bootstrap-скрипт
После первой установки Elasticsearch — чистый лист. Bootstrap-скрипт создаёт необходимую конфигурацию:
bashES_USER=elastic ES_PASS='<password>' ./scripts/bootstrap-elasticsearch.sh
1. Ingest pipeline для логов APISIX:
json{
"description": "Parse APISIX access log JSON",
"processors": [
{ "date": { "field": "timestamp", "formats": ["UNIX_MS"], "target_field": "@timestamp" } },
{ "remove": { "field": "timestamp" } },
{ "geoip": { "field": "remote_addr", "ignore_missing": true } }
]
}
2. Шаблон индекса для APISIX:
json{
"index_patterns": ["apisix*"],
"settings": {
"number_of_replicas": 0,
"default_pipeline": "apisix"
}
}
3. Шаблон для логов приложений:
json{
"index_patterns": ["vector*", "app*"],
"settings": { "number_of_replicas": 0 }
}
number_of_replicas: 0 обязателен для single-node. С репликами > 0 индексы навсегда остаются жёлтыми.
4. Патч существующих индексов:
bashcurl -X PUT "http://${ES_HOST}:9200/vector*/_settings" \
-H 'Content-Type: application/json' \
-d '{"index": {"number_of_replicas": 0}}'
Проверка состояния кластера
bashkubectl port-forward -n logging svc/elasticsearch 9200:9200
curl -u elastic:$ES_PASS http://localhost:9200/_cluster/health?pretty
# Список индексов
curl -u elastic:$ES_PASS http://localhost:9200/_cat/indices?v
# Проверить, что у всех индексов 0 реплик
curl -u elastic:$ES_PASS "http://localhost:9200/_cat/indices?v&h=index,health,rep"
На single-node все индексы должны быть зелёными и с 0 реплик.
Жизненный цикл индексов
Логи APISIX пишутся в apisix (один индекс с ingest pipeline). Логи приложений — в vector-YYYY-MM-DD (ежедневные rolling-индексы).
ILM не настроен. Автоматическое удаление старых индексов:
bash# Удалить индексы старше 30 дней
curl -X DELETE "http://localhost:9200/vector-$(date -d '30 days ago' +%Y.%m.%d)"
Kibana
Kibana работает только на кластере infra. Для spoke-кластеров достаточно port-forward к Elasticsearch или Elasticsearch Exporter + дашборды Grafana.
Elasticsearch Exporter
yamlapiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
name: elasticsearch-exporter
namespace: observability
spec:
chart:
spec:
chart: prometheus-elasticsearch-exporter
sourceRef:
kind: HelmRepository
name: prometheus-community
values:
es:
uri: http://elasticsearch.logging.svc.cluster.local:9200
serviceMonitor:
enabled: true
labels:
release: kube-prom-stack
Ключевые метрики: elasticsearch_cluster_health_status, elasticsearch_indices_docs, elasticsearch_jvm_memory_used_bytes.
Диагностика
Жёлтый статус кластера: Проверьте number_of_replicas — должно быть 0 на single-node.
OOM kills: JVM heap = 50% от лимита контейнера. Лимит 4Gi → 2Gi heap. Этого достаточно для умеренных объёмов логов.
Pipeline не применяется: Убедитесь, что default_pipeline указан в шаблоне индекса, а не только в настройках конкретного индекса.