igozhang

——

    Grafana + Zabbix 6.2.6 部署指南

    Ubuntu 20.04 / 22.04 · x86_64 · 非 root(sudo)· 超时 10s · 仅系统自带命令


    0. 变量(执行前修改)

    export ZABBIX_HOST="zabbix.igozhang.cn"
    export ZABBIX_PORT="80"
    export ZABBIX_SCHEME="http"                               # http or https
    export ZABBIX_API_PATH="/api_jsonrpc.php"                 # or /zabbix/api_jsonrpc.php
    export GRAFANA_ADMIN_PASS="ChangeMe_StrongPass"
    export GRAFANA_HTTP_PORT="3000"
    export NGINX_BIZ_IP=""                                    # empty=auto detect biz IPv4
    export NGINX_DOMAIN="grafana.igozhang.cn"
    export NGINX_SSL_CERT="/data/nginx/ssl/tls.pem"
    export NGINX_SSL_KEY="/data/nginx/ssl/tls.key"
    
    变量 说明 默认
    ZABBIX_HOST Zabbix 服务器 IP/域名 zabbix.igozhang.cn
    ZABBIX_PORT Zabbix Web 端口 80
    ZABBIX_SCHEME 协议 http
    ZABBIX_API_PATH API 路径 /api_jsonrpc.php
    GRAFANA_ADMIN_PASS Grafana admin 密码 无,必填
    GRAFANA_HTTP_PORT Grafana 监听端口 3000
    NGINX_BIZ_IP Nginx 绑定业务 IPv4 空=自动取默认路由 src
    NGINX_DOMAIN 对外域名 grafana.igozhang.cn
    NGINX_SSL_CERT TLS 证书 /data/nginx/ssl/tls.pem
    NGINX_SSL_KEY TLS 私钥 /data/nginx/ssl/tls.key

    1. 预检(并行,只读)

    检测 OS、磁盘、内存、网络,不改动系统。

    sudo ZABBIX_HOST="${ZABBIX_HOST:-zabbix.igozhang.cn}" ZABBIX_PORT="${ZABBIX_PORT:-80}" \
      ZABBIX_SCHEME="${ZABBIX_SCHEME:-http}" \
      ZABBIX_API_PATH="${ZABBIX_API_PATH:-/api_jsonrpc.php}" \
      GRAFANA_HTTP_PORT="${GRAFANA_HTTP_PORT:-3000}" bash <<'EOF'
    set -euo pipefail
    export ZABBIX_HOST ZABBIX_PORT ZABBIX_SCHEME ZABBIX_API_PATH GRAFANA_HTTP_PORT
    ZABBIX_API_URL="${ZABBIX_SCHEME}://${ZABBIX_HOST}:${ZABBIX_PORT}${ZABBIX_API_PATH}"
    echo "=== Preflight Start ==="
    run_check(){ local n="$1"; shift; local o
      if o=$(timeout 10 bash -c "$*" 2>&1); then printf '[OK]   %s\n%s\n\n' "$n" "$o"
      else printf '[FAIL] %s\n%s\n\n' "$n" "$o"; fi; }
    run_check "OS Release" \
      '. /etc/os-release; echo "ID=${ID} VERSION=${VERSION_ID} CODENAME=${VERSION_CODENAME}"'
    run_check "CPU Arch" 'echo "arch=$(uname -m) cores=$(nproc)"'
    run_check "Memory" 'free -h|awk "/^Mem:/{print \"total=\"\$2\" used=\"\$3\" avail=\"\$7}"'
    run_check "Disk / and /data" 'df -hT / /data 2>/dev/null|awk "NR==1||/\\//||/\\/data/"'
    run_check "Grafana Port ${GRAFANA_HTTP_PORT}" \
      "ss -tln|awk '/:${GRAFANA_HTTP_PORT} /{print \"LISTEN :${GRAFANA_HTTP_PORT}\"}'||echo 'port free'"
    ( run_check "Zabbix API ${ZABBIX_API_URL}" \
      "r=\$(curl -sS -m 10 -X POST '${ZABBIX_API_URL}' \
         -H 'Content-Type: application/json-rpc' \
         -d '{\"jsonrpc\":\"2.0\",\"method\":\"apiinfo.version\",\"params\":[],\"id\":1}'); \
       echo \"\$r\"; echo \"\$r\"|grep -q '\"jsonrpc\"'&&echo \"\$r\"|grep -q '\"result\"'" ) &
    ( run_check "DNS / Route" \
      "ip -4 route show default; echo; ip -4 addr show scope global|awk '/inet/{print \$2}'" ) &
    wait
    echo "=== Preflight Done ==="
    EOF
    

    返回 File not found. 表示 API 路径错误(404),不是网络不通。用下方命令探测正确路径:

    sudo ZABBIX_HOST="${ZABBIX_HOST:-zabbix.igozhang.cn}" ZABBIX_PORT="${ZABBIX_PORT:-80}" \
      ZABBIX_SCHEME="${ZABBIX_SCHEME:-http}" bash <<'EOF'
    set -euo pipefail
    export ZABBIX_HOST ZABBIX_PORT ZABBIX_SCHEME
    for p in /api_jsonrpc.php /zabbix/api_jsonrpc.php; do
      u="${ZABBIX_SCHEME}://${ZABBIX_HOST}:${ZABBIX_PORT}${p}"
      echo "=== try ${u} ==="
      r=$(timeout 10 curl -sS -m 10 -X POST "${u}" \
        -H 'Content-Type: application/json-rpc' \
        -d '{"jsonrpc":"2.0","method":"apiinfo.version","params":[],"id":1}'||true)
      echo "${r}"
      echo "${r}"|grep -q '"result"' && echo "[HIT] export ZABBIX_API_PATH=\"${p}\"" && echo
    done
    EOF
    

    常见情况:File not found → 改用 export ZABBIX_API_PATH="/api_jsonrpc.php"(Zabbix 6.x 根路径部署)后重跑预检。


    2. 安装 Grafana(官方 APT 源)

    整块复制执行;已安装则跳过。

    sudo bash <<'EOF'
    set -euo pipefail
    echo "=== Install Grafana Start ==="
    if command -v grafana-server >/dev/null 2>&1; then
      echo "[SKIP] grafana-server already installed"; grafana-server -v; echo
      echo "=== Install Grafana Done ==="; exit 0; fi
    export DEBIAN_FRONTEND=noninteractive
    apt-get update -qq
    apt-get install -y -qq apt-transport-https ca-certificates gnupg wget
    install -d -m 0755 /etc/apt/keyrings
    timeout 10 wget -qO- https://apt.grafana.com/gpg.key|gpg --dearmor>/etc/apt/keyrings/grafana.gpg
    cat>/etc/apt/sources.list.d/grafana.list<<'REPO'
    deb [signed-by=/etc/apt/keyrings/grafana.gpg] https://apt.grafana.com stable main
    REPO
    apt-get update -qq && apt-get install -y -qq grafana
    echo; grafana-server -v; echo
    echo "=== Install Grafana Done ==="
    EOF
    

    3. 数据目录与 grafana.ini

    将 data/logs/plugins 迁至 /data/grafana,首次自动备份原 ini。

    sudo GRAFANA_ADMIN_PASS="${GRAFANA_ADMIN_PASS:-ChangeMe_StrongPass}" \
      GRAFANA_HTTP_PORT="${GRAFANA_HTTP_PORT:-3000}" bash <<'EOF'
    set -euo pipefail
    export GRAFANA_ADMIN_PASS GRAFANA_HTTP_PORT
    echo "=== Configure Grafana Start ==="
    install -d -m 0755 /data/grafana/{data,logs,plugins}
    chown -R grafana:grafana /data/grafana
    [ ! -f /etc/grafana/grafana.ini.bak ] && cp -a /etc/grafana/grafana.ini /etc/grafana/grafana.ini.bak \
      && echo "[OK] backup -> /etc/grafana/grafana.ini.bak"
    python3 <<'PY'
    import os,re,pathlib
    p=os.environ.get("GRAFANA_HTTP_PORT","3000")
    w=os.environ.get("GRAFANA_ADMIN_PASS","ChangeMe_StrongPass")
    f=pathlib.Path("/etc/grafana/grafana.ini"); t=f.read_text()
    m={r"(?m)^;?\s*data\s*=.*$":"data = /data/grafana/data",
       r"(?m)^;?\s*logs\s*=.*$":"logs = /data/grafana/logs",
       r"(?m)^;?\s*plugins\s*=.*$":"plugins = /data/grafana/plugins",
       r"(?m)^;?\s*http_addr\s*=.*$":"http_addr = 0.0.0.0",
       r"(?m)^;?\s*http_port\s*=.*$":f"http_port = {p}",
       r"(?m)^;?\s*admin_password\s*=.*$":f"admin_password = {w}",
       r"(?m)^;?\s*allow_sign_up\s*=.*$":"allow_sign_up = false"}
    for k,v in m.items(): t=re.sub(k,v,t,count=1) if re.search(k,t) else t+f"\n{v}\n"
    f.write_text(t)
    PY
    echo
    grep -E '^(data|logs|plugins|http_addr|http_port|admin_password|allow_sign_up)\s*=' \
      /etc/grafana/grafana.ini|head -20
    echo; echo "=== Configure Grafana Done ==="
    EOF
    

    使用 Ubuntu 自带 python3 修改 ini,比 sed 更可靠。


    4. 安装 Zabbix 插件并启动服务

    先启动 Grafana,优先在 Web UI 安装 Zabbix 插件;UI 不可用或无外网时用命令行备选。

    4.1 启动 Grafana 服务

    sudo GRAFANA_HTTP_PORT="${GRAFANA_HTTP_PORT:-3000}" bash <<'EOF'
    set -euo pipefail
    export GRAFANA_HTTP_PORT
    echo "=== Service Start ==="
    systemctl daemon-reload && systemctl enable grafana-server && systemctl restart grafana-server
    timeout 10 bash -c "for i in \$(seq 1 10); do ss -tln|grep -q \":${GRAFANA_HTTP_PORT} \"&&exit 0;sleep 1;done;exit 1" \
      && echo "[OK] grafana-server listening on :${GRAFANA_HTTP_PORT}" \
      || echo "[WARN] port not ready within 10s, check: journalctl -u grafana-server -n 30"
    echo; systemctl is-active grafana-server; echo
    echo "Web UI: http://$(hostname -I|awk '{print $1}'):${GRAFANA_HTTP_PORT}"
    echo "=== Service Start Done ==="
    EOF
    

    4.2 Web UI 安装 Zabbix 插件(推荐)

    1. 浏览器打开 Grafana(步骤 4.1 输出的地址,或 https://grafana.igozhang.cn
    2. 使用 admin / GRAFANA_ADMIN_PASS 登录
    3. 左侧 ConnectionsAdd new connection
    4. 搜索 Zabbix,选择 Zabbix(作者 Alexander Zobnin)
    5. 点击 Install → 等待安装完成
    6. 若为 App 类型,进入插件页点击 Enable
    7. 确认状态为 Installed;左侧 ConnectionsData sources 中可见 Zabbix

    UI 安装需服务器能访问 Grafana 插件目录(grafana.com)。内网隔离环境请用下方 4.3 命令行。

    4.3 备选:命令行安装

    UI 失败或无外网时执行:

    sudo GRAFANA_HTTP_PORT="${GRAFANA_HTTP_PORT:-3000}" bash <<'EOF'
    set -euo pipefail
    export GRAFANA_HTTP_PORT
    echo "=== Plugin CLI Install ==="
    grafana-cli plugins install alexanderzobnin-zabbix-app 2>&1|tail -5; echo
    grafana-cli plugins ls|grep -i zabbix||true; echo
    systemctl restart grafana-server
    timeout 10 bash -c "for i in \$(seq 1 10); do ss -tln|grep -q \":${GRAFANA_HTTP_PORT} \"&&exit 0;sleep 1;done;exit 1" \
      && echo "[OK] grafana-server listening on :${GRAFANA_HTTP_PORT}" \
      || echo "[WARN] port not ready within 10s"
    echo "=== Plugin CLI Install Done ==="
    EOF
    

    5. 安装后验证(并行)

    sudo GRAFANA_HTTP_PORT="${GRAFANA_HTTP_PORT:-3000}" \
      GRAFANA_ADMIN_PASS="${GRAFANA_ADMIN_PASS:-ChangeMe_StrongPass}" bash <<'EOF'
    set -euo pipefail
    export GRAFANA_HTTP_PORT GRAFANA_ADMIN_PASS
    echo "=== Verify Start ==="
    run_check(){ local n="$1"; shift; local o
      if o=$(timeout 10 bash -c "$*" 2>&1); then printf '[OK]   %s\n%s\n\n' "$n" "$o"
      else printf '[FAIL] %s\n%s\n\n' "$n" "$o"; fi; }
    ( run_check "Service Status" \
      'systemctl is-active grafana-server;systemctl show grafana-server -p ActiveEnterTimestamp --value' ) &
    ( run_check "HTTP Health" \
      "curl -sS -m 10 -o /dev/null -w 'http_code=%{http_code} time=%{time_total}s' \
       http://127.0.0.1:${GRAFANA_HTTP_PORT}/api/health" ) &
    ( run_check "Disk Usage /data/grafana" 'du -sh /data/grafana 2>/dev/null;df -h /data|tail -1' ) &
    ( run_check "Recent Logs" 'journalctl -u grafana-server -n 5 --no-pager -o cat' ) &
    wait
    echo "=== Verify Done ==="; echo
    echo "Web UI: http://$(hostname -I|awk '{print $1}'):${GRAFANA_HTTP_PORT}"; echo
    echo "Login:  admin / ${GRAFANA_ADMIN_PASS}"
    EOF
    

    6. Nginx 反向代理(HTTPS)

    生成配置到 /etc/nginx/sites-enabled/,直接覆盖,不建目录、不备份。
    NGINX_BIZ_IP 留空则自动取默认路由业务口 IPv4。

    sudo NGINX_BIZ_IP="${NGINX_BIZ_IP:-}" NGINX_DOMAIN="${NGINX_DOMAIN:-grafana.igozhang.cn}" \
      NGINX_SSL_CERT="${NGINX_SSL_CERT:-/data/nginx/ssl/tls.pem}" \
      NGINX_SSL_KEY="${NGINX_SSL_KEY:-/data/nginx/ssl/tls.key}" \
      GRAFANA_HTTP_PORT="${GRAFANA_HTTP_PORT:-3000}" bash <<'EOF'
    set -euo pipefail
    export NGINX_BIZ_IP NGINX_DOMAIN NGINX_SSL_CERT NGINX_SSL_KEY GRAFANA_HTTP_PORT
    BIZ_IP="${NGINX_BIZ_IP:-$(ip -4 route get 1.1.1.1 2>/dev/null|awk '{for(i=1;i<=NF;i++)if($i=="src"){print $(i+1);exit}}')}"
    [ -n "${BIZ_IP}" ]||{ echo "[FAIL] NGINX_BIZ_IP empty and auto detect failed"; exit 1; }
    CONF="/etc/nginx/sites-enabled/${NGINX_DOMAIN}.conf"
    cat>"${CONF}"<<NGINX
    server {
        listen ${BIZ_IP}:80;
        server_name ${NGINX_DOMAIN};
        return 301 https://\$host\$request_uri;
    }
    server {
        listen ${BIZ_IP}:443 ssl;
        server_name ${NGINX_DOMAIN};
        ssl_certificate     ${NGINX_SSL_CERT};
        ssl_certificate_key ${NGINX_SSL_KEY};
        ssl_protocols       TLSv1.2 TLSv1.3;
        location / {
            proxy_pass http://127.0.0.1:${GRAFANA_HTTP_PORT};
            proxy_set_header Host              \$host;
            proxy_set_header X-Real-IP           \$remote_addr;
            proxy_set_header X-Forwarded-For     \$proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto   \$scheme;
            proxy_http_version 1.1;
            proxy_set_header Upgrade             \$http_upgrade;
            proxy_set_header Connection          "upgrade";
        }
    }
    NGINX
    echo "[OK] conf -> ${CONF}"
    echo "[OK] biz_ip=${BIZ_IP} domain=${NGINX_DOMAIN}"
    echo "[OK] url=https://${NGINX_DOMAIN}/"
    grep -E '^(listen|server_name|ssl_certificate)' "${CONF}"
    EOF
    

    写入后检测并重载:

    sudo nginx -t && sudo systemctl reload nginx
    

    同步 Grafana root_url(避免登录跳转异常):

    sudo NGINX_DOMAIN="${NGINX_DOMAIN:-grafana.igozhang.cn}" bash <<'EOF'
    set -euo pipefail
    export NGINX_DOMAIN
    python3 <<'PY'
    import os,re,pathlib
    d=os.environ.get("NGINX_DOMAIN","grafana.igozhang.cn")
    f=pathlib.Path("/etc/grafana/grafana.ini"); t=f.read_text()
    k=r"(?m)^;?\s*root_url\s*=.*$"; v=f"root_url = https://{d}/"
    t=re.sub(k,v,t,count=1) if re.search(k,t) else t+f"\n{v}\n"
    f.write_text(t); print(f"[OK] root_url = https://{d}/")
    PY
    systemctl restart grafana-server
    EOF
    

    DNS:NGINX_DOMAIN 需解析到 NGINX_BIZ_IP(或自动检测到的业务 IP)。


    7. 可选:UFW 放行端口

    仅当 UFW 处于 active 时执行。

    sudo GRAFANA_HTTP_PORT="${GRAFANA_HTTP_PORT:-3000}" bash <<'EOF'
    set -euo pipefail
    export GRAFANA_HTTP_PORT
    if ufw status 2>/dev/null|grep -q "Status: active"; then
      ufw allow "${GRAFANA_HTTP_PORT}/tcp" comment 'Grafana' >/dev/null
      ufw status numbered|grep -E "${GRAFANA_HTTP_PORT}|Status"; echo
      echo "[OK] ufw rule added"
    else echo "[SKIP] ufw not active"; fi
    EOF
    

    8. Web UI 配置 Zabbix 数据源

    字段
    类型 Zabbix
    URL ${ZABBIX_SCHEME}://${ZABBIX_HOST}:${ZABBIX_PORT}${ZABBIX_API_PATH}
    用户名 Zabbix 只读 API 用户
    密码 对应密码
    访问方式 Server

    路径:Connections → Data sources → Add → Zabbix → Save & test

    成功提示:Zabbix API version: 6.2.x


    9. Zabbix 侧前置条件(手动)

    在 Zabbix Web UI 创建用户 grafana_readonly

    • 角色:Zabbix User 或自定义只读角色
    • 主机组:对目标组授予 Read 权限
    • 非必要勿启用 Direct DB Connection

    10. 排错(按需执行)

    sudo ZABBIX_HOST="${ZABBIX_HOST:-zabbix.igozhang.cn}" ZABBIX_PORT="${ZABBIX_PORT:-80}" \
      ZABBIX_SCHEME="${ZABBIX_SCHEME:-http}" \
      ZABBIX_API_PATH="${ZABBIX_API_PATH:-/api_jsonrpc.php}" \
      GRAFANA_HTTP_PORT="${GRAFANA_HTTP_PORT:-3000}" bash <<'EOF'
    set -euo pipefail
    export ZABBIX_HOST ZABBIX_PORT ZABBIX_SCHEME ZABBIX_API_PATH GRAFANA_HTTP_PORT
    ZABBIX_API_URL="${ZABBIX_SCHEME}://${ZABBIX_HOST}:${ZABBIX_PORT}${ZABBIX_API_PATH}"
    echo "=== Troubleshoot ==="
    echo "[Service]"; systemctl status grafana-server --no-pager -l|head -15; echo
    echo "[Port]"; ss -tlnp|grep -E ':3000|:80'||true; echo
    echo "[API Health]"
    timeout 10 curl -sS -m 10 "http://127.0.0.1:${GRAFANA_HTTP_PORT}/api/health"||true; echo
    echo "[Zabbix API] ${ZABBIX_API_URL}"
    timeout 10 curl -sS -m 10 -X POST "${ZABBIX_API_URL}" \
      -H 'Content-Type: application/json-rpc' \
      -d '{"jsonrpc":"2.0","method":"apiinfo.version","params":[],"id":1}'||true; echo
    echo "[Last 20 log lines]"; journalctl -u grafana-server -n 20 --no-pager -o cat
    EOF
    

    版本对照

    组件 最低 推荐
    Grafana 10.4.8 11.x stable
    Zabbix 插件 4.3.1 latest 6.2.x
    Zabbix Server 6.2.6 6.2.6

    插件低于 4.3.1 可能因 Zabbix 6.2 API 变更(selectHostGroups)导致主机列表为空。


    完整流程

    1. 执行 步骤 0 设置变量
    2. 依次复制执行 步骤 1 → 2 → 3 → 4.1(启动 Grafana)
    3. 步骤 4.2 Web UI 安装 Zabbix 插件(推荐);失败时用 4.3 命令行
    4. 执行 步骤 5 验证
    5. 步骤 6 配置 Nginx HTTPS(按需);步骤 7 UFW 按需
    6. 步骤 8 Web UI 配置 Zabbix 数据源;步骤 9 Zabbix 侧前置
    7. 异常时执行 步骤 10

    MP3