بلاگ/راه‌اندازی سیستم لاگ متمرکز برای چند سرور با Grafana Loki و Alloy
به‌روز شده

راه‌اندازی سیستم لاگ متمرکز برای چند سرور با Grafana Loki و Alloy

1405/06/060 بازدید
راه‌اندازی سیستم لاگ متمرکز برای چند سرور با Grafana Loki و Alloy

راه‌اندازی سیستم لاگ متمرکز برای چند سرور با Grafana Loki و Alloy

نمایی انتزاعی از انتقال لاگ چند سرور به یک سامانه مرکزی وقتی فقط یک سرور دارید، اجرای journalctl یا بررسی فایل‌های داخل /var/log معمولاً کافی است. با افزایش تعداد سرورها، همین کار ساده وقت‌گیر می‌شود: برای پیدا کردن یک خطا باید وارد چند ماشین شوید، بازه زمانی هر کدام را بررسی کنید و امیدوار باشید لاگ موردنظر هنوز پاک نشده باشد. در این راهنما، یک معماری ساده برای راه‌اندازی لاگ متمرکز با Grafana Loki می‌سازیم. Loki و Grafana روی یک سرور مرکزی اجرا می‌شوند و Grafana Alloy لاگ‌های هر سرور لینوکسی را جمع‌آوری و ارسال می‌کند. در پایان می‌توانیم همه لاگ‌ها را از یک رابط جست‌وجو کنیم، با LogQL فیلتر بسازیم و برای نگه‌داری داده‌ها محدودیت مشخصی بگذاریم.

معماری مورد استفاده

برای نمونه، این زیرساخت را در نظر می‌گیریم: - یک سرور مرکزی با آدرس خصوصی 10.10.0.10 - دو یا چند سرور مجازی یا اختصاصی به‌عنوان منبع لاگ - Docker و Docker Compose روی سرور مرکزی - Docker روی سرورهای منبع برای اجرای Alloy - ارتباط خصوصی میان سرورها، مانند VLAN، تونل WireGuard یا شبکه داخلی دیتاسنتر هر سرور منبع، فایل‌های لاگ محلی را با Alloy می‌خواند. Alloy برای هر جریان لاگ برچسب‌هایی مانند نام سرور، نوع سرویس و نام فایل می‌سازد و داده را به Loki می‌فرستد. Grafana نیز Loki را به‌عنوان Data Source می‌خواند. مسیر جریان داده در معماری لاگ متمرکز: Alloy روی هر سرور منبع لاگ‌های محلی را می‌خواند و برچسب‌گذاری می‌کند، آن‌ها را به Loki روی سرور مرکزی می‌فرستد و Grafana لاگ‌ها را از Loki می‌خواند و نمایش می‌دهد Loki برخلاف سامانه‌هایی که متن کامل هر خط را ایندکس می‌کنند، بیشتر برچسب‌های لاگ را ایندکس می‌کند. این روش معمولاً مصرف دیسک و حافظه کمتری دارد، اما انتخاب نادرست برچسب‌ها می‌تواند کارایی را کاهش دهد.

Loki، Alloy و Grafana چه وظیفه‌ای دارند؟

اجزای این سامانه مسئولیت‌های جداگانه‌ای دارند:

مؤلفهمحل اجراوظیفه
Grafana Alloyهر سرور منبعخواندن، برچسب‌گذاری و ارسال لاگ
Grafana Lokiسرور مرکزیذخیره و جست‌وجوی لاگ‌ها
Grafanaسرور مرکزینمایش، جست‌وجو، داشبورد و هشدار
LogQLداخل Grafana یا APIفیلتر و تحلیل داده‌های Loki

Promtail قبلاً ایجنت رایج Loki بود، اما Alloy گزینه جدیدتر Grafana برای جمع‌آوری سیگنال‌های مشاهده‌پذیری است. Alloy علاوه بر لاگ، برای متریک، تریس و پروفایل نیز قابل استفاده است. در این مقاله فقط مسیر جمع‌آوری لاگ را فعال می‌کنیم.

آماده‌سازی سرور مرکزی

ابتدا یک پوشه برای سرویس‌ها بسازید:

sudo mkdir -p /opt/central-logging/{loki,grafana/provisioning/datasources}
cd /opt/central-logging

فایل /opt/central-logging/loki/config.yaml را با محتوای زیر ایجاد کنید:

auth_enabled: false
server:
  http_listen_port: 3100
common:
  path_prefix: /loki
  replication_factor: 1
  ring:
    kvstore:
      store: inmemory
  storage:
    filesystem:
      chunks_directory: /loki/chunks
      rules_directory: /loki/rules
schema_config:
  configs:
    - from: 2024-01-01
      store: tsdb
      object_store: filesystem
      schema: v13
      index:
        prefix: index_
        period: 24h
compactor:
  working_directory: /loki/compactor
  retention_enabled: true
  delete_request_store: filesystem
limits_config:
  retention_period: 720h

مقدار 720h یعنی لاگ‌ها ۳۰ روز نگه‌داری شوند. این عدد را باید با ظرفیت دیسک، حجم روزانه لاگ و نیاز عملیاتی تنظیم کنید. سپس Data Source مربوط به Grafana را در فایل /opt/central-logging/grafana/provisioning/datasources/loki.yaml قرار دهید:

apiVersion: 1
datasources:
  - name: Loki
    type: loki
    access: proxy
    url: http://loki:3100
    isDefault: true
    editable: false

حالا فایل compose.yaml را بسازید:

services:
  loki:
    image: grafana/loki:3.2.1
    command: -config.file=/etc/loki/config.yaml
    restart: unless-stopped
    volumes:
      - ./loki/config.yaml:/etc/loki/config.yaml:ro
      - loki-data:/loki
    ports:
      - "10.10.0.10:3100:3100"
  grafana:
    image: grafana/grafana:11.3.1
    restart: unless-stopped
    environment:
      GF_SECURITY_ADMIN_USER: admin
      GF_SECURITY_ADMIN_PASSWORD: change-this-password
    volumes:
      - grafana-data:/var/lib/grafana
      - ./grafana/provisioning:/etc/grafana/provisioning:ro
    ports:
      - "10.10.0.10:3000:3000"
    depends_on:
      - loki
volumes:
  loki-data:
  grafana-data:

نسخه‌های تصویر نمونه هستند. پیش از استقرار، یک نسخه پایدار و پشتیبانی‌شده را انتخاب و همان نسخه را ثابت کنید. استفاده از تگ latest ممکن است پس از به‌روزرسانی خودکار، تغییر ناسازگاری وارد کند. سرویس‌ها را اجرا کنید:

sudo docker compose up -d
sudo docker compose ps

آماده بودن Loki را بررسی کنید:

curl http://10.10.0.10:3100/ready

پاسخ ready نشان می‌دهد سرویس درخواست می‌پذیرد. رابط Grafana نیز روی پورت 3000 در دسترس است.

نصب و تنظیم Alloy روی سرورهای منبع

روی هر سرور منبع، پوشه‌های لازم را ایجاد کنید:

sudo mkdir -p /opt/alloy
cd /opt/alloy

فایل /opt/alloy/config.alloy را بسازید:

local.file_match "system_logs" {
  path_targets = [
    {
      "__path__" = "/var/log/syslog",
      "job"      = "system",
      "host"     = "app-01",
    },
    {
      "__path__" = "/var/log/auth.log",
      "job"      = "auth",
      "host"     = "app-01",
    },
    {
      "__path__" = "/var/log/nginx/*.log",
      "job"      = "nginx",
      "host"     = "app-01",
    },
  ]
}
loki.source.file "local_files" {
  targets    = local.file_match.system_logs.targets
  forward_to = [loki.write.central.receiver]
}
loki.write "central" {
  endpoint {
    url = "http://10.10.0.10:3100/loki/api/v1/push"
  }
}

در هر سرور، مقدار برچسب host را تغییر دهید؛ برای مثال db-01 یا web-02. بهتر است این نام ثابت و قابل تشخیص باشد. فایل Compose مربوط به Alloy:

services:
  alloy:
    image: grafana/alloy:v1.5.1
    command:
      - run
      - --storage.path=/var/lib/alloy/data
      - /etc/alloy/config.alloy
    restart: unless-stopped
    volumes:
      - ./config.alloy:/etc/alloy/config.alloy:ro
      - alloy-data:/var/lib/alloy/data
      - /var/log:/var/log:ro
volumes:
  alloy-data:

Alloy برای ثبت محل خواندن فایل‌ها به فضای ذخیره‌سازی پایدار نیاز دارد. اگر volume مربوط به alloy-data حذف شود، ممکن است پس از شروع دوباره بخشی از فایل‌ها مجدداً خوانده شوند. ایجنت را اجرا و خروجی آن را بررسی کنید:

sudo docker compose up -d
sudo docker compose logs --tail=100 alloy

همین تنظیم را روی سرورهای دیگر تکرار کنید و برچسب host را برای هر ماشین تغییر دهید. در توزیع‌هایی مانند Rocky Linux یا AlmaLinux ممکن است مسیر /var/log/messages و /var/log/secure به‌جای syslog و auth.log استفاده شود. مسیرها را متناسب با توزیع خود تنظیم کنید.

دسترسی فایل‌ها و عیب‌یابی ارسال

اگر هیچ لاگی به Loki نمی‌رسد، ابتدا بررسی کنید فایل‌ها داخل کانتینر Alloy دیده می‌شوند:

sudo docker compose exec alloy ls -la /var/log

سپس دسترسی شبکه را آزمایش کنید:

curl http://10.10.0.10:3100/ready

در سرور مرکزی نیز لاگ Loki را ببینید:

sudo docker compose logs --tail=200 loki

خطاهای permission denied معمولاً به مجوز فایل یا محدودیت‌هایی مانند SELinux مربوط‌اند. خطاهای connection refused نیز اغلب از آدرس اشتباه، فایروال یا اجرا نشدن Loki ناشی می‌شوند. پورت 3100 را روی اینترنت عمومی باز نکنید. در این پیکربندی، احراز هویت داخلی Loki غیرفعال است و فرض می‌شود ارتباط از شبکه خصوصی انجام می‌شود. برای محیط عمومی باید یک Reverse Proxy با TLS و احراز هویت در جلوی Loki قرار گیرد.

جست‌وجوی لاگ‌ها با LogQL

در Grafana وارد بخش Explore شوید و Data Source پیش‌فرض Loki را انتخاب کنید. برای مشاهده همه لاگ‌های یک سرور:

{host="app-01"}

برای مشاهده لاگ‌های Nginx همان سرور:

{host="app-01", job="nginx"}

برای پیدا کردن خطوطی که شامل عبارت error هستند:

{host="app-01"} |= "error"

جست‌وجوی بدون حساسیت به حروف کوچک و بزرگ:

{job="nginx"} |~ "(?i)error|timeout|failed"

اگر لاگ Nginx در قالب JSON نوشته می‌شود، می‌توان فیلدها را استخراج کرد:

{job="nginx"} | json | status >= 500

برای شمارش خطاها در بازه‌های پنج‌دقیقه‌ای:

sum by (host) (
  count_over_time({job="nginx"} |~ " 5[0-9]{2} " [5m])
)

انتخاب درست برچسب‌ها

برچسب‌هایی مانند host، job، environment و datacenter معمولاً تعداد مقادیر محدودی دارند و برای فیلتر اولیه مناسب‌اند. داده‌هایی مانند شناسه درخواست، IP کاربر، URL کامل یا شناسه سفارش نباید برچسب شوند؛ چون برای هر خط ممکن است مقدار متفاوتی داشته باشند. این وضعیت با نام cardinality بالا شناخته می‌شود و می‌تواند مصرف حافظه و حجم ایندکس را افزایش دهد. چنین مقادیری را داخل متن یا ساختار JSON لاگ نگه دارید و هنگام اجرای کوئری استخراج کنید. برای شروع، همین سه برچسب کافی است:

host=app-01
job=nginx
environment=production

اگر چند محیط دارید، می‌توانید environment را در بخش path_targets تنظیم کنید.

مدیریت نگه‌داری و فضای دیسک

محدودیت ۳۰روزه فقط نقطه شروع است. برای انتخاب مقدار مناسب، حجم واقعی داده را برای چند روز اندازه بگیرید. اگر مجموعه سرورها روزانه ۲۰ گیگابایت لاگ تولید کند، نگه‌داری ۳۰روزه بدون درنظر گرفتن فشرده‌سازی، رشد ایندکس و فضای آزاد به برنامه‌ریزی دقیق نیاز دارد. چند کار ساده جلوی پر شدن ناگهانی دیسک را می‌گیرد: - برای volume لوکی فضای جداگانه در نظر بگیرید. - میزان مصرف دیسک را مانیتور کنید و پیش از رسیدن به آستانه خطر هشدار بسازید. - لاگ‌های کم‌ارزش یا تکراری را پیش از ارسال حذف کنید. - سطح لاگ برنامه‌ها را در حالت عادی روی info نگه دارید و debug را موقت فعال کنید. - نسخه پشتیبان تنظیمات را نگه دارید؛ Loki را جایگزین بکاپ امنیتی یا آرشیو قانونی فرض نکنید. ذخیره‌سازی filesystem برای یک استقرار کوچک و تک‌سروری مناسب است. اگر حجم داده یا نیاز به دسترس‌پذیری افزایش یافت، از Object Storage سازگار با S3 و معماری چندنمونه‌ای Loki استفاده کنید.

ساخت داشبورد عملیاتی

یک داشبورد ساده می‌تواند شامل نرخ کل لاگ، تعداد خطاها به تفکیک سرور، خطاهای HTTP سری ۵۰۰ و تازه‌ترین پیام‌های سرویس‌های حساس باشد. متغیری با نام host نیز بسازید تا اپراتور بتواند سرور را از بالای داشبورد انتخاب کند. داشبورد جای Explore را نمی‌گیرد. داشبورد برای الگوهای شناخته‌شده مناسب است؛ Explore زمانی کاربرد دارد که خطایی تازه رخ داده و هنوز کوئری ثابتی برای آن ندارید. برای هشدار نیز ابتدا شرایط مشخصی تعریف کنید؛ مثلاً بیشتر شدن تعداد خطاهای Nginx از یک آستانه در پنج دقیقه. هشدار روی هر عبارت error معمولاً نویز زیادی تولید می‌کند.

انتخاب زیرساخت مناسب برای سرور مرکزی

سرور Loki به دیسک پایدار، فضای کافی و ارتباط شبکه مناسب با سرورهای منبع نیاز دارد. مصرف CPU و حافظه به تعداد جریان‌ها، حجم لاگ و پیچیدگی کوئری‌ها بستگی دارد؛ بنابراین ظرفیت را با داده واقعی تنظیم کنید، نه فقط تعداد سرورها. اگر برای اجرای Loki و Grafana به یک ماشین مستقل نیاز دارید، می‌توانید مشخصات سرور ابری آریاسرویس را بررسی کنید. برای محیط کوچک، بهتر است با منابع محدود شروع کنید و پس از اندازه‌گیری نرخ ورود لاگ و مصرف دیسک، ظرفیت را افزایش دهید.

جمع‌بندی

در این معماری، Alloy روی هر سرور فایل‌های لاگ را می‌خواند، Loki آن‌ها را روی سرور مرکزی ذخیره می‌کند و Grafana امکان جست‌وجو و ساخت داشبورد را می‌دهد. پس از راه‌اندازی اولیه، مهم‌ترین کارها انتخاب برچسب‌های کم‌تعداد، محدود کردن دسترسی شبکه، تعیین دوره نگه‌داری و مانیتور کردن فضای دیسک هستند. راه‌اندازی لاگ متمرکز با Grafana Loki زمانی مفیدتر می‌شود که نام‌گذاری برچسب‌ها میان همه سرورها یکسان باشد. پیش از اضافه کردن تعداد زیادی منبع، الگوی host، job و environment را مشخص کنید تا کوئری‌ها و داشبوردها بعداً به بازنویسی گسترده نیاز نداشته باشند.