Bài 5

Lab Docker

Đến lúc bắt tay thực hành. Bài này dựng một stack giám sát hoàn chỉnh bằng Docker Compose: Grafana để trực quan hoá, Prometheus để thu thập & lưu metrics, và Node Exporter để phát metrics của máy. Toàn bộ cấu hình dưới đây là thật, copy-paste chạy được ngay — kể cả phần provisioning để Grafana tự động có sẵn data source khi khởi động. Yêu cầu: đã cài Docker Desktop (hoặc Docker Engine) có Docker Compose v2.

Kiến trúc lab
Ai scrape ai, cổng nào ra cổng nào

Ba container chạy trên cùng một Docker network (Compose tự tạo). Trong network đó, mỗi service gọi nhau qua tên service (DNS nội bộ), còn ta truy cập từ máy host qua cổng đã publish:

ServiceImageCổng (host:container)Vai trò
Grafanagrafana/grafana3000:3000Giao diện web, dashboard. Query Prometheus.
Prometheusprom/prometheus9090:9090Thu thập & lưu metrics. Scrape node-exporter.
Node Exporterprom/node-exporter9100:9100Phát metrics phần cứng/OS (CPU, RAM, disk...).

Luồng dữ liệu đi theo hướng:

Điểm mấu chốt: Prometheus theo mô hình pull — nó chủ động đi kéo metrics, chứ không phải các service đẩy về. Vì thế trong prometheus.yml ta khai báo target là những địa chỉ Prometheus cần đến kéo.
Cấu trúc thư mục
Tổ chức file trước khi chạy

Tạo một thư mục grafana-lab với bố cục sau. Việc tách file provisioning giúp Grafana tự cấu hình khi khởi động, không cần bấm tay:

grafana-lab/ ├── docker-compose.yml ├── prometheus/ │ └── prometheus.yml └── grafana/ └── provisioning/ ├── datasources/ │ └── datasource.yml └── dashboards/ └── dashboard.yml

Tạo nhanh khung thư mục bằng lệnh (chạy trong thư mục cha):

# Linux / macOS / Git Bash
mkdir -p grafana-lab/prometheus
mkdir -p grafana-lab/grafana/provisioning/datasources
mkdir -p grafana-lab/grafana/provisioning/dashboards
# Windows PowerShell
New-Item -ItemType Directory -Force grafana-lab\prometheus
New-Item -ItemType Directory -Force grafana-lab\grafana\provisioning\datasources
New-Item -ItemType Directory -Force grafana-lab\grafana\provisioning\dashboards
docker-compose.yml
File điều phối chính

Đây là file trung tâm. Lưu vào grafana-lab/docker-compose.yml:

services:
  prometheus:
    image: prom/prometheus:latest
    container_name: prometheus
    restart: unless-stopped
    ports:
      - "9090:9090"
    volumes:
      - ./prometheus/prometheus.yml:/etc/prometheus/prometheus.yml:ro
      - prometheus-data:/prometheus
    command:
      - '--config.file=/etc/prometheus/prometheus.yml'
      - '--storage.tsdb.path=/prometheus'
      - '--web.enable-lifecycle'
    networks:
      - monitoring

  node-exporter:
    image: prom/node-exporter:latest
    container_name: node-exporter
    restart: unless-stopped
    ports:
      - "9100:9100"
    command:
      - '--path.rootfs=/host'
    volumes:
      - /:/host:ro,rslave
    networks:
      - monitoring

  grafana:
    image: grafana/grafana:latest
    container_name: grafana
    restart: unless-stopped
    ports:
      - "3000:3000"
    environment:
      - GF_SECURITY_ADMIN_USER=admin
      - GF_SECURITY_ADMIN_PASSWORD=admin
      - GF_USERS_ALLOW_SIGN_UP=false
    volumes:
      - grafana-storage:/var/lib/grafana
      - ./grafana/provisioning:/etc/grafana/provisioning:ro
    depends_on:
      - prometheus
    networks:
      - monitoring

volumes:
  prometheus-data:
  grafana-storage:

networks:
  monitoring:
    driver: bridge
Giải thích vài điểm: node-exporter mount /:/host:ro và dùng --path.rootfs=/host để đọc được metrics thật của máy host (không phải của container). --web.enable-lifecycle cho phép reload cấu hình Prometheus qua HTTP mà không cần restart. Hai volumes ở cuối giữ dữ liệu tồn tại qua các lần restart.
prometheus/prometheus.yml
Cấu hình scrape

Prometheus cần biết kéo metrics từ đâu và bao lâu một lần. Lưu vào grafana-lab/prometheus/prometheus.yml:

global:
  scrape_interval: 15s        # mặc định kéo mỗi 15 giây
  evaluation_interval: 15s    # đánh giá rule mỗi 15 giây

scrape_configs:
  # 1) Prometheus tự giám sát chính nó
  - job_name: 'prometheus'
    static_configs:
      - targets: ['localhost:9090']

  # 2) Node Exporter — gọi qua tên service trong Docker network
  - job_name: 'node-exporter'
    static_configs:
      - targets: ['node-exporter:9100']
Chú ý tên host: target là node-exporter:9100 chứ không phải localhost:9100. Trong container Prometheus, localhost là chính nó — nó phải gọi node-exporter qua tên service (DNS của Docker network). Đây là lỗi kinh điển của người mới.
Provisioning Grafana
Tự thêm data source & dashboard provider

Data source. Thay vì vào UI bấm tay, ta khai báo Prometheus bằng file YAML để Grafana tự nạp khi khởi động. Lưu vào grafana-lab/grafana/provisioning/datasources/datasource.yml:

apiVersion: 1

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

Chú ý urlhttp://prometheus:9090 — dùng tên service, vì Grafana container gọi Prometheus container qua DNS nội bộ của Docker network, không phải qua localhost của máy host.

Dashboard provider. File này bảo Grafana quét một thư mục và tự nạp mọi file dashboard .json trong đó. Lưu vào grafana-lab/grafana/provisioning/dashboards/dashboard.yml:

apiVersion: 1

providers:
  - name: 'default'
    orgId: 1
    folder: ''
    type: file
    disableDeletion: false
    updateIntervalSeconds: 30
    allowUiUpdates: true
    options:
      path: /etc/grafana/provisioning/dashboards
Nạp dashboard bằng file: nếu muốn có sẵn dashboard, tải file JSON (vd Node Exporter Full) và đặt vào grafana/provisioning/dashboards/ — Grafana sẽ tự import theo provider trên. Ở lab này ta sẽ import qua UI cho trực quan (mục tiếp theo), cách nào cũng được.
Các bước chạy
Từ khởi động tới dashboard đầu tiên
Dashboard 1860 ("Node Exporter Full") là dashboard cộng đồng phổ biến nhất cho node-exporter — hàng trăm panel dựng sẵn. Đây là cách nhanh nhất để thấy dữ liệu mà không phải tự vẽ panel nào.
Biến môi trường & lưu dữ liệu
Tuỳ chỉnh Grafana qua env vars

Grafana cấu hình rất tốt qua biến môi trường, theo quy tắc GF_<SECTION>_<KEY>. Vài biến hữu ích:

BiếnTác dụng
GF_SECURITY_ADMIN_PASSWORDĐặt mật khẩu admin ban đầu (thay cho admin mặc định).
GF_SECURITY_ADMIN_USERĐổi tên tài khoản admin.
GF_USERS_ALLOW_SIGN_UPfalse để tắt tự đăng ký tài khoản.
GF_AUTH_ANONYMOUS_ENABLEDtrue để cho xem dashboard mà không cần đăng nhập.
GF_AUTH_ANONYMOUS_ORG_ROLEQuyền của khách ẩn danh: Viewer (chỉ xem) là an toàn nhất.
Anonymous access. Muốn cho cả team xem dashboard không cần login (vd màn hình TV chung), thêm vào environment của service grafana:
- GF_AUTH_ANONYMOUS_ENABLED=true
- GF_AUTH_ANONYMOUS_ORG_ROLE=Viewer
Persist dữ liệu. Volume grafana-storage mount vào /var/lib/grafana giữ lại toàn bộ user, dashboard tự tạo, cấu hình... qua các lần restart. Nếu không khai báo volume này, mọi thứ tạo qua UI sẽ mất khi container bị xoá. Tương tự, prometheus-data giữ lịch sử metrics của Prometheus.

Dừng và dọn dẹp lab:

# Dừng nhưng GIỮ dữ liệu (volume còn nguyên)
docker compose down

# Dừng và XOÁ luôn dữ liệu (volume bị xoá)
docker compose down -v
Troubleshooting
Các lỗi thường gặp
Data source "Bad Gateway" / không kết nối được Prometheus. Gần như luôn do dùng sai host: bạn khai http://localhost:9090 thay vì http://prometheus:9090. Trong container Grafana, localhost trỏ về chính Grafana, không phải máy host. Phải dùng tên service Docker (prometheus). Sửa lại datasource.yml hoặc ô URL trong UI.
Port đã bị chiếm ("port is already allocated"). Có tiến trình khác đang giữ cổng 3000/9090/9100 (Grafana cũ, một app khác...). Đổi cổng phía host trong compose, vd "3001:3000" rồi mở localhost:3001; hoặc tắt tiến trình đang chiếm cổng đó. Kiểm tra bằng docker ps hoặc netstat.

Vài lệnh chẩn đoán nhanh:

# Xem trạng thái các container
docker compose ps

# Xem log của một service (theo dõi realtime)
docker compose logs -f grafana
docker compose logs -f prometheus

# Vào trong container Prometheus để test kết nối tới node-exporter
docker compose exec prometheus wget -qO- http://node-exporter:9100/metrics | head
node-exporter target DOWN? Mở http://localhost:9090/targets. Nếu báo lỗi kết nối, kiểm tra: (1) target đúng là node-exporter:9100, (2) cả hai service cùng network monitoring, (3) container node-exporter đang Up (docker compose ps).
← Bài trước
Bài 4: Alerting