Настройка сбора логов на одном VPS: Loki или journald
Узнайте, как организовать хранение логов на одном VPS. Сравнение ресурсов для systemd-journald, Grafana Loki и OpenSearch. Выберите решение с учетом лимитов RAM и ротации.
Реальная стоимость самостоятельного управления логами на одном VPS
Самостоятельное управление логами на одном VPS (виртуальном выделенном сервере) сводится к одному вопросу: нужен ли вам поисковый кластер или достаточно ротации и утилиты grep? Большинство руководств от вендоров предлагают начинать с трех узлов и 12 GB оперативной памяти еще до отправки первой строки лога. Для одного сервера такой подход бесполезен, поэтому ниже приведено сравнение того, сколько ресурсов каждая опция требует от небольшой машины до начала записи данных.
Если вы используете один или два сервера и вам нужно узнать, что произошло в прошлый вторник, systemd-journald и logrotate уже выполняют эту задачу, и вы можете остановиться после следующего раздела. Если несколько машин должны передавать логи в одно место с возможностью поиска по ним в течение недель, Grafana Loki подойдет для небольшой машины, так как она индексирует метки, а не текст строк. Elasticsearch и OpenSearch предоставляют полноценный полнотекстовый поиск, но платой за это является потребление оперативной памяти, так как куча JVM (Java virtual machine) имеет минимальный порог, ниже которого опуститься невозможно.
Начните с journald, так как большинство администраторов останавливаются на этом этапе
systemd-journald уже запущен на любом современном сервере Ubuntu или Debian. Он перехватывает стандартный вывод каждого юнита службы, сообщения ядра и всё, что отправляется в syslog. Четыре команды позволяют решить большинство инцидентов.
journalctl -u nginx.service --since "2026-08-14 09:00" --until "2026-08-14 10:00"
journalctl -p err -b
journalctl -f -u ssh.service
journalctl --disk-usageПоследняя команда выводит строку вида Archived and active journals take up 1.1G in the file system.. Это число определяет, нужно ли вам что-то ещё. Если размер составляет несколько сотен мегабайт и вы можете найти нужную информацию с помощью -u и --since, работа завершена.
Сохранится ли журнал после перезагрузки, зависит от Storage= и от того, существует ли /var/log/journal. При стандартной настройке Storage=auto, journald пишет в /var/log/journal, если этот каталог существует, и в /run/log/journal, если его нет. /run находится в оперативной памяти, поэтому на сервере без этого каталога все логи удаляются при перезагрузке — именно в тот момент, когда они вам нужны. Образы Ubuntu содержат этот каталог. Минималистичные и контейнерные образы часто его не имеют.
ls -d /var/log/journal
sudo mkdir -p /var/log/journal
sudo systemctl restart systemd-journald
journalctl --disk-usageПосле перезапуска journalctl --disk-usage должен показывать размер менее /var/log/journal, а не /run. Значения по умолчанию уже ограничены, что является главной причиной, почему journald — это полноценное решение, а не временный вариант. Страница руководства journald.conf устанавливает SystemMaxUse= на уровне 10% от размера файловой системы, а SystemKeepFree= — на 15%, ограничивая каждое вычисленное значение 4G. SystemMaxFileSize= по умолчанию составляет одну восьмую от SystemMaxUse= с ограничением в 128M, поэтому обычно у вас хранится семь ротированных файлов. MaxRetentionSec= по умолчанию равно 0, что отключает удаление по возрасту. Прочитайте последнее значение ещё раз: «из коробки» журнал ограничен только размером, но не возрастом.
[Journal]
Storage=persistent
SystemMaxUse=2G
MaxRetentionSec=30dayЗапишите это в /etc/systemd/journald.conf.d/99-size.conf, перезапустите journald, затем убедитесь, что journalctl --disk-usage приблизился к вашему новому лимиту. Чтобы освободить место сейчас, не дожидаясь следующей ротации, выполните sudo journalctl --vacuum-size=500M или sudo journalctl --vacuum-time=14d. Обе команды выводят список всех удаляемых файлов, поэтому отсутствие вывода означает, что удалять нечего.
Всё, что находится вне журнала, например /var/log/nginx/access.log, является задачей logrotate, который запускается ежедневно по таймеру systemd. Стоит знать об одной ошибке, так как она выглядит как баг в df. После ротации старый файл исчезает из списка каталога, пока демон продолжает держать его открытым, поэтому df -h сообщает о переполнении диска, в то время как du -sh /var/log показывает гораздо меньший объем. Место освобождается только тогда, когда процесс заново открывает свой лог, для чего и нужна строка postrotate в конфигурации. sudo lsof -nP +L1 выводит список удаленных файлов, которые всё ещё удерживаются открытыми, с указанием процесса, удерживающего каждый из них. Протестируйте правило без внесения изменений с помощью sudo logrotate -d /etc/logrotate.d/nginx.
Передача логов с нескольких серверов на один коллектор
Когда серверов становится больше одного, управление несколькими серверами Linux одновременно упрощается, если все логи поступают в одно место. rsyslog уже установлен в большинстве дистрибутивов, поэтому самый простой способ организации централизованного сбора — это настройка одного файла на каждом отправителе.
*.* action(type="omfwd" target="logs.example.com" port="514" protocol="tcp")Сохраните это как /etc/rsyslog.d/50-forward.conf, проверьте конфигурацию с помощью sudo rsyslogd -N1 (команда проверяет синтаксис и завершает работу без запуска сервиса), а затем перезапустите rsyslog. На стороне коллектора включите прием данных по TCP.
module(load="imtcp")
input(type="imtcp" port="514")Два предостережения, оба касаются технической реализации. Обычный syslog не использует шифрование и аутентификацию, поэтому любой, кто имеет доступ к порту 514, может внедрить строки логов, которые будут выглядеть как ваши. Привяжите сервис к частной сети или VPN и ограничьте доступ к порту через firewall. Во-вторых, очередь действий по умолчанию находится в оперативной памяти, поэтому при недоступности коллектора очередь переполняется, и сообщения отбрасываются без сохранения копий. rsyslog описывает использование очереди с записью на диск для таких случаев в своем руководстве по надежной пересылке.
Почему стек ELK не подходит для небольших VPS
ELK — это Elasticsearch для хранения и поиска, Logstash для конвейера обработки данных и Kibana для интерфейса. Нижний порог потребления памяти определяется кучей (heap) JVM, которая резервируется до поступления первых логов.
Документация Elastic рекомендует выделять под кучу не более 50% от общего объема оперативной памяти, доступной каждому узлу Elasticsearch. Это связано с тем, что процесс также использует буферы вне кучи и полагается на файловый кэш операционной системы для быстрого чтения индексных файлов. Таким образом, куча размером 2 GB требует 4 GB оперативной памяти на сервере — и это еще до запуска Kibana и основного приложения, ради которого сервер был арендован. Elastic также указывает, что Elasticsearch автоматически подбирает размер кучи исходя из ролей узла и общего объема памяти. В результате на маленьком сервере процесс получает небольшую кучу и постоянно тратит ресурсы на сборку мусора (garbage collection).
Logstash — это компонент, который окончательно делает использование стека невозможным при ограниченных ресурсах. Страница настроек JVM от Elastic рекомендует для типичной обработки данных выделять под кучу от 4 GB до 8 GB. Это весь объем памяти VPS на 4 GB, отведенный только под один процесс в середине конвейера.
The data behind this chart
[
{
"label": "Loki plus Alloy (no JVM)",
"documented_heap_mb": 0
},
{
"label": "OpenSearch demo compose",
"documented_heap_mb": 512
},
{
"label": "OpenSearch production example",
"documented_heap_mb": 2048
},
{
"label": "Logstash recommended minimum",
"documented_heap_mb": 4096
}
]Это значения, которые каждый проект публикует в своей документации. Они не являются результатами замеров на тестовом стенде, и ваша рабочая нагрузка может их изменить. Пример файла compose для OpenSearch устанавливает 512 MB на узел для демонстрации и 2048 MB в примере для промышленной эксплуатации, в то время как рекомендуемый нижний порог для Logstash составляет 4096 MB. В столбце для кучи указано 0 для Loki и Alloy, так как это программы на Go, которым не требуется резервировать кучу JVM. В этом и заключается вся разница: компонент на JVM забирает зарезервированную память независимо от того, поступают логи или нет.
Если вы все же хотите запустить стек Elastic на одном небольшом сервере, откажитесь от Logstash и отправляйте данные напрямую в Elasticsearch с помощью легковесного сборщика. Logstash предназначен для парсинга и трансформации больших объемов данных, а на одном сервере эту работу можно выполнить на стороне источника или вовсе пропустить.
И Elasticsearch, и OpenSearch также требуют увеличения vm.max_map_count до 262144, так как они используют отображение индексных файлов в память (memory mapping), а стандартного лимита Linux для них недостаточно. Если контейнер завершает работу через несколько секунд после запуска на чистой системе, чаще всего причина именно в этом.
OpenSearch или Elasticsearch: что выбрать для развертывания?
Краткая история лицензий важна, так как она определяет допустимые условия использования. В январе 2021 года компания Elastic перевела Elasticsearch и Kibana с лицензии Apache 2.0 на двойную модель: SSPL (Server Side Public License) и Elastic License 2.0. AWS создала форк последней версии кода под лицензией Apache 2.0, назвав его OpenSearch, который сохраняет лицензию Apache 2.0. В сентябре 2024 года Elastic добавила AGPLv3 (GNU Affero General Public License version 3) в качестве еще одного варианта для бесплатного исходного кода. Для частного использования на одном VPS любая из этих лицензий позволяет выполнять ваши задачи. Ограничения лицензий вступают в силу, если вы предлагаете это ПО другим пользователям как управляемый сервис.
Практическая разница на небольшом сервере меньше, чем кажется из истории, так как в основе обоих продуктов лежит один и тот же движок. Различаются названия: управление жизненным циклом индексов называется ISM (Index State Management) в OpenSearch и ILM (Index Lifecycle Management) в Elasticsearch. На август 2026 года OpenSearch версии 2.12 и выше отказывается запускаться без установки пароля администратора при первом запуске.
sudo sysctl -w vm.max_map_count=262144
printf 'vm.max_map_count = 262144\n' | sudo tee /etc/sysctl.d/99-opensearch.conf
docker run -d -p 9200:9200 -p 9600:9600 -e "discovery.type=single-node" \
-e "OPENSEARCH_INITIAL_ADMIN_PASSWORD=<custom-admin-password>" \
opensearchproject/opensearch:latestСтрока sysctl -w применяет настройку немедленно, а файл в /etc/sysctl.d/ сохраняет её после перезагрузки. Проверьте, что контейнер запущен с помощью curl -k -u admin:<password> https://localhost:9200. Он отвечает по протоколу https с использованием демонстрационного сертификата, поэтому -k пропускает проверку, а корректный ответ представляет собой небольшой JSON-блок с названием кластера и версией. Страница установки OpenSearch также рекомендует пользователям Docker Desktop выделять хосту не менее 4 GB оперативной памяти, что является показателем реальных потребностей процесса.
Как Loki сохраняет компактность: метки вместо полнотекстового индекса
Loki поддерживает один индекс по меткам и хранит строки логов в виде сжатых чанков. Запрос сначала выбирает потоки, а затем фильтрует текст. {unit="ssh.service"} |= "Failed password" выбирает поток по его метке, а затем сканирует эти чанки на наличие строки. Тело строки не индексируется, поэтому прием данных остается дешевым, а в памяти не нужно хранить инвертированный индекс. Затраты переносятся на время выполнения запроса, и это оправданный обмен, когда вы обычно знаете, какой сервис ищете.
Документация Grafana определяет монолитный режим, подразумевающий работу всего Loki в одном процессе с -target=all, как подходящий для небольших объемов чтения и записи — до 20GB в день. Один VPS отлично справляется с такой нагрузкой.
Ловушка заключается в кардинальности меток. Каждая уникальная комбинация значений меток образует отдельный поток, а количество потоков напрямую влияет на потребление памяти и размер индекса Loki. Метка, содержащая IP-адрес клиента или идентификатор запроса, создает отдельный поток для каждого значения, поэтому нагруженный веб-сервер может генерировать десятки тысяч потоков в день, и процесс будет расти, пока ядро не завершит его. Используйте в качестве меток только те значения, которые можно пересчитать на бумаге: unit, host, job, level. Переменные данные размещайте в самой строке лога, где их можно найти с помощью выражения фильтрации во время выполнения запроса.
Установка Loki и Alloy на один VPS
Эту работу выполняют два процесса. Loki хранит данные и отвечает на запросы. Grafana Alloy читает логи и отправляет их. Ранее для доставки логов использовался Promtail, но 2 марта 2026 года срок его поддержки истёк, поэтому новые установки используют Alloy, а официальный пример Docker от Loki теперь содержит конфигурацию для Alloy.
wget https://raw.githubusercontent.com/grafana/loki/v3.7.0/cmd/loki/loki-local-config.yaml -O loki-config.yamlПрочитайте этот файл перед использованием. В нём задан path_prefix: /tmp/loki с чанками в /tmp/loki/chunks, что подходит для демонстрации, но не для сервера: данные в /tmp контейнера удаляются при его пересоздании, поэтому история исчезнет при следующем обновлении образа. Укажите путь, который вы монтируете из файловой системы хоста.
common:
instance_addr: 127.0.0.1
path_prefix: /loki
storage:
filesystem:
chunks_directory: /loki/chunks
rules_directory: /loki/rules
replication_factor: 1
ring:
kvstore:
store: inmemorydocker volume create loki-data
docker run --name loki -d \
-v $(pwd):/mnt/config -v loki-data:/loki \
-p 127.0.0.1:3100:3100 \
grafana/loki:3.7.0 -config.file=/mnt/config/loki-config.yaml
curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1:3100/readyПоследняя команда должна вывести 200, так как /ready возвращает HTTP 200, когда Loki готов принимать трафик. Любой другой результат означает, что процесс ещё запускается или конфигурация была отклонена, а docker logs loki покажет причину. Две детали в команде запуска выбраны намеренно. Порт опубликован только на 127.0.0.1, так как пример конфигурации содержит auth_enabled: false, а Loki не имеет встроенной аутентификации пользователей. Любой, кто может подключиться к порту 3100, сможет прочитать все логи или записать ложные. Оставьте его на loopback-интерфейсе или за VPN либо аутентифицирующим reverse proxy. Именованный том важен, так как образ запускается от имени пользователя loki с UID 10001, поэтому контейнер не сможет записывать данные в примонтированную директорию хоста, принадлежащую root.
sudo apt-get update && sudo apt-get install -y gpg wget
sudo mkdir -p /etc/apt/keyrings/
sudo wget -O /etc/apt/keyrings/grafana.asc https://apt.grafana.com/gpg-full.key
echo "deb [signed-by=/etc/apt/keyrings/grafana.asc] https://apt.grafana.com stable main" \
| sudo tee /etc/apt/sources.list.d/grafana.list
sudo apt-get update
sudo apt-get install -y alloyAlloy читает /etc/alloy/config.alloy. Эта конфигурация считывает системный journal и набор файлов, отправляя их в локальный Loki.
loki.write "local" {
endpoint {
url = "http://127.0.0.1:3100/loki/api/v1/push"
}
}
loki.relabel "journal" {
forward_to = []
rule {
source_labels = ["__journal__systemd_unit"]
target_label = "unit"
}
}
loki.source.journal "read" {
forward_to = [loki.write.local.receiver]
relabel_rules = loki.relabel.journal.rules
labels = {job = "systemd-journal", host = "app-01"}
}
local.file_match "nginx" {
path_targets = [{"__path__" = "/var/log/nginx/*.log", "job" = "nginx", "host" = "app-01"}]
}
loki.source.file "nginx" {
targets = local.file_match.nginx.targets
forward_to = [loki.write.local.receiver]
}Правило relabel копирует поле journal __journal__systemd_unit в метку unit, что обеспечивает работу {unit="ssh.service"} в дальнейшем. Без этого правила имя юнита будет находиться внутри записи, а не в метке, поэтому вы не сможете фильтровать по нему, и каждый запрос будет сканировать всё содержимое.
sudo systemctl reload alloy
systemctl show -p User alloy
sudo journalctl -n 5
sudo -u alloy journalctl -n 5На этом этапе большинство установок перестают работать. Alloy запускается от имени собственной сервисной учётной записи, а не root. Чтение системного journal требует членства в группе systemd-journal, а файлы в /var/log/nginx принадлежат группе adm в Debian и Ubuntu. Подставьте учётную запись, которую systemctl show вывел в последней команде. Если записей возвращается значительно меньше, чем при запуске от root, значит, эта учётная запись не может прочитать системный journal, и Loki останется пустым, даже если конфигурация верна. Добавьте пользователя в группы и перезапустите процесс с помощью sudo usermod -aG systemd-journal,adm alloy, а затем sudo systemctl restart alloy.
curl -G -s "http://127.0.0.1:3100/loki/api/v1/query_range" \
--data-urlencode 'query={job="systemd-journal"}' \
--data-urlencode 'limit=5' | jq '.data.result | length'Число больше 0 означает, что потоки с этой меткой существуют и содержат записи. 0 означает, что данные с этой меткой ещё не поступали. Один параметр по умолчанию объясняет частую ложную тревогу: loki.source.journal устанавливает max_age в 7h, поэтому при первом запуске считываются логи только за последние семь часов. Для удобства работы запустите Grafana на том же сервере и укажите источник данных Loki по адресу http://127.0.0.1:3100.. Логи контейнеров требуют другого источника: Alloy обнаруживает запущенные Docker-контейнеры и читает их логи, как это сделано в примере Loki для начала работы. В случае одноузлового кластера k3s на VPS эта задача переносится в директорию логов пода, куда пишет kubelet.
Хранение: выбор срока жизни логов
Почти никто не задумывается о сроке хранения логов, пока не закончится место на диске, а затем это приходится делать в 3 часа ночи при неработающем сервисе. Определите этот срок в первый же день, ответив на два вопроса: как далеко назад вы реально заглядываете и что вам может понадобиться при разборе инцидента в следующем месяце. Для одного сервера диапазон от 14 до 30 дней закрывает оба вопроса.
Loki не удаляет ничего, пока вы не включите compactor. По умолчанию хранение отключено, что становится сюрпризом для тех, чей диск переполнился, пока retention_period бездействовал в конфигурации.
limits_config:
retention_period: 744h
compactor:
working_directory: /loki/retention
compaction_interval: 10m
retention_enabled: true
retention_delete_delay: 2h
retention_delete_worker_count: 150
delete_request_store: filesystem744h — это 31 день. Этот блок подчиняется четырем задокументированным правилам:
- Политика хранения применяется компонентом compactor, и документация Grafana рекомендует запускать его в единственном экземпляре. На одном VPS это происходит автоматически.
- Минимальный срок хранения составляет 24h, и механизм работает только при периоде индекса 24h. В примере
schema_configуже используетсяperiod: 24h, поэтому не меняйте это значение. - Параметр
delete_request_storeобязателен, еслиretention_enabledимеет значение true. Он указывает хранилище для запросов на удаление, поэтому для одиночного узла с файловой системой он должен совпадать сobject_store: filesystem, уже указанным в схеме. - Чанки (chunks) сначала помечаются, а затем удаляются по истечении
retention_delete_delay(в данном случае 2h), поэтому свободное место освобождается позже, чем предполагает политика. Не оценивайте эффективность настройки поdfчерез пять минут после перезагрузки.
OpenSearch удаляет целые индексы, а не отдельные строки, поэтому индексы логов создаются ежедневно. Политика ISM проводит индекс через различные состояния и удаляет его, когда он становится достаточно старым, а ism_template применяет эту политику к новым индексам, чтобы вам не приходилось делать это вручную.
Политика ISM для удаления индексов логов через 14 дней
{
"policy": {
"description": "delete log indexes after 14 days",
"default_state": "hot",
"states": [
{
"name": "hot",
"actions": [],
"transitions": [
{ "state_name": "delete", "conditions": { "min_index_age": "14d" } }
]
},
{
"name": "delete",
"actions": [ { "delete": {} } ],
"transitions": []
}
],
"ism_template": { "index_patterns": ["logs-*"], "priority": 100 }
}
}Создайте её с помощью PUT-запроса к _plugins/_ism/policies/logs-retention. Шаблон применяется к индексам, созданным после появления политики, поэтому для тех, что уже находятся на диске, политику нужно привязать вручную.
Какую бы систему вы ни использовали, значение срока хранения эффективно лишь до тех пор, пока работает проверка свободного места. Удаление логов через 14 дней не поможет, если 10 дней логов уже занимают весь объем диска, поэтому дополните политику мониторингом состояния диска на VPS и оповещением при заполнении на 80%.
Сколько дискового пространства требуется на 1 ГБ логов
Честный ответ зависит от количества строк и полей, поэтому измеряйте показатели на собственных данных, а не полагайтесь на опубликованные коэффициенты. Механизмы хранения различаются достаточно сильно, чтобы можно было предсказать направление роста. OpenSearch и Elasticsearch создают инвертированный индекс для каждого проиндексированного поля параллельно с хранением самого документа, поэтому объем данных на диске превышает размер исходного текста, а каждая реплика умножает этот объем. На одиночном узле установите количество реплик в 0, так как реплика шарды на том же узле не поможет при выходе узла из строя: значение 1 удваивает занимаемое место и навсегда переводит статус кластера в состояние yellow. Loki записывает сжатые чанки вместе с небольшим индексом меток, поэтому занимаемое место соответствует размеру сжатых строк.
sudo du -sh /var/lib/docker/volumes/loki-data/_data
curl -k -u admin:<password> "https://localhost:9200/_cat/indices?v&h=index,docs.count,store.size"Запустите соответствующие измерения в течение двух дней подряд. Разница между ними — ваш ежедневный прирост. Умножьте это значение на количество дней хранения, добавьте около 30% запаса на процессы компакции и слияния, а затем сравните результат с объемом диска. Если данные не помещаются, сократите срок хранения перед покупкой нового диска, так как увеличение объема лишь отложит ту же проблему на несколько недель.
Что выходит из строя первым на небольшом сервере
Первой заканчивается оперативная память. Механизм OOM (out of memory) killer в ядре выбирает наиболее ресурсоемкий процесс, и на сервере сбора логов таким процессом чаще всего оказывается JVM. journalctl -k | grep -i "killed process" показывает факт завершения процесса с его именем в скобках. Жертвой не всегда становится стек логирования: система может выбрать sshd или базу данных, из-за чего эксперимент с логированием приводит к падению приложения, логи которого вы пытались собрать. Установите для контейнеров явные лимиты, чтобы сбой происходил там, где вы это предусмотрели; для этого используются лимиты памяти в Docker Compose.
Вторым заканчивается дисковое пространство, и поисковые движки выходят из строя предсказуемым образом. Elasticsearch и OpenSearch отслеживают использование диска на нескольких уровнях. Нижний порог (low watermark) составляет 85%, верхний (high watermark) — 90%. При достижении критического уровня в 95% (flood stage) каждый индекс, имеющий шарды на этом узле, получает блокировку index.blocks.read_only_allow_delete, после чего операции записи завершаются с ошибкой blocked by: [FORBIDDEN/12/index read-only / allow delete (api)]. Блокировка снимается автоматически, как только использование диска падает ниже верхнего порога. Сначала освободите место, и только если блокировка сохраняется, снимайте её вручную.
curl -k -u admin:<password> -X PUT "https://localhost:9200/_all/_settings" \
-H 'Content-Type: application/json' \
-d '{"index.blocks.read_only_allow_delete": null}'Loki выходит из строя тише. У него нет режима «только чтение», поэтому переполнение тома проявляется в виде ошибок при отправке данных (failed pushes) на стороне отправителя и пропусках в результатах запросов, а проблема высокой кардинальности выражается в постепенном росте потребления памяти, а не в явной ошибке. Отслеживайте размер директории с чанками (chunks) по расписанию, а не после инцидента.
Последняя проблема — запись нецелевых данных. Система логирования — это не система метрик: хранить загрузку CPU, опрашиваемую каждые 10 секунд и сохраненную в текстовом виде, дорого и неудобно для построения графиков; эта задача предназначена для инструментов вроде сервера мониторинга Zabbix на Ubuntu 24.04. Исключения приложений требуют группировки, дедупликации и просмотра трассировки стека, что является задачей самостоятельно развернутого трекера ошибок. Оповещение о том, что сайт недоступен — это отдельная задача, которую решает система мониторинга аптайма и статуса, например Uptime Kuma. Используйте систему логирования для текстовых строк, которые будет читать человек.
FAQ
Нужен ли Elasticsearch для поиска по логам сервера?
Не для одного или двух серверов. journalctl уже позволяет фильтровать логи по юниту, приоритету, загрузке и временному интервалу, а ротированные файлы доступны через grep и zgrep. Кластер для поиска оправдывает затраты оперативной памяти, когда у вас много машин, когда нужен полнотекстовый поиск по всем ним одновременно или когда нескольким пользователям нужен общий интерфейс. В остальных случаях journald с установленными лимитами размера и времени хранения выполняет ту же задачу без лишнего потребления RAM.
Сколько оперативной памяти нужно для self-hosted системы управления логами?
Ориентируйтесь на официальные требования каждого проекта, а не на общие правила. Loki и Alloy — это программы на Go, которые не резервируют heap заранее, а Grafana указывает для монолитного Loki нагрузку до 20GB в день. В примерах compose для OpenSearch указано 512 MB heap для демо-режима и 2 GB для production-примера. Elastic утверждает, что heap должен составлять не более 50% от общего объема памяти, поэтому для 2 GB heap потребуется машина с 4 GB RAM до запуска Kibana. Документация Logstash рекомендует выделять не менее 4GB heap только для самого процесса. Это задокументированные настройки, а не результаты тестов, поэтому оценивайте собственную нагрузку перед планированием ресурсов.
В чем реальная разница между Loki и OpenSearch для логов?
В модели индексации. Loki индексирует только метки, а тело лога хранит в виде сжатых чанков, которые сканируются во время выполнения запроса. Поэтому запись логов обходится дешево, а широкие запросы требуют больше ресурсов. OpenSearch индексирует содержимое полей, поэтому произвольный полнотекстовый поиск выполняется быстро, но за это приходится платить памятью и дисковым пространством под индекс. Выбирайте Loki, если вы знаете, какой сервис и временной интервал вам нужны. Выбирайте OpenSearch, если вам нужно искать текст, который нельзя предсказать заранее.
Как долго следует хранить логи на VPS?
Определите срок хранения до того, как это сделает за вас переполненный диск. Установите лимиты в одном месте для каждой системы: MaxRetentionSec= и SystemMaxUse= для journald, retention_period с включенным compactor для Loki и политику ISM с min_index_age для OpenSearch. Для большинства конфигураций на одном сервере 14–30 дней достаточно для отладки и анализа инцидентов. Все, что нужно хранить дольше, следует копировать на внешний носитель, так как лог, хранящийся только на вышедшем из строя сервере, не является надежной записью.
Является ли Promtail все еще актуальным способом отправки логов в Loki?
Нет. Срок поддержки Promtail истек 2 марта 2026 года, его заменил Grafana Alloy. В актуальных примерах установки Loki через Docker теперь используется конфигурация Alloy, а Grafana предоставляет конвертер, который преобразует существующий конфиг Promtail в синтаксис Alloy. Существующая установка Promtail продолжит работать, но она не получает исправлений, поэтому рассматривайте миграцию как плановое обслуживание, а не как обновление, которое можно откладывать бесконечно.