控平臺(tái):從配置到告警的完整實(shí)踐)
想了很久在監(jiān)控工具里到底該選誰最后還是把 Zabbix 7.4 用 Docker 跑了起來。這套組合不是靈光一閃而是因?yàn)?Zabbix 本身是開源監(jiān)控里功能最完整的那一檔加上 7.4 這個(gè)版本在可視化、告警和采集性能上都做了不少優(yōu)化Docker 又能把部署成本壓到最低。這篇東西就是記錄我實(shí)際部署的全過程包括 compose 文件的寫法、環(huán)境變量怎么配、踩過哪些坑適合正在做監(jiān)控選型、或者剛接手 Zabbix 的人直接抄作業(yè)。1. 為什么要用 Docker 跑 Zabbix 7.41.1 Zabbix 7.4 解決了什么問題Zabbix 7.4 給我的第一感覺是“終于把界面和配置邏輯理順了”。老版本里常用的儀表盤、主機(jī)組、模板關(guān)聯(lián)都藏在多級(jí)菜單里新版本明顯做了一次收攏很多操作不用再跳來跳去。另一個(gè)比較實(shí)在的變化是監(jiān)控項(xiàng)的處理效率官方給出的數(shù)據(jù)是單臺(tái) server 可以支撐的監(jiān)控項(xiàng)數(shù)量比之前版本更進(jìn)一步實(shí)際用下來同一套配置下歷史數(shù)據(jù)查詢的響應(yīng)速度也要快一些。不過選 7.4 最重要的原因是它對(duì)容器環(huán)境更友好。官方鏡像倉庫里提供了 server、web、agent 的全套鏡像tag 直接對(duì)應(yīng)版本號(hào)不再需要自己用源碼編譯或者手工改配置文件。這一點(diǎn)對(duì)中小團(tuán)隊(duì)尤其關(guān)鍵監(jiān)控系統(tǒng)本身越省事才越有精力去整理業(yè)務(wù)側(cè)的告警規(guī)則。1.2 Docker 部署與裸機(jī)部署的取舍如果只有兩三臺(tái)服務(wù)器很多人會(huì)覺得直接裝個(gè) RPM 包就夠了。確實(shí)單機(jī)部署 Zabbix 的安裝過程也不算復(fù)雜但一旦涉及升級(jí)、回滾、遷移問題就來了。我見過不止一個(gè)團(tuán)隊(duì)因?yàn)榉?wù)器上殘留著舊版本的依賴庫導(dǎo)致升級(jí)到新版本時(shí)數(shù)據(jù)庫 schema 遷移失敗最后只能重新部署。Docker 把運(yùn)行環(huán)境和依賴一起打包很大程度上規(guī)避了這類問題。容器化也讓“一個(gè)監(jiān)控平臺(tái)同時(shí)跑多個(gè)監(jiān)控場(chǎng)景”變得更簡(jiǎn)單。比如需要臨時(shí)測(cè)試告警規(guī)則可以在同一臺(tái)宿主機(jī)上再起一個(gè)隔離的實(shí)例想升級(jí)版本把鏡像 tag 改掉重啟 compose 項(xiàng)目不行就切回舊 tag整個(gè)過程對(duì)現(xiàn)有監(jiān)控?cái)?shù)據(jù)的影響很小。當(dāng)然代價(jià)也有Docker 網(wǎng)絡(luò)、存儲(chǔ)卷、容器日志這些概念需要額外理解但相比之下收益遠(yuǎn)大于學(xué)習(xí)成本。1.3 整體架構(gòu)與運(yùn)行原理Zabbix 7.4 的 Docker 部署通常拆成三個(gè)核心容器數(shù)據(jù)庫、Zabbix Server、Zabbix Web另外再加一個(gè) Agent2 容器用于采集宿主機(jī)自身狀態(tài)。數(shù)據(jù)庫負(fù)責(zé)存配置和監(jiān)控歷史數(shù)據(jù)Server 是邏輯大腦負(fù)責(zé)輪詢、數(shù)據(jù)處理、觸發(fā)告警Web 是前面的界面層負(fù)責(zé)渲染儀表盤和接受操作指令。三個(gè)容器各司其職通過一個(gè)自定義 bridge 網(wǎng)絡(luò)互相通信。Agent2 的作用容易被低估。它不只是“裝在被監(jiān)控機(jī)器上”的東西在 Docker 部署場(chǎng)景里還可以把宿主機(jī)本身納入監(jiān)控順便通過主動(dòng)模式匯報(bào)數(shù)據(jù)。這樣即便被監(jiān)控網(wǎng)絡(luò)的防火墻限制比較嚴(yán)格只要宿主機(jī)能出站到 Server 的 10051 端口監(jiān)控鏈路仍然是通的。2. 部署前的規(guī)劃與關(guān)鍵決策2.1 數(shù)據(jù)庫選型PostgreSQL 還是 MySQLZabbix 7.4 官方支持 PostgreSQL 和 MySQL 兩種主流數(shù)據(jù)庫。我的建議是新部署無腦選 PostgreSQL。原因不是 MySQL 不能用而是 Zabbix 在 PostgreSQL 上的分區(qū)表、歷史數(shù)據(jù)批量清理機(jī)制支持得更成熟遇到大規(guī)模監(jiān)控項(xiàng)時(shí)不容易出現(xiàn)鎖表現(xiàn)象。此外官方鏡像里zabbix/zabbix-server-pgsql和zabbix/zabbix-web-nginx-pgsql的 tag 維護(hù)最及時(shí)避坑概率更高。如果團(tuán)隊(duì)里已經(jīng)有成熟的 MySQL 運(yùn)維體系也不是不能選 MySQL但要注意字符集和時(shí)區(qū)設(shè)置避免寫入中文亂碼或者時(shí)間偏移。真要我給一個(gè)硬性建議只要不是歷史包袱太重?cái)?shù)據(jù)庫就選 PostgreSQL后續(xù)備份、調(diào)優(yōu)、遷移都會(huì)輕松不少。2.2 鏡像 tag 與版本配套Docker 部署最容易犯的錯(cuò)誤是亂用 tag導(dǎo)致 server 是 7.4 而 web 是 7.2數(shù)據(jù)庫 schema 直接不兼容。官方鏡像倉庫里 7.4 對(duì)應(yīng)的核心鏡像如下組件鏡像名推薦 tag數(shù)據(jù)庫postgres16-alpineServerzabbix/zabbix-server-pgsql7.4-latestWebzabbix/zabbix-web-nginx-pgsql7.4-latestAgentzabbix/zabbix-agent27.4-latest這里有個(gè)細(xì)節(jié)Web 鏡像里其實(shí)已經(jīng)內(nèi)置了 Nginx 和 PHP-FPM不需要額外再裝一個(gè) Nginx外部訪問直接映射 Web 容器的 8080 端口即可。數(shù)據(jù)庫鏡像我選了 Alpine 版體積小不少對(duì)監(jiān)控系統(tǒng)這類長(zhǎng)時(shí)間運(yùn)行的服務(wù)來說也更干凈。2.3 數(shù)據(jù)持久化方案Zabbix 的數(shù)據(jù)安全完全依賴于持久化配置做對(duì)了沒有。最穩(wěn)妥的方案是數(shù)據(jù)庫用 Docker volume而 server 和 web 容器不需要持久化任何數(shù)據(jù)因?yàn)檎嬲臓顟B(tài)都在數(shù)據(jù)庫里。有人習(xí)慣用宿主機(jī)目錄 bind mount 來存數(shù)據(jù)庫也可以但要注意目錄權(quán)限PostgreSQL 容器內(nèi)的postgres用戶 UID 是 70權(quán)限不對(duì)會(huì)出現(xiàn)“Permission denied”導(dǎo)致數(shù)據(jù)庫起不來。建議在部署前就定義好 volume 的命名后續(xù)做備份和遷移時(shí)可以直接用docker run --volumes-from或者pg_dump從容器里把數(shù)據(jù)導(dǎo)出來避免跟不同項(xiàng)目的掛載點(diǎn)搞混。3. 基于 Docker Compose 的一鍵部署實(shí)操3.1 準(zhǔn)備工作與目錄規(guī)劃我先在一臺(tái)干凈的 Linux 服務(wù)器上做演示系統(tǒng)是 CentOS 7.9 的內(nèi)核層面兼容方案但實(shí)際用的發(fā)行版是 Debian 系原因不再展開重點(diǎn)是想說明這個(gè)方案跟發(fā)行版關(guān)系不大只要 Docker Engine 和 Compose 插件可用就行。安裝 Docker 后先建好項(xiàng)目目錄mkdir -p /opt/zabbix在/opt/zabbix下放一個(gè)docker-compose.yml以及后續(xù)會(huì)用到的.env文件。為什么要單獨(dú)建目錄因?yàn)?compose 項(xiàng)目名稱默認(rèn)以目錄名命名后續(xù)執(zhí)行docker compose down時(shí)只會(huì)影響這個(gè)項(xiàng)目?jī)?nèi)的容器不會(huì)誤傷其他服務(wù)。3.2 完整 compose 文件直接貼出我實(shí)際使用的 compose 配置services: zabbix-db: image: postgres:16-alpine container_name: zabbix-db environment: POSTGRES_USER: zabbix POSTGRES_PASSWORD: zabbix_pwd POSTGRES_DB: zabbix volumes: - zabbix-db-data:/var/lib/postgresql/data networks: - zabbix-net restart: unless-stopped healthcheck: test: [CMD-SHELL, pg_isready -U zabbix -d zabbix] interval: 5s timeout: 3s retries: 10 zabbix-server: image: zabbix/zabbix-server-pgsql:7.4-latest container_name: zabbix-server environment: DB_SERVER_HOST: zabbix-db DB_SERVER_PORT: 5432 POSTGRES_USER: zabbix POSTGRES_PASSWORD: zabbix_pwd POSTGRES_DB: zabbix ZBX_CACHESIZE: 128M ZBX_HISTORYCACHESIZE: 128M ZBX_TRENDCACHESIZE: 64M ports: - 10051:10051 volumes: - zabbix-server-alertscripts:/usr/lib/zabbix/alertscripts networks: - zabbix-net depends_on: zabbix-db: condition: service_healthy restart: unless-stopped zabbix-web: image: zabbix/zabbix-web-nginx-pgsql:7.4-latest container_name: zabbix-web environment: ZBX_SERVER_HOST: zabbix-server ZBX_SERVER_PORT: 10051 POSTGRES_USER: zabbix POSTGRES_PASSWORD: zabbix_pwd POSTGRES_DB: zabbix PHP_TZ: Asia/Shanghai ports: - 8080:8080 networks: - zabbix-net depends_on: - zabbix-server restart: unless-stopped zabbix-agent2: image: zabbix/zabbix-agent2:7.4-latest container_name: zabbix-agent2 environment: ZBX_SERVER_HOST: zabbix-server ZBX_SERVER_PORT: 10051 ZBX_HOSTNAME: Docker Host pid: host privileged: true networks: - zabbix-net depends_on: - zabbix-server restart: unless-stopped volumes: zabbix-db-data: networks: zabbix-net: driver: bridge幾個(gè)關(guān)鍵點(diǎn)我單獨(dú)說一下。ZBX_CACHESIZE這些緩存參數(shù)初始環(huán)境用默認(rèn)值也能跑但我給的是適合幾千個(gè)監(jiān)控項(xiàng)的經(jīng)驗(yàn)值后續(xù)監(jiān)控項(xiàng)增加后可以按需調(diào)整。zabbix-server-alertscripts卷是給自定義告警腳本預(yù)留的一開始就掛出來后面要做 Webhook 或發(fā)短信腳本時(shí)不用動(dòng)容器。Agent2 容器加了privileged: true是因?yàn)槲蚁胱屗ㄟ^ mount 方式采集宿主機(jī)的磁盤和進(jìn)程數(shù)據(jù)如果只是采基本 CPU、內(nèi)存指標(biāo)這個(gè)權(quán)限可以不開放。3.3 啟動(dòng)與日志檢查在/opt/zabbix目錄下執(zhí)行docker compose up -d第一次啟動(dòng)會(huì)因?yàn)槔R像和初始化數(shù)據(jù)庫花一兩分鐘不要急著看頁面。用下面的命令觀察 server 是否正常docker compose logs -f zabbix-server正常日志里會(huì)出現(xiàn)類似server #0 started [Zabbix Server]的字樣這時(shí)候再去訪問 Web 端。數(shù)據(jù)庫初始化過程最怕 server 容器在數(shù)據(jù)庫未就緒時(shí)反復(fù)重啟我的 compose 里已經(jīng)用 healthcheck 加了依賴等待所以基本不會(huì)出現(xiàn)這個(gè)問題。如果日志一直在報(bào)連接拒絕優(yōu)先查數(shù)據(jù)庫容器狀態(tài)。3.4 Web 界面初始化與中文設(shè)置瀏覽器打開http://服務(wù)器IP:8080第一次訪問會(huì)進(jìn)入安裝向?qū)?。過程很簡(jiǎn)單確認(rèn)數(shù)據(jù)庫連接信息無誤后Zabbix 會(huì)自動(dòng)執(zhí)行 schema 導(dǎo)入完成后跳轉(zhuǎn)到登錄頁默認(rèn)賬號(hào)是Admin默認(rèn)密碼是zabbix。進(jìn)來后第一件事是把界面語言改成中文。點(diǎn)右上角頭像進(jìn)入 User settings把 Language 改為Chinese (zh_CN)。這里有個(gè)常見坑如果PHP_TZ環(huán)境變量沒設(shè)置或設(shè)置錯(cuò)誤中文界面下時(shí)間會(huì)偏移告警時(shí)間對(duì)不上號(hào)所以我在 Web 容器的環(huán)境變量里已經(jīng)寫好了PHP_TZ: Asia/Shanghai。4. 常見故障與排查實(shí)錄4.1 數(shù)據(jù)庫連接不上的連鎖反應(yīng)剛部署完最容易遇到的現(xiàn)象是zabbix-server容器每隔幾秒重啟一次日志顯示failed to connect to database。多數(shù)原因是 server 啟動(dòng)時(shí)數(shù)據(jù)庫還沒 ready或者 compose 里的depends_on條件寫得太簡(jiǎn)單。我現(xiàn)在的寫法是讓 server 依賴數(shù)據(jù)庫的 healthcheck 結(jié)果只有pg_isready返回成功才開始拉 server。如果已經(jīng)把 compose 文件改成這樣還重啟那就手工進(jìn)數(shù)據(jù)庫容器驗(yàn)證docker exec -it zabbix-db psql -U zabbix -d zabbix -c select 1能返回1說明數(shù)據(jù)庫本身沒問題問題大概率在密碼或者 host 配置。環(huán)境變量里的POSTGRES_PASSWORD必須和數(shù)據(jù)庫初始化時(shí)保持一致改密碼后要同步改 compose 里的所有引用位置。4.2 Agent 顯示不可達(dá)的問題監(jiān)控宿主機(jī)時(shí)如果 Agent2 容器已經(jīng)跑了但 Web 界面上主機(jī)狀態(tài)一直是紅色先別急著懷疑網(wǎng)絡(luò)。Zabbix 的主機(jī)名匹配機(jī)制是常見原因Agent 上報(bào)的Hostname要和主機(jī)配置里的名字一致不一致時(shí) server 會(huì)把數(shù)據(jù)當(dāng)未知來源丟掉。我在 Web 上配置主機(jī)時(shí)主機(jī)名寫的是“Docker Host”Agent2 容器的ZBX_HOSTNAME也必須是“Docker Host”。同時(shí)要把主機(jī)類型改成主動(dòng)或被動(dòng)對(duì)應(yīng)模式默認(rèn)的 Agent 模式是主動(dòng)檢查如果 Agent 配成被動(dòng)檢查但對(duì)端端口不通界面一樣顯示不可達(dá)。4.3 容器重啟后數(shù)據(jù)全丟這個(gè)問題多半是沒掛 volume。數(shù)據(jù)庫容器如果沒掛zabbix-db-datadocker compose down之后容器刪除數(shù)據(jù)跟著就沒了。驗(yàn)證方法很簡(jiǎn)單docker volume ls | grep zabbix能查到對(duì)應(yīng) volume 才說明持久化正常。備份時(shí)直接用pg_dump導(dǎo)出數(shù)據(jù)庫內(nèi)容不需要整個(gè) volume 快照但如果是遷移服務(wù)器還是建議用 volume 快照加pg_dump雙保險(xiǎn)。4.4 時(shí)區(qū)錯(cuò)亂引發(fā)的告警誤差PHP 默認(rèn)時(shí)區(qū)是 UTC國(guó)內(nèi)服務(wù)器如果不顯式設(shè)置PHP_TZ頁面上的時(shí)間會(huì)比北京時(shí)間慢 8 小時(shí)。這個(gè)問題的隱蔽之處在于Zabbix Server 內(nèi)部的告警判斷是基于 UTC 的Web 端展示時(shí)間會(huì)通過 PHP 時(shí)區(qū)轉(zhuǎn)換所以最后看到的就是“告警時(shí)間對(duì)不上”。排查技巧先在數(shù)據(jù)庫里查now()和current_timestamp確認(rèn)數(shù)據(jù)庫時(shí)區(qū)正常再看 Web 容器環(huán)境變量是否有PHP_TZ。修改環(huán)境變量后不需要重建容器只需要docker compose up -d重新創(chuàng)建 Web 容器即可。5. 上線后的配置、備份與加固5.1 基礎(chǔ)監(jiān)控模板與告警通道Zabbix 7.4 自帶了很多官方模板比如 Linux 主機(jī)模板、Windows 主機(jī)模板、SNMP 設(shè)備模板。建議先把宿主機(jī)通過 Agent2 接入跑一遍自帶模板確認(rèn)監(jiān)控項(xiàng)數(shù)據(jù)正常后再擴(kuò)展其他設(shè)備。告警通道方面先配置一個(gè)最簡(jiǎn)單的郵件告警確認(rèn)觸發(fā)鏈路通再去搞 Webhook 或釘釘機(jī)器人。在配置告警媒介時(shí)千萬不要只在 Media type 里填寫服務(wù)器地址還要在 Users 里給用戶添加“告警媒介”。我見過很多新手卡在這一步告警動(dòng)作配置了媒介也配置了但用戶沒有綁定媒介結(jié)果一條告警都收不到。5.2 數(shù)據(jù)庫的備份策略Docker 部署環(huán)境的備份比物理機(jī)簡(jiǎn)單。我推薦每天凌晨用 cron 執(zhí)行一次pg_dump到宿主機(jī)備份目錄保留最近 7 天docker exec zabbix-db pg_dump -U zabbix zabbix | gzip /backup/zabbix_$(date \%F).sql.gz find /backup -name zabbix_*.sql.gz -mtime 7 -delete執(zhí)行前確保宿主機(jī)libpq客戶端可用或者直接在容器內(nèi)執(zhí)行并掛載備份目錄?;謴?fù)時(shí)先用gunzip解壓再通過psql導(dǎo)入到新數(shù)據(jù)庫注意導(dǎo)入順序要保證目標(biāo)庫是空的否則會(huì)有主鍵沖突。5.3 安全加固的幾個(gè)動(dòng)作默認(rèn)密碼Admin/zabbix上線后必須第一時(shí)間改掉。其次是把 Guest 用戶禁用這個(gè)用戶默認(rèn)存在但基本用不上留著只會(huì)增加暴露面。Web 容器如果只在內(nèi)網(wǎng)訪問建議端口映射時(shí)綁定內(nèi)網(wǎng) IPports: - 127.0.0.1:8080:8080需要從公網(wǎng)訪問時(shí)前面加一層帶有 HTTPS 證書的反向代理不要直接暴露 Zabbix Web 的 8080 端口。數(shù)據(jù)庫 5432 端口不需要映射到宿主機(jī)compose 里只放在自定義網(wǎng)絡(luò)內(nèi)即可外部連不上反而安全。最后再分享一個(gè)小技巧Zabbix Server 容器日志默認(rèn)是標(biāo)準(zhǔn)輸出長(zhǎng)時(shí)間運(yùn)行會(huì)積累不少數(shù)據(jù)建議在運(yùn)行 Docker 的宿主機(jī)上配置 log rotation。/etc/docker/daemon.json里加上log-driver和max-size配置避免/var/lib/docker/containers目錄被日志撐爆。這個(gè)坑是我在監(jiān)控平臺(tái)跑了三個(gè)月之后才遇到的提前配置好能省掉不少清理工作。