بلاگ/راه‌اندازی مانیتورینگ سرور با Prometheus و Grafana روی سرور مجازی و اختصاصی
به‌روز شده

راه‌اندازی مانیتورینگ سرور با Prometheus و Grafana روی سرور مجازی و اختصاصی

1405/06/170 بازدید
راه‌اندازی مانیتورینگ سرور با Prometheus و Grafana روی سرور مجازی و اختصاصی

راه‌اندازی مانیتورینگ سرور با Prometheus و Grafana روی سرور مجازی و اختصاصی

وقتی مصرف CPU برای چند دقیقه بالا می‌رود، فضای دیسک رو به پایان است یا حافظهٔ سرور به‌تدریج پر می‌شود، ورود دستی با SSH معمولاً دیرتر از زمانی انجام می‌شود که مشکل بر سرویس اثر گذاشته است. یک سامانهٔ مانیتورینگ مناسب باید وضعیت فعلی را نشان دهد، داده‌های گذشته را نگه دارد و پیش از بحرانی‌شدن شرایط هشدار بفرستد. در این راهنما، راه‌اندازی مانیتورینگ سرور با Prometheus و Grafana را با Docker Compose انجام می‌دهیم. Prometheus معیارها را جمع‌آوری و ذخیره می‌کند، Node Exporter اطلاعات سیستم‌عامل را در اختیار آن می‌گذارد و Grafana داده‌ها را به نمودار و داشبورد تبدیل می‌کند. این روش برای یک سرور مجازی، سرور اختصاصی یا یک ماشین مانیتورینگ مرکزی مناسب است. دستورها بر مبنای Ubuntu و Debian نوشته شده‌اند، اما ساختار پیکربندی در توزیع‌های دیگر نیز تفاوت زیادی ندارد. نمای کلی ارتباط Prometheus، Node Exporter و Grafana در سامانه مانیتورینگ سرور

اجزای استک مانیتورینگ چه کاری انجام می‌دهند؟

هر جزء مسئولیت مشخصی دارد: - Node Exporter معیارهایی مانند بار پردازنده، حافظه، فضای دیسک، ورودی و خروجی شبکه و وضعیت فایل‌سیستم را از لینوکس می‌خواند. - Prometheus در بازه‌های زمانی مشخص به endpoint معیارها متصل می‌شود، داده‌ها را جمع می‌کند و در پایگاه دادهٔ سری زمانی خود نگه می‌دارد. - Grafana به Prometheus متصل می‌شود و داده‌ها را در داشبوردهای قابل‌فهم نمایش می‌دهد. - Alertmanager در صورت نیاز هشدارهای Prometheus را گروه‌بندی و به مقصدهایی مانند ایمیل، Slack یا webhook ارسال می‌کند. برای شروع، سه جزء اول کافی‌اند. Alertmanager را پس از اطمینان از صحت جمع‌آوری معیارها اضافه می‌کنیم.

منابع موردنیاز برای Prometheus و Grafana

میزان مصرف منابع به تعداد سرورها، تعداد معیارها، فاصلهٔ scrape و مدت نگهداری داده وابسته است. برای مانیتورینگ یک تا پنج سرور با فاصلهٔ جمع‌آوری ۱۵ ثانیه، مقادیر زیر نقطهٔ شروع مناسبی هستند:

تعداد سرورپردازنده پیشنهادیحافظهٔ پیشنهادیفضای ذخیره‌سازی اولیه
۱ تا ۵۲ هسته۲ تا ۴ گیگابایت۲۰ تا ۴۰ گیگابایت SSD
۶ تا ۲۰۴ هسته۸ گیگابایت۸۰ تا ۱۵۰ گیگابایت SSD
بیش از ۲۰وابسته به تعداد سری‌هاحداقل ۸ گیگابایتبر اساس نرخ رشد داده

این اعداد قطعی نیستند. اگر exporterهای متعدد، سرویس‌های Kubernetes یا معیارهای برنامه را نیز جمع‌آوری کنید، تعداد سری‌های زمانی و مصرف دیسک بیشتر می‌شود. بعد از چند روز، حجم دایرکتوری دادهٔ Prometheus و نرخ رشد آن را بررسی کنید. بهتر است استک مانیتورینگ روی ماشینی جدا از سرویس اصلی اجرا شود. در این حالت، اختلال یا پرشدن منابع سرور برنامه، دسترسی شما به داشبورد مانیتورینگ را هم از بین نمی‌برد.

پیش‌نیازهای نصب

پیش از شروع مطمئن شوید که: - یک سرور لینوکسی با دسترسی sudo دارید. - Docker Engine و افزونهٔ Docker Compose نصب شده‌اند. - پورت‌های موردنیاز در فایروال مشخص شده‌اند. - ساعت سیستم با NTP همگام است. - برای محیط عمومی، دامنه و گواهی TLS یا دست‌کم دسترسی VPN دارید. نسخه‌های نصب‌شده را بررسی کنید:

docker --version
docker compose version
timedatectl status

در این راهنما سرویس‌های زیر استفاده می‌شوند:

سرویسپورت پیش‌فرضدسترسی پیشنهادی
Grafana3000فقط از طریق reverse proxy با HTTPS
Prometheus9090شبکهٔ داخلی یا VPN
Node Exporter9100فقط IP سرور Prometheus
Alertmanager9093شبکهٔ داخلی یا VPN

پورت‌های Prometheus، Node Exporter و Alertmanager را بدون محدودیت روی اینترنت باز نکنید. این endpointها ممکن است اطلاعاتی دربارهٔ نام میزبان، فایل‌سیستم و ساختار زیرساخت نشان دهند.

ساخت ساختار پروژه

ابتدا یک دایرکتوری برای فایل‌های پیکربندی بسازید:

sudo mkdir -p /opt/monitoring/{prometheus,grafana/provisioning/datasources}
sudo chown -R "$USER":"$USER" /opt/monitoring
cd /opt/monitoring

ساختار نهایی چنین خواهد بود:

/opt/monitoring/
├── compose.yaml
├── prometheus/
│   ├── prometheus.yml
│   └── alerts.yml
└── grafana/
    └── provisioning/
        └── datasources/
            └── prometheus.yml

پیکربندی Prometheus و هدف‌های scrape

فایل prometheus/prometheus.yml را ایجاد کنید:

global:
  scrape_interval: 15s
  evaluation_interval: 15s
rule_files:
  - /etc/prometheus/alerts.yml
scrape_configs:
  - job_name: prometheus
    static_configs:
      - targets:
          - prometheus:9090
  - job_name: linux-servers
    static_configs:
      - targets:
          - node-exporter:9100
        labels:
          environment: production
          server_role: monitoring

در این فایل، Prometheus هر ۱۵ ثانیه معیارها را می‌خواند. نام‌های environment و server_role برچسب‌های اختیاری‌اند، اما هنگام ساخت داشبورد یا فیلترکردن هشدارها مفید هستند. اگر Node Exporter روی سرورهای دیگری نصب شده است، IP خصوصی یا نام DNS آن‌ها را به فهرست اضافه کنید:

  - job_name: linux-servers
    static_configs:
      - targets:
          - 10.10.0.11:9100
          - 10.10.0.12:9100
        labels:
          environment: production

برای جلوگیری از خطاهای YAML از فاصله استفاده کنید و سراغ Tab نروید. همچنین هر بار پس از تغییر فایل، پیکربندی Prometheus را بررسی کنید:

docker run --rm \
  -v "$PWD/prometheus:/etc/prometheus:ro" \
  prom/prometheus:latest \
  promtool check config /etc/prometheus/prometheus.yml

در محیط تولید بهتر است به‌جای latest یک نسخهٔ مشخص و آزمایش‌شده را در فایل Compose ثبت کنید تا ارتقای ناخواسته رخ ندهد.

تعریف سرویس‌ها در Docker Compose

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

services:
  prometheus:
    image: prom/prometheus:latest
    container_name: prometheus
    restart: unless-stopped
    command:
      - --config.file=/etc/prometheus/prometheus.yml
      - --storage.tsdb.path=/prometheus
      - --storage.tsdb.retention.time=30d
    volumes:
      - ./prometheus/prometheus.yml:/etc/prometheus/prometheus.yml:ro
      - ./prometheus/alerts.yml:/etc/prometheus/alerts.yml:ro
      - prometheus-data:/prometheus
    ports:
      - "127.0.0.1:9090:9090"
    networks:
      - monitoring
  node-exporter:
    image: prom/node-exporter:latest
    container_name: node-exporter
    restart: unless-stopped
    command:
      - --path.rootfs=/host
    volumes:
      - /:/host:ro,rslave
    ports:
      - "127.0.0.1:9100:9100"
    networks:
      - monitoring
  grafana:
    image: grafana/grafana-oss:latest
    container_name: grafana
    restart: unless-stopped
    environment:
      GF_SECURITY_ADMIN_USER: admin
      GF_SECURITY_ADMIN_PASSWORD: ${GRAFANA_ADMIN_PASSWORD}
      GF_USERS_ALLOW_SIGN_UP: "false"
    volumes:
      - grafana-data:/var/lib/grafana
      - ./grafana/provisioning:/etc/grafana/provisioning:ro
    ports:
      - "127.0.0.1:3000:3000"
    networks:
      - monitoring
networks:
  monitoring:
volumes:
  prometheus-data:
  grafana-data:

محدودکردن پورت‌ها به 127.0.0.1 باعث می‌شود سرویس‌ها مستقیماً از اینترنت در دسترس نباشند. برای مشاهدهٔ Grafana می‌توانید از SSH tunnel استفاده کنید:

ssh -L 3000:127.0.0.1:3000 user@server-ip

سپس http://localhost:3000 را در مرورگر باز کنید. در محیط دائمی، Nginx یا Caddy را جلوی Grafana قرار دهید و HTTPS را فعال کنید. رمز عبور Grafana را در فایل .env بگذارید:

GRAFANA_ADMIN_PASSWORD=replace-with-a-long-random-password

از commit‌کردن این فایل در مخزن Git خودداری کنید.

افزودن خودکار Prometheus به Grafana

برای اینکه پس از هر بار ساخت کانتینر مجبور به تعریف دستی data source نباشید، فایل grafana/provisioning/datasources/prometheus.yml را بسازید:

apiVersion: 1
datasources:
  - name: Prometheus
    type: prometheus
    access: proxy
    url: http://prometheus:9090
    isDefault: true
    editable: false

یک فایل اولیه برای قوانین هشدار نیز ایجاد کنید تا mount مربوط به آن معتبر باشد:

touch prometheus/alerts.yml

اکنون سرویس‌ها را بالا بیاورید:

docker compose up -d
docker compose ps

لاگ‌ها را برای خطاهای احتمالی بررسی کنید:

docker compose logs --tail=100 prometheus
docker compose logs --tail=100 node-exporter
docker compose logs --tail=100 grafana

نمودار جریان معیارها از سرورها تا جمع‌آوری در Prometheus و نمایش در داشبورد Grafana

بررسی جمع‌آوری داده و ساخت داشبورد اول

ابتدا در رابط Prometheus به بخش Status > Targets بروید. وضعیت هدف‌های prometheus و linux-servers باید UP باشد. با SSH tunnel جداگانه می‌توانید رابط Prometheus را باز کنید:

ssh -L 9090:127.0.0.1:9090 user@server-ip

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

up
100 - (
  avg by (instance) (
    rate(node_cpu_seconds_total{mode="idle"}[5m])
  ) * 100
)

پرس‌وجوی دوم درصد تقریبی مصرف CPU را برای هر سرور نشان می‌دهد. برای محاسبهٔ درصد حافظهٔ مصرف‌شده می‌توان از این عبارت استفاده کرد:

100 * (
  1 - (
    node_memory_MemAvailable_bytes
    /
    node_memory_MemTotal_bytes
  )
)

در Grafana وارد بخش ساخت داشبورد شوید، یک visualization اضافه کنید و data source را روی Prometheus قرار دهید. یکی از پرس‌وجوهای بالا را وارد کنید و نوع نمایش را Time series یا Gauge بگذارید. برای رسیدن سریع‌تر به یک داشبورد کامل، می‌توانید داشبوردهای آمادهٔ Node Exporter را از کاتالوگ Grafana وارد کنید. قبل از استفاده در محیط تولید، پرس‌وجوها، متغیرها و شناسهٔ job داشبورد را با پیکربندی خود تطبیق دهید؛ هر داشبورد عمومی لزوماً با نام برچسب‌ها و نسخهٔ exporter شما سازگار نیست.

مانیتورینگ چند سرور

در معماری چندسروری معمولاً Prometheus و Grafana فقط روی سرور مانیتورینگ اجرا می‌شوند و Node Exporter روی هر ماشین مقصد قرار می‌گیرد. در این حالت، پورت 9100 هر سرور باید فقط برای IP خصوصی سرور Prometheus مجاز باشد. اگر UFW فعال است، روی سرور مقصد می‌توانید دسترسی را محدود کنید:

sudo ufw allow from 10.10.0.5 to any port 9100 proto tcp

در این مثال 10.10.0.5 آدرس خصوصی سرور Prometheus است. اگر شبکهٔ خصوصی ندارید، از VPNهایی مانند WireGuard استفاده کنید. قراردادن Node Exporter پشت نام کاربری و رمز عبور به‌تنهایی جای شبکهٔ محدودشده و TLS را نمی‌گیرد. برای نصب Node Exporter روی میزبان‌های دیگر، می‌توانید همان سرویس Compose را در یک فایل مستقل اجرا کنید. سپس IP خصوصی آن ماشین را به targets در prometheus.yml اضافه کرده و Prometheus را reload کنید:

docker kill --signal=SIGHUP prometheus

پس از reload دوباره صفحهٔ Targets را بررسی کنید.

تعریف هشدار برای قطعی و کمبود فضای دیسک

فایل prometheus/alerts.yml را به شکل زیر تکمیل کنید:

groups:
  - name: server-health
    rules:
      - alert: ServerTargetDown
        expr: up{job="linux-servers"} == 0
        for: 2m
        labels:
          severity: critical
        annotations:
          summary: "دسترسی Prometheus به سرور قطع شده است"
          description: "هدف {{ $labels.instance }} بیش از دو دقیقه در دسترس نیست."
      - alert: DiskSpaceLow
        expr: |
          (
            node_filesystem_avail_bytes{
              fstype!~"tmpfs|overlay|squashfs"
            }
            /
            node_filesystem_size_bytes{
              fstype!~"tmpfs|overlay|squashfs"
            }
          ) * 100 < 15
        for: 10m
        labels:
          severity: warning
        annotations:
          summary: "فضای آزاد دیسک کمتر از ۱۵ درصد است"
          description: "فضای فایل‌سیستم {{ $labels.mountpoint }} روی {{ $labels.instance }} رو به پایان است."

فایل قوانین را اعتبارسنجی کنید:

docker exec prometheus \
  promtool check rules /etc/prometheus/alerts.yml

سپس Prometheus را reload کنید. وضعیت قوانین در بخش Alerts قابل مشاهده است. این قوانین فقط هشدار را در Prometheus فعال می‌کنند؛ برای ارسال پیام باید Alertmanager را به استک اضافه و مقصد اعلان را تنظیم کنید. آستانه‌ها را متناسب با رفتار واقعی سرویس انتخاب کنید. هشدار CPU با عبور لحظه‌ای از ۸۰ درصد معمولاً نویز زیادی تولید می‌کند. استفاده از شرط زمانی مانند for: 10m کمک می‌کند فقط وضعیت پایدار گزارش شود.

نگهداری، امنیت و پشتیبان‌گیری

داده‌های Prometheus با گزینهٔ retention.time در نمونهٔ بالا برای ۳۰ روز نگه داشته می‌شوند. اگر فضای دیسک محدود است، این بازه را کاهش دهید یا سقف حجمی تعیین کنید. فضای volume را مرتب بررسی کنید:

docker system df -v
docker exec prometheus du -sh /prometheus

برای پشتیبان‌گیری، تنظیمات Compose، فایل‌های Prometheus و provisioning گرافانا را نگه دارید. داشبوردهایی که فقط از رابط Grafana ساخته شده‌اند در volume گرافانا قرار دارند؛ آن‌ها را به JSON صادر کنید یا provisioning داشبورد را به پروژه بیفزایید. چند اقدام ضروری دیگر عبارت‌اند از: - imageها را با نسخهٔ مشخص pin و ارتقا را ابتدا در محیط آزمایشی بررسی کنید. - Grafana را پشت HTTPS قرار دهید و ثبت‌نام عمومی را غیرفعال نگه دارید. - دسترسی مدیر Grafana را محدود و رمز اولیه را تعویض کنید؛ برای سخت‌کردن کل سرور نیز می‌توانید از راهنمای افزایش امنیت سرور لینوکس کمک بگیرید. - برای دیسک خود سامانهٔ مانیتورینگ نیز هشدار بسازید. - فایل .env و اطلاعات webhook را وارد Git نکنید. - بعد از هر تغییر، targets، قوانین هشدار و لاگ کانتینرها را بررسی کنید.

خطاهای رایج

اگر target در وضعیت DOWN است، از داخل کانتینر Prometheus اتصال را بررسی کنید:

docker exec prometheus \
  wget -qO- http://node-exporter:9100/metrics | head

خطای connection refused معمولاً به اجرا نبودن exporter، اشتباه‌بودن آدرس یا بسته‌بودن پورت مربوط است. خطای timeout بیشتر به فایروال، route شبکه یا آدرس خصوصی اشتباه اشاره دارد. اگر Grafana داده‌ای نشان نمی‌دهد، ابتدا در Explore عبارت up را اجرا کنید. نبودن نتیجه در این بخش معمولاً مشکل data source یا Prometheus است؛ وجود نتیجه همراه با پنل خالی، بیشتر از ناسازگاری query یا متغیرهای داشبورد می‌آید. اگر Prometheus پیوسته restart می‌شود، لاگ آن و نتیجهٔ promtool را ببینید. تورفتگی اشتباه YAML و mount‌شدن فایل در مسیر نادرست از علت‌های پرتکرار هستند.

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

برای چند ماشین و حجم متعارف معیارها، یک VPS با دیسک SSD معمولاً کافی است. اگر قرار است داده‌های تعداد زیادی سرور را با retention طولانی ذخیره کنید، سرعت و ظرفیت دیسک اهمیت بیشتری پیدا می‌کند. در زیرساخت‌های بزرگ‌تر نیز می‌توان Prometheus را با راهکارهای ذخیره‌سازی بلندمدت یا معماری توزیع‌شده تکمیل کرد. برای شروع یک نود مانیتورینگ مستقل، می‌توانید مشخصات سرور مجازی ابری آریاسرویس را بررسی کنید. اندازهٔ پلن را بر اساس تعداد targetها، مدت نگهداری داده و نرخ رشد مصرف دیسک انتخاب کنید.

جمع‌بندی

با اجرای Node Exporter، Prometheus و Grafana یک مسیر کامل از جمع‌آوری معیار تا نمایش داشبورد در اختیار دارید. راه‌اندازی اولیه پایان کار نیست: محدودکردن دسترسی شبکه، تنظیم retention، تعریف هشدارهای کم‌نویز، پشتیبان‌گیری از داشبوردها و کنترل رشد دیسک برای استفادهٔ پایدار ضروری‌اند. کار را با معیارهای اصلی CPU، حافظه، دیسک و شبکه شروع کنید. پس از شناخت رفتار عادی سرورها، هشدارها و exporterهای بیشتر را مرحله‌به‌مرحله اضافه کنید. این رویکرد هم عیب‌یابی را ساده‌تر می‌کند و هم مانع تبدیل سامانهٔ هشدار به مجموعه‌ای از اعلان‌های بی‌استفاده می‌شود.

معیارها فقط نیمی از تصویر مانیتورینگ را نشان می‌دهند؛ برای بررسی علت دقیق یک خطا معمولاً به لاگ هم نیاز دارید. در این باره راه‌اندازی سیستم لاگ متمرکز با Grafana Loki و Alloy را بخوانید.