Featured image of post Zabbix的一些筆記

Zabbix的一些筆記

人生中總是有許多無奈,被迫去學的Zabbix筆記

參考網址:監控大挑戰 - 以 Zabbix 為例

為什麼選擇Zabbix?

目前常見的監控軟體有三者

  1. Zabbix
  2. Cacti
  3. Nagios

NagiOs的介面

image-20230317110443666

Cacti的介面

image-20230317110544016

Zabbix的介面

image-20230317110906297

監控產品ZabbixNagiosCacti
圖形介面好看不是特別好還行
監控性能併發監控,對CPU要求較高併發監控,對CPU要求較高輪詢監控,效能低
配置難度較低,有圖形化介面使用需使用CommandLine需使用CommandLine
自動發現支持不支持不支持
異常通知方式Email,簡訊,webhook,Line…Email,簡訊,webhook,Line…較弱,預設只支援Email

Zabbix是什麼

Zabbix是一種開源的網絡監視和警報系統,用於監視各種網絡設備,包括服務器、網絡設備和應用程序等。Zabbix提供了一個可擴展的架構,可用於監視多個位置的數千個設備。

Zabbix支持各種監視方式,包括SNMP、JMX、IPMI和VMware監視,還可以通過自定義監視腳本進行擴展。Zabbix還提供了一個強大的報警系統,可以通過電子郵件、SMS和其他方式發送警報,以便快速解決問題。

Zabbix還提供了一個用戶友好的Web界面,可以輕鬆設置監視器和警報。Zabbix的開源設計使其成為一個非常有用的監視解決方案,可以滿足各種規模的企業和組織的需求

image-20230313142828806

Zabbix術語

Zabbix Server

  • Zabbix server是agent程序報告系統可用性、系統完整性和統計數據的核心組件,是所有配置訊息、統計訊息和操作數據的核心儲存器

Zabbix資料庫存取

  • 所有配置訊息和Zabbix收集到的數據都被儲存在資料庫中

Zabbix Web介面

  • 為了從任何地方和任何平台都可以輕鬆地訪問Zabbix,我們提供基於Web的Zabbix介面,該介面是Zabbix Server的一部分,通常(但不一定)跟Zabbix Server運行在同一台物理主機上

Zabbix Proxy 代理服務器

  • Zabbix Proxy可以替Zabbix Server收集性能和可用性數據。Proxy代理服務器是Zabbix軟體可選擇部屬的一部分,當然,Proxy代理服務器可以幫助單台Zabbix Server分擔負載壓力

Zabbix Agent 監控代理

  • Zabbix agent 監控代理,部屬在監控目標上,能夠主動間空本地資源和應用程序,並將收集到的數據報告給Zabbix Server

Zabbix數據流

  • 監控方面,為了創造一個監控項(item)用於採集數據,必須先創建一個主機(host)
  • 告警方面,在監控項裡面創造觸發器(trigger),通過觸發器(trigger)來觸發告警動作(action)。因此如果你想收到Server XCPU負載過高的告警,必須滿足
  1. 為Server X創建一個Host並關聯一個用對CPU進行監控的監控項(item)
  2. 創建一個Trigger,設置成當CPU負載過高時會觸發
  3. Trigger被觸發,發送告警郵件

雖然看起來有很多步驟,但是使用模板的話操作起來其實非常簡單,Zabbix這樣的設計使得配置機制非常靈活易用

主機(Host)

  • 一台你想監控的網路設備,用IP和域名表示

主機組(host Group)

  • 主機的邏輯組;包含了主機和模板。一個主機裡的主機和模板之間並沒有任何直接的關聯,通常在給不同用戶組的主機分配權限時,使用主機組

監控項(item)

  • 你想要接收的主機的特定數據,一個度量數據

觸發器(Trigger)

  • 一個被用於定義問題閾值和"評估"監控項接受到的數據的邏輯表達式,當接收到的數據高於閾值時,觸發器從OK變成Problem狀態。當接收到的數據低於閾值時,觸發器保留/返回一個OK的狀態

事件(Event)

  • 單次發生的需要注意的事情,例如觸發器狀態改變,或是發現有監控代理自動註冊

異常(Problem)

  • 一個處在異常狀態的觸發器

動作(Action)

  • 一個對事件做出反應的預定義的操作
  • 一個動作由操作(例如發出通知)和條件(當時操作正在發生)組成

升級(Escalation)

  • 一個在動作內執行操作的自定義場景;發生通知/執行遠程命令的序列

媒介(Media)

  • 發送告警通知的手段;告警通知的途徑

通知(Notification)

  • 利用已選擇的媒體途徑把跟事件相關的訊息發送給用戶

遠程命令(remote command)

  • 一個預定義好的,滿足一些條件的情況下,可以在被監控主機上自動執行的命令

模板(template)

  • 一組可以被應用到一個或多個主機上的實體(監控項、觸發器、圖形、聚合圖形、應用、LLD、Web場景)的集合
  • 模板的任務就是加快對主機監控任務的實施;也可以使監控任務的批量修改更簡單。模板是直接關連到每台單獨的主機上

應用(Application)

  • 一組監控項組成的邏輯分組

Web場景(Web Scenario)

  • 利用一個或多個HTTP請求來檢查網站的可用性

前端(FrontEnd)

  • Zabbix提供的Web介面

Zabbix API

  • Zabbix API允許你使用JSON RPC協議(是一個無狀態且輕量級的遠程過程調用Remote Procedure Call 傳送協議,其傳遞內容透過JSON為主)來創建、更新和獲取Zabbix對象(如主機、監控項、圖形和其他)信息或者執行任何其他的字定義的任務

Zabbix Server

  • Zabbix軟件實現監控的核心程序,主要功能是與Zabbix proxies和Agents進行交互、觸發器計算、發送告警通知、並將資料集中保存

Zabbix Agent

  • 一個部屬在監控對象上的,能夠主動監控本地資源和應用的程序
  • Zabbix Agent部屬在監控的目標上,主動監測本地的資源和應用(硬體驅動、記憶體、處理器統計等等)
  • Zabbix Agent收集本地的操作訊息並將資料報告給Zabbix Server用於進一步處理。一旦出現異常(比如硬碟空間已滿或者有崩潰的服務器Process),Zabbix Server會主動警告管理員指定機器上的異常。Zabbix Agents的極端高校源於他可以利用本地系統調用來完成統計數據的收集

被動(Passive) 和 主動(Active)檢查

  • Zabbix Agent可以執行被動和主動兩種檢查方式
  1. 被動檢查(Passive Check)模式中Agent應答數據請求,Zabbix Server(或者Proxy)詢問Agent資料,如CPU負仔狀況,然後Zabbix Agent回傳結果
  2. 主動檢查(Active Checks) 處理過程將相對複雜。Agent必須首先從Zabbix server索取監控項列表以進行獨立處理,然後週期性的發送新的值給Server

執行被動或主動檢查是通過選擇相應的監測項目類型來配置的。Item Type. Zabbix Agent處理監控項類型有Zabbix agent和 Zabbix Agent(Active)

Zabbix Proxy

  • 一個幫助Zabbix server收集數據,分擔Zabbix Server負擔的程式
  • Zabbix Proxy是一個可以從一個或多個受監控設備收集監控數據,並將訊息結果發送到Zabbix Server的Process,基本上是代表Server工作的。所有收集的數據都在本地進行快取,然後傳送到Proxy所屬的Zabbix Server。
  • 部屬Proxy是可選的,但是可能會非常有益於分散單個Zabbix Sever的負載,如果只有Proxy收集數據,Server上的進程就會減少,CPU消耗和磁碟I/O負載
  • Zabbix Proxy是完成遠端區域,分支機構,沒有本地管理員的網路集中監控的理想解決方案
  • Zabbix Proxy需要使用獨立的資料庫

使用Docker安裝 Zabbix

首先先點到下列網站 https://www.zabbix.com/documentation/5.0/en/manual/installation/containers

並在這邊選擇要使用的版本

這次是使用官網提供的,也就是用mysql當database的版本

並按照下列的cmd指令輸入,下面的參數,若有需要變可以在自行修改

1
docker network create --subnet 172.20.0.0/16 --ip-range 172.20.240.0/20 zabbix-net

1
docker run --name postgres-server -t -e POSTGRES_USER="zabbix" -e POSTGRES_PASSWORD="zabbix_pwd" -e POSTGRES_DB="zabbix" --network=zabbix-net --restart unless-stopped -d postgres:latest

1
docker run --name zabbix-snmptraps -t -v /zbx_instance/snmptraps:/var/lib/zabbix/snmptraps:rw -v /var/lib/zabbix/mibs:/usr/share/snmp/mibs:ro --network=zabbix-net -p 162:1162/udp --restart unless-stopped -d zabbix/zabbix-snmptraps:alpine-5.0-latest

1
docker run --name zabbix-server-pgsql -t -e DB_SERVER_HOST="postgres-server" -e POSTGRES_USER="zabbix" -e POSTGRES_PASSWORD="zabbix_pwd" -e POSTGRES_DB="zabbix" -e ZBX_ENABLE_SNMP_TRAPS="true" --network=zabbix-net -p 10051:10051 --volumes-from zabbix-snmptraps  --restart unless-stopped -d zabbix/zabbix-server-pgsql:alpine-5.0-latest

1
docker run --name zabbix-web-nginx-pgsql -t -e ZBX_SERVER_HOST="zabbix-server-pgsql" -e DB_SERVER_HOST="postgres-server" -e POSTGRES_USER="zabbix" -e POSTGRES_PASSWORD="zabbix_pwd" -e POSTGRES_DB="zabbix" --network=zabbix-net -p 443:8443 -p 80:8080 -v /etc/ssl/nginx:/etc/ssl/nginx:ro --restart unless-stopped -d zabbix/zabbix-web-nginx-pgsql:alpine-5.0-latest

透過termianl訪問Container中的資料庫,以psql為例

1
docker exec -it [containerId] bash

1
psql -U zabbix -h localhost zabbix

demo

當全部都設置好後

訪問 http://localohst/ 即可訪問Zabbix頁面

帳號:Admin 密碼:zabbix

在Window下安裝 Zabbix Agent

這邊待補啦,不過先講一下Zabbix的Server端要怎麼對應

image-20230317111417481

Host Name:要和當初設定Agent的Name一致

Group:Templates/Operating systems

Agent:當Agent的那一台主機的IP

image-20230317111854438

image-20230317111428373

Temlate:Template OS Windows by Zabbix agent

API的使用

可以到下列的網站使用線上的Zabbix API Test

https://sbcode.net/zabbix/zabbix-api-test-form/

url都是 http://localhost/api_jsonrpc.php,差別在於Body的內容

測試用API,用以返回版本號

1
2
3
4
5
6
7
{
    "jsonrpc": "2.0",
    "method": "apiinfo.version",
    "id": 1,
    "auth": null,
    "params": {}
}

返回的結果

1
2
3
4
5
{
    "jsonrpc": "2.0",
    "result": "5.0.32",
    "id": 1
}

登入用的API,用來取得Token

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
{
    "jsonrpc": "2.0",
    "method": "user.login",
    "params": {
        "user": "Admin",
        "password": "zabbix"
    },
    "id": 1,
    "auth": null
}

返回的結果

1
2
3
4
5
{
    "jsonrpc": "2.0",
    "result": "1a6022b1a01b787b2129d011763c73e6",
    "id": 1
}

result就是Token值

返回目前存在的Agent

記得把Auth的值改成login返回的token

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
{
    "jsonrpc": "2.0",
    "method": "host.get",
    "params": {
        "output": [
            "hostid",
            "host"
        ],
        "selectInterfaces": [
            "interfaceid",
            "ip"
        ]
    },
    "id": 2,
    "auth": "1a6022b1a01b787b2129d011763c73e6"
}

返回的結果

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
{
    "jsonrpc": "2.0",
    "result": [
        {
            "hostid": "10084",
            "host": "Zabbix server",
            "interfaces": [
                {
                    "interfaceid": "1",
                    "ip": "127.0.0.1"
                }
            ]
        },
        {
            "hostid": "10438",
            "host": "Ian",
            "interfaces": [
                {
                    "interfaceid": "2",
                    "ip": "192.168.100.51"
                }
            ]
        },
        {
            "hostid": "10440",
            "host": "Bill",
            "interfaces": [
                {
                    "interfaceid": "4",
                    "ip": "192.168.100.57"
                }
            ]
        },
        {
            "hostid": "10439",
            "host": "Jess",
            "interfaces": [
                {
                    "interfaceid": "3",
                    "ip": "192.168.100.51"
                }
            ]
        }
    ],
    "id": 2
}

Zabbix API介紹

https://sbcode.net/zabbix/zabbix-api-test-form/

在很多的API Parameter中,會常常看到

1
{"output": "extend"}

這段。這句話的意思是這樣的 output代表你想要返回的value值有什麼下面會有詳細的介紹 而extend則代表「請提供給我,更多的資訊」,詳細的差異如下

我們假設 host.get的返回值為下

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
{
  "jsonrpc": "2.0",
  "result": [
    {
      "hostid": "10084",
      "proxy_hostid": "0",
      "host": "Zabbix server",
      "status": "0",
      "disable_until": "1679972679",
      "error": "Get value from agent failed: cannot connect to [[127.0.0.1]:10050]: [111] Connection refused",
      "available": "2",
      "errors_from": "1679019319",
      "lastaccess": "0",
      "ipmi_authtype": "-1",
      "ipmi_privilege": "2",
      "ipmi_username": "",
      "ipmi_password": "",
      "ipmi_disable_until": "0",
      "ipmi_available": "0",
      "snmp_disable_until": "0",
      "snmp_available": "0",
      "maintenanceid": "0",
      "maintenance_status": "0",
      "maintenance_type": "0",
      "maintenance_from": "0",
      "ipmi_errors_from": "0",
      "snmp_errors_from": "0",
      "ipmi_error": "",
      "snmp_error": "",
      "jmx_disable_until": "0",
      "jmx_available": "0",
      "jmx_errors_from": "0",
      "jmx_error": "",
      "name": "Zabbix server",
      "flags": "0",
      "templateid": "0",
      "description": "",
      "tls_connect": "1",
      "tls_accept": "1",
      "tls_issuer": "",
      "tls_subject": "",
      "tls_psk_identity": "",
      "tls_psk": "",
      "proxy_address": "",
      "auto_compress": "1",
      "inventory_mode": "-1"
    } 
  ],
  "id": 2
}

但我們並不想要那麼多資訊,我們可能只想要其中幾項,比如說proxy_hostid,status而已,那我們就可以把我們Parameters的參數修改成這樣

1
{"output": ["hostid","proxy_hostid"]}

回傳的結果就會變成這樣

使用Zabbix來取得CPU Utilization (in %)

  1. 先使用host.get來取得所有host資訊
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
{
    "jsonrpc": "2.0",
    "method": "host.get",
    "params": {
        "output": [
            "hostid",
            "host"
        ],
        "selectInterfaces": [
            "interfaceid",
            "ip"
        ]
    },
    "id": 2,
    "auth": "7cdc68d62750b0ed7ae693d1d7a52466"
}

返回的結果如下

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
{
    "jsonrpc": "2.0",
    "result": [
        {
            "hostid": "10084",
            "host": "Zabbix server",
            "interfaces": [
                {
                    "interfaceid": "1",
                    "ip": "127.0.0.1"
                }
            ]
        },
        {
            "hostid": "10438",
            "host": "Ian",
            "interfaces": [
                {
                    "interfaceid": "2",
                    "ip": "192.168.100.51"
                }
            ]
        },
        {
            "hostid": "10440",
            "host": "Bill",
            "interfaces": [
                {
                    "interfaceid": "4",
                    "ip": "192.168.100.57"
                }
            ]
        }
    ],
    "id": 2
}
  1. 透過item.get取得hostId的資料

假設我們現在要找到hostId=10440的資料,我們的API BODY要這樣送

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
{
    "jsonrpc": "2.0",
    "method": "item.get",
    "params": {
        "output":["name","description","lastvalue"],
        "filter":{
            "hostid":"10440"
        }
    },
    "id": 2,
    "auth": "7cdc68d62750b0ed7ae693d1d7a52466"
}

其中 output的值代表,只顯示name,description,lastvalue這幾個key的資料,filter則代表我只要key-value為hostid:10440的資料

返回的結果很長,這邊講個大概就好

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
{
    "jsonrpc": "2.0",
    "result": [
        {
            "itemid": "37631",
            "name": "Interface Intel(R) Ethernet Connection (14) I219-V(乙太網路): Outbound packets with errors",
            "description": "The number of outgoing packets with errors on the network interface.",
            "lastvalue": "0"
        },
        {
            "itemid": "37632",
            "name": "Interface Intel(R) Ethernet Connection (14) I219-V(乙太網路): Inbound packets discarded",
            "description": "The number of incoming packets dropped on the network interface.",
            "lastvalue": "0"
        },
        {
            "itemid": "37633",
            "name": "Interface Intel(R) Ethernet Connection (14) I219-V(乙太網路): Inbound packets with errors",
            "description": "The number of incoming packets with errors on the network interface.",
            "lastvalue": "0"
        },
        {
            "itemid": "37634",
            "name": "Interface Intel(R) Ethernet Connection (14) I219-V(乙太網路): Bits received",
            "description": "Incoming traffic on the network interface.",
            "lastvalue": "6431168"
        }
        ...
        //以下略..
}
  1. 找到CPU Utilization的資訊

搜尋關鍵字 CPU

這邊,那個lastValue其實就是最新的CPU使用率,這樣就成功取得CPU的使用率囉!

  1. 取得CPU Utilization的使用率

API Body如下

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
{
    "jsonrpc": "2.0",
    "method": "history.get",
    "params": {
        "history": "0",
        "itemids": "37631", 
        "output": "extend"
    },
    "auth": "7cdc68d62750b0ed7ae693d1d7a52466",
    "id": 1
}

返回的結果如下

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
{
    "jsonrpc": "2.0",
    "result": [
        {
            "itemid": "37568",
            "clock": "1679900528",
            "value": "5.186729",
            "ns": "297585693"
        },
        {
            "itemid": "37568",
            "clock": "1679900648",
            "value": "6.917095",
            "ns": "233421931"
        }
        // ... 
    ]
}

使用Docker安裝,可能導致API路徑不正確

最近在學習zabbix時,安裝在Linux系統下時,透過Postman是可以正常取得資料的

但是當我用Docker把Zabbix架設在Window環境下時卻一直出現

1
File not found.

的錯誤

發現錯誤

兩邊的版本、設置、Server Port都一樣,完全不知道到底發生了什麼問題,後來是透過網頁的開發人員工具才發現一小處的不同

這是Linux環境下的API請求

這是Window下的API請求

聰明的你一定發現了,肏你媽的這兩個API請求的URL完全不一樣啊,幹你媽的

解決方法

我個人猜應該是Docker在部屬的時候,不知道為什麼裡面檔案的結構層級直接跳過了\zabbix這一層,直接變成http://localhost/api_jsonrpc.php的路徑。

將URL改成正確地之後就能正常訪問了

Licensed under CC BY-NC-SA 4.0