Шаблоны индексов: автоматическая настройка

Чтобы каждый новый дневной индекс логов сам получал правильный маппинг и политику ILM, нужен шаблон.

Index template — заготовка настроек (маппинг, число шардов, привязка ILM-политики), которую Elasticsearch автоматически применяет к новым индексам, имя которых подходит под заданную маску.

Проблема без шаблонов

Логи нарезаются по времени: каждый день (или каждый rollover) создаётся новый индекс. Если настраивать каждый вручную, то один забудет про @timestamp типа date, другой получит 5 шардов вместо 1, третий не привяжется к ILM и будет жить вечно. На потоке новых индексов ручная настройка нереальна. Шаблон гарантирует, что любой новый индекс под маску logs-* рождается уже правильным.

Что задаёт шаблон

Index template обычно описывает три вещи: маппинг (типы полей), settings (число шардов/реплик) и привязку ILM. Пример шаблона для логов приложения:

{
  "index_patterns": ["logs-app-*"],
  "template": {
    "settings": {
      "number_of_shards": 1,
      "number_of_replicas": 1,
      "index.lifecycle.name": "logs-policy"
    },
    "mappings": {
      "properties": {
        "@timestamp": { "type": "date" },
        "level":      { "type": "keyword" },
        "service":    { "type": "keyword" },
        "status":     { "type": "integer" },
        "message":    { "type": "text" },
        "trace_id":   { "type": "keyword" }
      }
    }
  }
}

Теперь любой индекс logs-app-... автоматически получит этот маппинг (правильные keyword для идентификаторов и integer для статуса), один шард и политику logs-policy из урока про ILM. Регистрируется шаблон через ES API:

curl -X PUT "http://es01:9200/_index_template/logs-app" \
  -H 'Content-Type: application/json' \
  -d @logs-app-template.json

Component templates: переиспользование

В современном ES шаблоны можно собирать из переиспользуемых кусочков — component templates. Например, отдельный компонент с базовыми ECS-полями и отдельный с настройками ILM; итоговый index template их комбинирует. Это избавляет от копирования одного и того же маппинга в десяток шаблонов разных сервисов.

Как работает под капотом: динамический маппинг и его опасность

Если поле пришло, а в маппинге шаблона его нет, ES применяет динамический маппинг — угадывает тип сам. Это удобно, но опасно для логов: то самое поле trace_id ES может угадать как text вместо keyword, а произвольные JSON-ключи (помните взрыв полей?) насоздают тысячи полей. Поэтому в шаблонах логов часто либо явно описывают все важные поля, либо настраивают dynamic: strict (запретить незнакомые поля) или dynamic templates (правило «все строки — keyword»). Шаблон — это ваша защита от хаоса автоматического угадывания типов.

Динамические шаблоны полей

Между двумя крайностями — описать каждое поле руками или отдать всё на откуп динамическому маппингу — есть удобная середина: dynamic templates. Это правила вида «любое новое строковое поле делать keyword, а не text» или «поля, чьё имя оканчивается на _ip, считать типом ip». Они задаются в том же index template и срабатывают на поля, которых нет в явном маппинге. Для логов это золотая середина: вы явно описываете ключевые поля и одновременно страхуетесь правилом по умолчанию, чтобы случайно пришедшее новое поле не стало проблемным text и не сломало будущие агрегации. Грамотно настроенные dynamic templates снимают значительную часть риска взрыва полей, не лишая гибкости.

Ещё одна полезная настройка уровня шаблона — лимит на число полей в индексе (index.mapping.total_fields.limit). Он работает как предохранитель: если из-за ошибки в приложении в логи хлынут динамические ключи, индекс упрётся в лимит и начнёт отвергать новые поля, а не молча раздует cluster state до падения. Лучше получить понятную ошибку «превышен лимит полей» и починить источник, чем обнаружить деградацию кластера постфактум.

Частые ошибки

  • Создать индекс раньше шаблона. Шаблон применяется только при создании индекса. Если индекс уже создан, изменение шаблона на него не подействует — нужен новый индекс (rollover).
  • Полагаться на динамический маппинг. Без явных типов идентификаторы станут text, и агрегации сломаются. Описывайте ключевые поля в шаблоне.
  • Конфликтующие шаблоны. Несколько шаблонов под пересекающиеся маски разруливаются по приоритету; неучтённый приоритет даёт неожиданный маппинг.

Итоги

  • Index template применяет маппинг, settings и привязку ILM к новым индексам по маске автоматически.
  • Без шаблона новые индексы получают опасный динамический маппинг (идентификаторы как text, взрыв полей).
  • Component templates позволяют собирать шаблоны из переиспользуемых частей (ECS-поля, ILM).
  • Шаблон действует только в момент создания индекса — на уже существующие не влияет.
Проверьте себя
1. Что делает index template в Elasticsearch?
AУдаляет старые индексы
BАвтоматически применяет маппинг, настройки шардов и привязку ILM к новым индексам, подходящим под маску
CПарсит логи grok'ом
DСоздаёт дашборды в Kibana
2. Чем опасен динамический маппинг для логов?
AОн замедляет запись
BES угадывает типы сам: идентификаторы могут стать text вместо keyword, а произвольные ключи — наплодить тысячи полей
CОн удаляет поля
DОн шифрует данные
3. На какие индексы подействует изменение index template?
AНа все существующие индексы сразу
BТолько на индексы, созданные после изменения (на уже существующие не повлияет)
CТолько на индекс с самым старым именем
DНа индексы в Kibana