[Lab basics] Sử dụng Grafana để monitor SNMP stats
UML
Fake SNMP Exporter:
Được triển khai bằng Python Flask
Tạo ra dữ liệu giả lập SNMP
Prometheus:
Scrape (thu thập) metrics từ Fake SNMP Exporter
Lưu trữ dữ liệu time series
Grafana:
Query dữ liệu từ Prometheus
Tạo dashboard và hiển thị dữ liệu
User:
- Tương tác với Grafana để xem dashboard
Tất cả các thành phần này (ngoại trừ User) đều được triển khai trong môi trường Docker, cho phép quản lý và triển khai dễ dàng.
Luồng dữ liệu trong hệ thống như sau:
Fake SNMP Exporter tạo ra dữ liệu giả lập SNMP.
Prometheus định kỳ scrape metrics từ Fake SNMP Exporter.
Grafana query dữ liệu từ Prometheus để hiển thị trên dashboard.
User truy cập Grafana để xem dashboard và tương tác với dữ liệu.
Sản phẩm cuối cùng
Một số file code phục vụ lab
Sample này thực hiện trên Cloud9, có ip public là 54.179.190.190 và mở các sg rule như sau:
Các file trong thư mục:
docker-compose.yml
version: '3'
services:
grafana:
image: grafana/grafana
ports:
- "3000:3000"
volumes:
- grafana_data:/var/lib/grafana
prometheus:
image: prom/prometheus
ports:
- "9090:9090"
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml
fake-snmp-exporter:
build:
context: .
dockerfile: Dockerfile.fake-snmp
ports:
- "9116:9116"
volumes:
grafana_data:
Dockerfile.fake-snmp
FROM python:3.9-slim
WORKDIR /app
COPY fake_snmp_exporter.py requirements.txt ./
RUN pip install -r requirements.txt
CMD ["python", "fake_snmp_exporter.py"]
fake_snmp_exporter.py
import logging
logging.basicConfig(level=logging.DEBUG)
from flask import Flask, Response
import random
import time
app = Flask(__name__)
@app.route('/')
def home():
return "Fake SNMP Exporter is running. Access /metrics for SNMP data."
@app.route('/metrics')
def metrics():
timestamp = int(time.time())
metrics = f"""
# HELP sysUpTime The time (in seconds) since the network management portion of the system was last re-initialized.
# TYPE sysUpTime gauge
sysUpTime {timestamp - 1600000}
# HELP ifHCInOctets Fake SNMP data for incoming traffic
# TYPE ifHCInOctets counter
ifHCInOctets{{interface="eth0"}} {random.randint(1000000, 5000000)} {timestamp}000
ifHCInOctets{{interface="eth1"}} {random.randint(500000, 2000000)} {timestamp}000
# HELP ifHCOutOctets Fake SNMP data for outgoing traffic
# TYPE ifHCOutOctets counter
ifHCOutOctets{{interface="eth0"}} {random.randint(1000000, 5000000)} {timestamp}000
ifHCOutOctets{{interface="eth1"}} {random.randint(500000, 2000000)} {timestamp}000
# HELP ifHighSpeed Fake SNMP data for interface speed
# TYPE ifHighSpeed gauge
ifHighSpeed{{interface="eth0"}} {1000} {timestamp}000
ifHighSpeed{{interface="eth1"}} {1000} {timestamp}000
# HELP ifOperStatus Fake SNMP data for interface operational status
# TYPE ifOperStatus gauge
ifOperStatus{{interface="eth0"}} {1} {timestamp}000
ifOperStatus{{interface="eth1"}} {1} {timestamp}000
# HELP ifAdminStatus Fake SNMP data for interface administrative status
# TYPE ifAdminStatus gauge
ifAdminStatus{{interface="eth0"}} {1} {timestamp}000
ifAdminStatus{{interface="eth1"}} {1} {timestamp}000
"""
app.logger.debug(f"Generated metrics:\n{metrics}")
return Response(metrics, mimetype='text/plain')
if __name__ == '__main__':
app.logger.info("Starting Fake SNMP Exporter on 0.0.0.0:9116")
app.run(host='0.0.0.0', port=9116, debug=True)
prometheus.yml
global:
scrape_interval: 15s
scrape_configs:
- job_name: 'fake_snmp'
static_configs:
- targets: ['fake-snmp-exporter:9116']
requirements.txt
Flask==2.0.1
Werkzeug==2.0.1
snmp.yml
if_mib:
walk:
- 1.3.6.1.2.1.2
- 1.3.6.1.2.1.31.1.1
metrics:
- name: ifHighSpeed
oid: 1.3.6.1.2.1.31.1.1.1.15
type: gauge
- name: ifHCInOctets
oid: 1.3.6.1.2.1.31.1.1.1.6
type: counter
- name: ifHCOutOctets
oid: 1.3.6.1.2.1.31.1.1.1.10
type: counter
Một số câu lệnh:
docker-compose down # (if dockercompse is running, use this before up if you update code and rerun)
docker-compose up -d --build
# Check process:
docker-compose ps
# Check log:
docker-compose logs fake-snmp-exporter
Kết quả lệnh:
AWSReservedSSO_AWSAdministratorAccess_4288b0790c6df772:~/environment/0-grafanatest/snmp_grafana_lab $ docker-compose up -d --build
Creating network "snmp_grafana_lab_default" with the default driver
WARNING: Found orphan containers (snmp_grafana_lab_snmp-exporter_1) for this project. If you removed or renamed this service in your compose file, you can run this command with the --remove-orphans flag to clean it up.
Building fake-snmp-exporter
[+] Building 0.9s (9/9) FINISHED docker:default
=> [internal] load build definition from Dockerfile.fake-snmp 0.0s
=> => transferring dockerfile: 264B 0.0s
=> [internal] load metadata for docker.io/library/python:3.9-slim 0.8s
=> [internal] load .dockerignore 0.0s
=> => transferring context: 2B 0.0s
=> [1/4] FROM docker.io/library/python:3.9-slim@sha256:2851c06da1fdc3c451784beef8aa31d1a313d8e3fc122e4a1891085a104b7cfb 0.0s
=> [internal] load build context 0.0s
=> => transferring context: 196B 0.0s
=> CACHED [2/4] WORKDIR /app 0.0s
=> CACHED [3/4] COPY fake_snmp_exporter.py requirements.txt ./ 0.0s
=> CACHED [4/4] RUN pip install -r requirements.txt 0.0s
=> exporting to image 0.0s
=> => exporting layers 0.0s
=> => writing image sha256:b1136651f4271b6d235f9ca88c971e2995d1ef2c5c214063db6b90d0755f947d 0.0s
=> => naming to docker.io/library/snmp_grafana_lab_fake-snmp-exporter 0.0s
Creating snmp_grafana_lab_prometheus_1 ... done
Creating snmp_grafana_lab_grafana_1 ... done
Creating snmp_grafana_lab_fake-snmp-exporter_1 ... done
AWSReservedSSO_AWSAdministratorAccess_4288b0790c6df772:~/environment/0-grafanatest/snmp_grafana_lab $ docker-compose ps
Name Command State Ports
-------------------------------------------------------------------------------------------------------------------------
snmp_grafana_lab_fake-snmp-exporter_1 python fake_snmp_exporter.py Up 0.0.0.0:9116->9116/tcp,:::9116->9116/tcp
snmp_grafana_lab_grafana_1 /run.sh Up 0.0.0.0:3000->3000/tcp,:::3000->3000/tcp
snmp_grafana_lab_prometheus_1 /bin/prometheus --config.f ... Up 0.0.0.0:9090->9090/tcp,:::9090->9090/tcp
AWSReservedSSO_AWSAdministratorAccess_4288b0790c6df772:~/environment/0-grafanatest/snmp_grafana_lab $ docker-compose logs fake-snmp-exporter
Attaching to snmp_grafana_lab_fake-snmp-exporter_1
fake-snmp-exporter_1 | INFO:fake_snmp_exporter:Starting Fake SNMP Exporter on 0.0.0.0:9116
fake-snmp-exporter_1 | * Serving Flask app 'fake_snmp_exporter' (lazy loading)
fake-snmp-exporter_1 | * Environment: production
fake-snmp-exporter_1 | WARNING: This is a development server. Do not use it in a production deployment.
fake-snmp-exporter_1 | Use a production WSGI server instead.
fake-snmp-exporter_1 | * Debug mode: on
fake-snmp-exporter_1 | WARNING:werkzeug: * Running on all addresses.
fake-snmp-exporter_1 | WARNING: This is a development server. Do not use it in a production deployment.
fake-snmp-exporter_1 | INFO:werkzeug: * Running on http://172.26.0.4:9116/ (Press CTRL+C to quit)
fake-snmp-exporter_1 | INFO:werkzeug: * Restarting with stat
fake-snmp-exporter_1 | INFO:fake_snmp_exporter:Starting Fake SNMP Exporter on 0.0.0.0:9116
fake-snmp-exporter_1 | WARNING:werkzeug: * Debugger is active!
fake-snmp-exporter_1 | INFO:werkzeug: * Debugger PIN: 413-678-369
fake-snmp-exporter_1 | DEBUG:fake_snmp_exporter:Generated metrics:
fake-snmp-exporter_1 |
fake-snmp-exporter_1 | # HELP sysUpTime The time (in seconds) since the network management portion of the system was last re-initialized.
fake-snmp-exporter_1 | # TYPE sysUpTime gauge
fake-snmp-exporter_1 | sysUpTime 1725598691
fake-snmp-exporter_1 |
fake-snmp-exporter_1 | # HELP ifHCInOctets Fake SNMP data for incoming traffic
fake-snmp-exporter_1 | # TYPE ifHCInOctets counter
fake-snmp-exporter_1 | ifHCInOctets{interface="eth0"} 1639329 1727198691000
fake-snmp-exporter_1 | ifHCInOctets{interface="eth1"} 1421752 1727198691000
fake-snmp-exporter_1 |
fake-snmp-exporter_1 | # HELP ifHCOutOctets Fake SNMP data for outgoing traffic
fake-snmp-exporter_1 | # TYPE ifHCOutOctets counter
fake-snmp-exporter_1 | ifHCOutOctets{interface="eth0"} 4246979 1727198691000
fake-snmp-exporter_1 | ifHCOutOctets{interface="eth1"} 1981217 1727198691000
fake-snmp-exporter_1 |
fake-snmp-exporter_1 | # HELP ifHighSpeed Fake SNMP data for interface speed
fake-snmp-exporter_1 | # TYPE ifHighSpeed gauge
fake-snmp-exporter_1 | ifHighSpeed{interface="eth0"} 1000 1727198691000
fake-snmp-exporter_1 | ifHighSpeed{interface="eth1"} 1000 1727198691000
fake-snmp-exporter_1 |
fake-snmp-exporter_1 | # HELP ifOperStatus Fake SNMP data for interface operational status
fake-snmp-exporter_1 | # TYPE ifOperStatus gauge
fake-snmp-exporter_1 | ifOperStatus{interface="eth0"} 1 1727198691000
fake-snmp-exporter_1 | ifOperStatus{interface="eth1"} 1 1727198691000
fake-snmp-exporter_1 |
fake-snmp-exporter_1 | # HELP ifAdminStatus Fake SNMP data for interface administrative status
fake-snmp-exporter_1 | # TYPE ifAdminStatus gauge
fake-snmp-exporter_1 | ifAdminStatus{interface="eth0"} 1 1727198691000
fake-snmp-exporter_1 | ifAdminStatus{interface="eth1"} 1 1727198691000
fake-snmp-exporter_1 |
fake-snmp-exporter_1 | INFO:werkzeug:172.26.0.3 - - [24/Sep/2024 17:24:51] "GET /metrics HTTP/1.1" 200 -
AWSReservedSSO_AWSAdministratorAccess_4288b0790c6df772:~/environment/0-grafanatest/snmp_grafana_lab $
Thử truy cập các endpoints:
http://54.179.190.190:9116/metrics (fake SNMP exporter)
http://54.179.190.190:9090 (Prometheus)
http://54.179.190.190:3000 (Grafana)
Lần đầu tiên truy cập Grafana thì username và password mặc định sẽ là admin/admin, sau khi đăng nhập thì sẽ phải đổi password.
Setup Grafana
Tải JSON của dashboard này: grafana.com/grafana/dashboards/11169-snmp-s..
Data source
Gõ vào thanh “Search or jump” của Grafana: Data Sources
Chọn "Add data source"
Chọn Prometheus
Lưu và test
Tiếp tục gõ thanh search: Import
Lúc này ở Dashboard sẽ có dữ liệu như sau
Note: để app chạy thêm một lúc nữa thì có thể thêm sẽ thêm metrics, tuy nhiên hãy click vào Visualization để ta thực hiện query
Query và add Visualization
Các OID cơ bản đã được map với tên metric trong fake SNMP exporter của chúng ta. Ví dụ:
ifHCInOctets: Đại diện cho OID 1.3.6.1.2.1.31.1.1.1.6
ifHCOutOctets: Đại diện cho OID 1.3.6.1.2.1.31.1.1.1.10
ifHighSpeed: Đại diện cho OID 1.3.6.1.2.1.31.1.1.1.15
sysUpTime: Đại diện cho OID 1.3.6.1.2.1.1.3
Để query một OID, bạn có thể sử dụng tên metric tương ứng. Ví dụ:
Để query incoming traffic:
rate(ifHCInOctets{job="fake_snmp"}[5m])
Để query outgoing traffic:
rate(ifHCOutOctets{job="fake_snmp"}[5m])
Để query uptime:
sysUpTime{job="fake_snmp"}
Nếu bạn muốn thêm các OID mới:
Bạn cần cập nhật file
fake_snmp_exporter.py
để thêm các OID mớiSau đó, rebuild và restart container fake-snmp-exporter
Cuối cùng, bạn có thể query các OID mới này trong Grafana bằng cách sử dụng tên metric bạn đã định nghĩa
Để xem danh sách đầy đủ các metric có sẵn:
Truy cập Prometheus UI (thường là http://[your-ip]:9090)
Vào tab "Graph"
Trong ô "Expression", bắt đầu gõ và bạn sẽ thấy gợi ý các metric có sẵn
Giả sử tôi query và add metrics:
Sau khi click vào Add > Visualization sẽ ra như sau:
Nên chọn Code thay vì Builder để dễ dùng hơn, Builder dù trực quan hơn nhưng có 1 số phần sẽ limit hơn
Giả sử query uptime: Để query uptime: sysUpTime{job="fake_snmp"}
Nếu thấy đã OK thì sẽ nhấn apply để add vào Dashboard, có thể sắp xếp lại dashboard cho đẹp mắt tương tự như Dashboard của AWS CloudWatch
Chi tiết hơn về cú pháp query: https://grafana.com/docs/grafana/latest/panels-visualizations/query-transform-data/
Gợi ý troubleshooting
Các điểm đánh dấu đỏ trên hình ảnh sau là các điểm cần quan tâm khi troubleshooting:
Scrape metrics (Fake SNMP Exporter -> Prometheus):
Kiểm tra cấu hình Prometheus (prometheus.yml): Đảm bảo job scrape đúng địa chỉ của Fake SNMP Exporter.
Kiểm tra logs của Prometheus:
docker-compose logs prometheus
Tìm các lỗi liên quan đến việc scrape data.Truy cập Prometheus UI (thường là http://[your-ip]:9090/targets): Xem trạng thái của target Fake SNMP Exporter.
Kiểm tra Fake SNMP Exporter có chạy không:
docker-compose psdocker-compose logs fake-snmp-exporter
Query data (Prometheus -> Grafana):
Kiểm tra cấu hình Data Source trong Grafana: Đảm bảo URL Prometheus chính xác.
Test connection trong Grafana Data Source settings.
Kiểm tra Query trong Grafana panel: Đảm bảo syntax đúng và metric tồn tại trong Prometheus.
Thử query trực tiếp trong Prometheus UI để xác nhận dữ liệu tồn tại.
View dashboard (Grafana -> User):
Kiểm tra Grafana có chạy không:
docker-compose ps
Xem logs của Grafana:
docker-compose logs grafana
Kiểm tra kết nối mạng: Đảm bảo port Grafana (thường là 3000) được mở và có thể truy cập từ bên ngoài.
Kiểm tra quyền truy cập: Đảm bảo user có quyền xem dashboard.
Các bước tổng quát để troubleshoot:
Kiểm tra trạng thái các container:
docker-compose ps
Xem logs của từng service:
docker-compose logs [service-name]
Kiểm tra kết nối mạng giữa các container:
docker network inspect [network-name]
Verify cấu hình của từng service (prometheus.yml, grafana.ini, etc.)
Kiểm tra firewall và security group của EC2 instance (nếu có)