Deploy an hourly systemd timer that writes pool and dataset capacity to node_exporter's textfile collector, since --collector.zfs exposes only ARC/I-O/state. Add a provisioned 'ZFS - Pools & Datasets' dashboard with per-pool totals, per-dataset used/quota and daily growth panels.
Grafana Role
Installs and configures Grafana as a system service with PostgreSQL backend.
Description
This role:
- Installs Grafana from official repositories (Arch Linux or Debian/Ubuntu)
- Creates a dedicated PostgreSQL database and user
- Configures Grafana to use PostgreSQL
- Optionally configures Nginx reverse proxy
- Follows the shared services pattern
Dependencies
postgresrole (for database backend)
Variables
Required Variables (Override with Ansible Vault!)
grafana_db_password: changeme
grafana_admin_password: changeme
grafana_secret_key: changeme
Server Configuration
grafana_http_port: 3000
grafana_domain: localhost
grafana_root_url: "%(protocol)s://%(domain)s:%(http_port)s/"
Database Configuration
grafana_db_type: postgres
grafana_db_name: grafana
grafana_db_user: grafana_user
grafana_db_host: localhost
grafana_db_port: 5432
grafana_db_ssl_mode: disable
Admin User
grafana_admin_user: admin
Analytics
grafana_reporting_enabled: false
grafana_check_for_updates: false
Nginx Reverse Proxy
grafana_nginx_enabled: false
grafana_nginx_hostname: grafana.local
Example Playbook
---
- hosts: monitoring
roles:
- role: grafana
vars:
grafana_domain: monitoring.example.com
grafana_nginx_enabled: true
grafana_nginx_hostname: grafana.example.com
grafana_admin_password: !vault |
$ANSIBLE_VAULT;1.1;AES256
...
grafana_db_password: !vault |
$ANSIBLE_VAULT;1.1;AES256
...
grafana_secret_key: !vault |
$ANSIBLE_VAULT;1.1;AES256
...
Architecture
Database Isolation
Grafana gets its own PostgreSQL database with a dedicated user that has minimal privileges:
CREATE DATABASE grafana;
CREATE USER grafana_user WITH PASSWORD 'xxx';
GRANT ALL PRIVILEGES ON DATABASE grafana TO grafana_user;
ALTER USER grafana_user NOSUPERUSER NOCREATEDB NOCREATEROLE;
Service Layout
System Services:
├── PostgreSQL (port 5432, localhost only)
│ └── grafana database → grafana_user
└── Grafana (port 3000, localhost only)
└── Nginx (port 80) → reverse proxy (optional)
Post-Installation
Access Grafana
Direct access:
http://localhost:3000
With Nginx reverse proxy:
http://grafana.local
Default Credentials
- Username:
admin(or value ofgrafana_admin_user) - Password: Value of
grafana_admin_password
Important: Change the admin password immediately after first login!
Verify Installation
# Check service status
systemctl status grafana-server # Debian/Ubuntu
systemctl status grafana # Arch Linux
# Check database connection
sudo -u postgres psql -c "\l" | grep grafana
sudo -u postgres psql -c "\du" | grep grafana
# Check configuration
sudo cat /etc/grafana/grafana.ini | grep -A 5 "\[database\]"
# Check logs
journalctl -u grafana-server -f # Debian/Ubuntu
journalctl -u grafana -f # Arch Linux
Security Considerations
- Passwords: Always use Ansible Vault for sensitive variables
- Database: Grafana user has minimal privileges (no superuser, can't create databases/roles)
- Network: Grafana binds to localhost by default, use Nginx for external access
- Secret Key: Used for signing cookies and other security features - keep it secret!
Nginx Integration
When grafana_nginx_enabled: true, the role:
- Deploys an Nginx vhost configuration to
/etc/nginx/conf.d/grafana.conf - Configures reverse proxy with WebSocket support for live updates
- Reloads Nginx gracefully
When disabled, the vhost configuration is removed.
OS Support
- Arch Linux: Installs from community repository
- Debian/Ubuntu: Installs from official Grafana APT repository
Troubleshooting
Grafana won't start
# Check logs
journalctl -u grafana-server -n 50 # Debian/Ubuntu
journalctl -u grafana -n 50 # Arch Linux
# Check configuration syntax
sudo grafana-cli admin validate-config
Can't connect to PostgreSQL
# Verify PostgreSQL is running
systemctl status postgresql
# Test database connection
psql -h localhost -U grafana_user -d grafana
# Check PostgreSQL logs
journalctl -u postgresql -n 50
502 Bad Gateway with Nginx
# Verify Grafana is running
systemctl status grafana-server
# Check if Grafana is listening
ss -tlnp | grep 3000
# Test direct access
curl http://localhost:3000