Munin 2.0.57 部署指南

Munin 2.0.57 Docker Compose 部署指南:自建双角色镜像(master/node 环境变量分发)、compose 编排 1 master + 2 node、显式网段 10.89.60.0/24、RRD 数据持久化、配置挂载与节点 ACL 自动放行,含 pid 目录与 CGI::Fast 缺失等排障实录,全部命令与回显实测。

MuninMunin监控2026/10/20

Munin 2.0.57 部署指南

目标:用 Docker Compose 一键部署「1 个 Munin master + 2 个被监控 node」的完整监控栈,覆盖镜像构建选型、端口与网段规划、数据持久化、配置挂载、节点 ACL 自动放行与日常运维命令。全文在 Docker Compose v5.5.1 + Ubuntu 22.04 基础镜像环境实测通过,Web 界面、静态/CGI 出图与多节点采集均逐条验证。

一、环境信息

  • 宿主操作系统:Ubuntu 22.04(x86_64)
  • Docker 与 Compose:Docker Engine + Docker Compose v5.5.1(docker compose version 实测)
  • Munin 版本:2.0.57-1ubuntu2(镜像内基于 ubuntu:22.04 经 apt 安装,munin version 2.0.57 实测)
  • 栈内拓扑:munin-master(采集 + Web 出图,映射宿主 8131→80)+ munin-node2 + munin-node3
  • 自定义网络:munin-net(bridge,显式子网 10.89.60.0/24,固定各节点 IPv4)
  • 持久化卷:munin-db(RRD 数据)、munin-www(HTML/图形输出)、munin-logs(日志)
  • 访问入口:宿主机 http://<宿主IP>:8131/munin/

二、镜像选型说明

Munin 官方不发布容器镜像,Docker Hub 上第三方镜像(如社区个人维护的 munin 镜像)版本陈旧、配置不可控。本方案选择自建镜像:以 ubuntu:22.04 为基础,apt 安装发行版仓库的 munin 全家桶(2.0.57)+ apache2,单一镜像通过环境变量区分 master/node 双角色——master 角色跑「cron 采集 + Apache 出图」,node 角色只跑 munin-node 前台。选型对比:

方案版本可控性维护成本适用
自建镜像(本文)锁定 Ubuntu 22.04 仓库版 2.0.57,可升级 2.0.75/76自己维护 Dockerfile生产推荐
第三方个人镜像版本不明、多为 2.0.x 老包低但不可控快速体验
官方镜像Munin 官方不发布—不存在

镜像构建文件 Dockerfile(与 compose 文件同目录):

# Munin 2.0.57 (Ubuntu 22.04) master/node 双角色镜像
# 构建后由 compose 以不同 command/环境变量区分 master / node 角色
FROM ubuntu:22.04

ENV DEBIAN_FRONTEND=noninteractive

RUN apt-get update && \
    apt-get install -y --no-install-recommends \
        munin munin-node munin-plugins-extra apache2 cron tzdata curl telnet \
        libwww-perl libcache-cache-perl libcgi-fast-perl && \
    rm -rf /var/lib/apt/lists/*
# master 角色默认站点配置(静态 HTML + CGI 出图)
COPY munin-apache.conf /etc/apache2/conf-available/munin.conf
RUN a2enconf munin && a2enmod cgid && \
    chown -R munin:www-data /var/log/munin && chmod -R g+rwX /var/log/munin && \
    mkdir -p /var/log/munin/cgi && chown -R www-data:adm /var/log/munin/cgi && \
    touch /var/log/munin/munin-cgi-graph.log /var/log/munin/munin-cgi-html.log && \
    chown www-data:www-data /var/log/munin/munin-cgi-graph.log /var/log/munin/munin-cgi-html.log

COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh

EXPOSE 80 4949

ENTRYPOINT ["/entrypoint.sh"]

Apache 站点片段 munin-apache.conf(静态 HTML + CGI 双通道,与裸机安装一致):

Alias /munin /var/cache/munin/www
<Directory /var/cache/munin/www>
        Require all granted
        Options FollowSymLinks SymLinksIfOwnerMatch
        AddDefaultCharset UTF-8
</Directory>
ScriptAlias /munin-cgi/munin-cgi-graph /usr/lib/munin/cgi/munin-cgi-graph
<Location /munin-cgi/munin-cgi-graph>
        Require all granted
        Options +ExecCGI
</Location>
ScriptAlias /munin-cgi/munin-cgi-html /usr/lib/munin/cgi/munin-cgi-html
<Location /munin-cgi/munin-cgi-html>
        Require all granted
        Options +ExecCGI
</Location>

入口脚本 entrypoint.sh(角色分发 + node 端 ACL 自动放行):

#!/bin/bash
# 按环境变量 MUNIN_ROLE 决定角色:master=采集+Web 出图,node=仅被采集端
ROLE="${MUNIN_ROLE:-master}"

# 被采集端:放行 master 网段(cidr_allow 取自环境变量,逗号分隔多个网段)
if [ -n "$MUNIN_NODE_CIDR_ALLOW" ]; then
    for net in $(echo "$MUNIN_NODE_CIDR_ALLOW" | tr ',' ' '); do
        grep -q "cidr_allow $net" /etc/munin/munin-node.conf || echo "cidr_allow $net" >> /etc/munin/munin-node.conf
    done
fi

# Net::Server 需要 pid 文件目录(systemd 场景由 RuntimeDirectory 提供,前台运行须自建)
mkdir -p /var/run/munin && chown munin:munin /var/run/munin

if [ "$ROLE" = "node" ]; then
    exec /usr/sbin/munin-node --foreground
fi

# master 角色:cron 周期采集 + apache 前台出图
service cron start >/dev/null 2>&1
/usr/sbin/munin-node --foreground &
apache2ctl -DFOREGROUND &
wait -n

⚠️ 注意:两处来自实测的排障点已固化在构建文件中——其一,apt --no-install-recommends 会漏掉推荐依赖 libcgi-fast-perl,CGI 出图将报 Can't locate CGI/Fast.pm in @INC(详见第十一章 FAQ 2),必须显式列入安装清单;其二,前台运行 munin-node 前必须自建 /var/run/munin,否则报 Couldn't open pid file ... No such file or directory(FAQ 1)。

三、前置条件

  1. 宿主机已安装 Docker 与 Docker Compose v2+:
docker compose version

实测回显:

Docker Compose version v5.5.1
  1. 端口与网段规划:宿主 Web 端口选 8131(确认空闲);容器网段选 10.89.60.0/24(确认不与既有网络冲突):
ss -ltn | grep 8131 || echo "8131 空闲"
docker network ls | grep -c munin || echo "无同名网络"

实测回显:

8131 空闲
无同名网络
  1. 项目目录就绪:以下 5 个文件置于同一目录(如 /opt/munin-compose/):Dockerfile、munin-apache.conf、entrypoint.sh、munin.conf、docker-compose.yml。

四、部署步骤

4.1 编写 compose 文件

docker-compose.yml(name: 显式指定项目名,避免与同机其他 compose 项目因目录同名冲突;网络显式 --subnet 固定网段):

name: munin-2-0-57-stack

services:
  munin-master:
    build:
      context: .
      dockerfile: Dockerfile
    image: munin-2.0.57-ubuntu22:v1
    container_name: munin-master
    hostname: munin-master1
    ports:
      - "8131:80"
    environment:
      MUNIN_ROLE: master
    volumes:
      - ./munin.conf:/etc/munin/munin.conf:ro
      - munin-db:/var/lib/munin
      - munin-www:/var/cache/munin/www
      - munin-logs:/var/log/munin
    networks:
      munin-net:
        ipv4_address: 10.89.60.10
    restart: unless-stopped

  munin-node2:
    image: munin-2.0.57-ubuntu22:v1
    container_name: munin-node2
    hostname: node2
    environment:
      MUNIN_ROLE: node
      MUNIN_NODE_CIDR_ALLOW: 10.89.60.0/24
    networks:
      munin-net:
        ipv4_address: 10.89.60.11
    restart: unless-stopped

  munin-node3:
    image: munin-2.0.57-ubuntu22:v1
    container_name: munin-node3
    hostname: node3
    environment:
      MUNIN_ROLE: node
      MUNIN_NODE_CIDR_ALLOW: 10.89.60.0/24
    networks:
      munin-net:
        ipv4_address: 10.89.60.12
    restart: unless-stopped

volumes:
  munin-db:
  munin-www:
  munin-logs:

networks:
  munin-net:
    driver: bridge
    ipam:
      config:
        - subnet: 10.89.60.0/24

master 挂载的主配置 munin.conf(把两个 node 纳入采集范围):

# Munin master 主配置(挂载进容器覆盖默认值)
dbdir   /var/lib/munin
htmldir /var/cache/munin/www
logdir  /var/log/munin
rundir  /var/run/munin

# 首轮采集完成后以 CGI 动态出图;static 首轮仍由 munin-cron 生成
tmpldir /etc/munin/templates
staticdir /etc/munin/static

# 分布式轮询并发度(节点多于 5 台时建议调大)
max_processes 4

# 本机(master 自身也作为被监控节点)
[munin-master1]
    address 127.0.0.1
    use_node_name yes

[node2]
    address 10.89.60.11
    use_node_name yes

[node3]
    address 10.89.60.12
    use_node_name yes

配置要点逐项说明:dbdir/htmldir/logdir/rundir 四目录分别对应三个命名卷与容器内运行目录;[munin-master1] address 127.0.0.1 让 master 顺带监控自身(容器内 munin-node 由 entrypoint 拉起);[node2]/[node3] 用固定 IPv4 寻址,节点扩缩只增删段落;max_processes 控制并行轮询 worker 数。

4.2 一键构建并启动

docker compose up -d --build

实测回显(输出节选,实测末段):

 Container munin-node3 Starting
 Container munin-master Starting
 Container munin-node3 Started
 Container munin-node2 Started
 Container munin-master Started

确认三服务状态:

docker compose ps --format 'table {{.Name}}\t{{.Status}}'

实测回显:

NAME           STATUS
munin-master   Up 14 seconds
munin-node2    Up 14 seconds
munin-node3    Up 14 seconds

4.3 触发首轮采集并验证

首轮数据落盘(进入 master 手动跑一次 munin-cron,免去等 5 分钟 cron 周期):

docker compose exec munin-master su - munin --shell /bin/bash -c "/usr/bin/munin-cron"
docker compose exec munin-master grep "Munin-update finished for node" /var/log/munin/munin-update.log | tail -3

实测回显:

2026/10/19 22:58:14 [INFO]: Munin-update finished for node node3;node3 (3.30 sec)
2026/10/19 22:58:14 [INFO]: Munin-update finished for node node2;node2 (3.30 sec)
2026/10/19 22:58:14 [INFO]: Munin-update finished for node munin-master1;munin-master1 (3.34 sec)

宿主机验证 Web 三连(首页 / node2 页面 / 趋势图):

curl -s -o /dev/null -w "host-html:%{http_code}\n" http://127.0.0.1:8131/munin/
curl -s -o /dev/null -w "host-node2:%{http_code}\n" http://127.0.0.1:8131/munin/node2/node2/
curl -s -o /dev/null -w "host-png:%{http_code} size:%{size_download}\n" http://127.0.0.1:8131/munin/node2/node2/load-day.png

实测回显:

host-html:200
host-node2:200
host-png:200 size:13490

CGI 动态出图验证(容器内):

docker compose exec munin-master curl -s -o /dev/null -w "cgi:%{http_code} type:%{content_type} size:%{size_download}\n" http://127.0.0.1/munin-cgi/munin-cgi-graph/node2/node2/load-day.png

实测回显:

cgi:200 type:image/png size:13273

浏览器访问 http://<宿主IP>:8131/munin/ 应看到 munin-master1、node2、node3 三个分组的完整趋势页。部署成功判据:三个服务 Up、update 日志三节点全 finished、宿主 8131 三连 200。

五、数据持久化说明

卷名容器内路径内容丢失影响
munin-2-0-57-stack_munin-db/var/lib/muninRRD 文件 + datafile 索引 + limits 状态历史趋势数据丢失,需重跑采集从零积累
munin-2-0-57-stack_munin-www/var/cache/munin/www静态 HTML/PNG 产物可再生(下一轮 munin-cron 重建)
munin-2-0-57-stack_munin-logs/var/log/munin各组件日志可再生

验证持久化(实测):docker compose down 后 docker compose up -d,RRD 数据保留、Web 页面无需首轮等待即有历史数据;down -v 才会连卷一起删除。

RRD 文件查看(每指标字段一个文件,四档 RRA 环形存储,尺寸固定):

docker compose exec munin-master ls /var/lib/munin/node3/ | head -3

实测回显:

node3-cpu-guest-d.rrd
node3-cpu-idle-d.rrd
node3-cpu-iowait-d.rrd

💡 说明:RRDtool(Round-Robin Database)是 Munin 的底层时序存储,同类存储引擎对比——

存储引擎特点适用
RRDtool固定尺寸环形文件、自动降采样、零数据库运维Munin/Cacti 类主机趋势监控
MySQL/PG 历史表查询灵活但需容量运维Zabbix 类平台化监控
Prometheus TSDB标签索引、高基数、压缩列存云原生指标体系

Munin 采用 RRDtool 的取舍是磁盘占用恒定、无数据库依赖;代价是不支持任意窗口灵活查询。本方案实际采用 RRDtool(Munin 内建)。

六、环境变量表

变量默认值作用取值示例
MUNIN_ROLEmaster服务角色:master=采集+Web,node=仅被采集端master / node
MUNIN_NODE_CIDR_ALLOW空node 角色:向 /etc/munin/munin-node.conf 追加 cidr_allow 网段,放行 master 来源;逗号分隔可多段10.89.60.0/24
TZUTC时区(影响图形横轴与日志时间戳)Asia/Shanghai

七、配置参数说明

master 核心配置即挂载的 munin.conf(4.1 节全文),关键参数:

  • dbdir / htmldir / logdir / rundir:四类目录,与 volumes 一一对应,改动会破坏与 compose 挂载的对应关系,保持默认;
  • max_processes 4:并行轮询 worker 数。实测 3 节点轮询每轮约 3.3 秒;节点规模 50+ 时建议按 CPU 核数调到 8~16;
  • tmpldir / staticdir:页面模板与静态资源位置,个性化界面时挂载覆盖;
  • host 段 [名字] address <IP> use_node_name yes:节点纳管声明,名字即页面分组层级。

node 端配置由 entrypoint 自动追加 cidr_allow,手工等价形态是在 /etc/munin/munin-node.conf 中写入:

cidr_allow 10.89.60.0/24

7.1 插件增补(node 容器内实测)

node 角色容器内用 munin-node-configure 启用更多插件(以启用 apache 插件族为例):

docker compose exec munin-node2 bash -c "apt-get update -qq && apt-get install -y -qq libwww-perl >/dev/null 2>&1; munin-node-configure --shell 2>/dev/null | grep 'ln -s' | bash; kill 1" 2>/dev/null; docker compose restart munin-node2

⚠️ 注意:容器内 node 进程以 PID 1 前台运行,装完依赖后 restart 重新拉起才会重新探测插件;验证方式与裸机一致(munin-run apache_accesses 输出 accesses80.value <n>)。

八、配置文件挂载

宿主文件挂载点读写说明
./munin.conf/etc/munin/munin.confromaster 主配置,改后 docker compose restart munin-master 生效
./munin-apache.conf构建期 COPY /etc/apache2/conf-available/munin.conf构建期站点配置,改动需 docker compose up -d --build
./entrypoint.sh构建期 COPY /entrypoint.sh构建期角色分发逻辑

节点容器内的 /etc/munin/munin-node.conf 未挂载,由镜像默认值 + entrypoint 追加 cidr_allow 生成;需深度定制 node 端配置时,可仿照 master 把本地文件以 :ro 挂进对应 node 服务。

九、等价 docker run

不使用 Compose 时,等价的分步启动命令(同一镜像、同一网络):

docker network create --driver bridge --subnet 10.89.60.0/24 munin-net

docker build -t munin-2.0.57-ubuntu22:v1 /opt/munin-compose/

docker run -d --name munin-master --hostname munin-master1 \
  -p 8131:80 \
  -e MUNIN_ROLE=master \
  -v /opt/munin-compose/munin.conf:/etc/munin/munin.conf:ro \
  munin-2.0.57-ubuntu22:v1

docker run -d --name munin-node2 --hostname node2 \
  -e MUNIN_ROLE=node -e MUNIN_NODE_CIDR_ALLOW=10.89.60.0/24 \
  --network munin-net munin-2.0.57-ubuntu22:v1

⚠️ 注意:等价命令中 master 未挂卷、node2 未显式指定网络地址,仅用于理解 compose 语义;生产按第四章 compose 配置为准。

十、常用运维命令

docker compose ps                       # 栈内服务状态
docker compose logs munin-master        # master 日志(cron/apache 输出)
docker compose exec munin-master bash   # 进入 master 排障
docker compose exec munin-master su - munin --shell /bin/bash -c "/usr/bin/munin-cron"   # 手动触发一轮采集
docker compose restart munin-node2      # 重启单个节点(改插件/配置后)
docker compose up -d --build            # 改 Dockerfile/挂载文件后重建
docker compose down                     # 停栈保留数据卷
docker compose down -v                  # 停栈并删除数据卷(历史数据清零,慎用)

实测示例(telnet 协议抽查 node2 指标):

docker compose exec munin-node2 sh -c '(echo nodes; sleep 1; echo quit) | timeout 5 telnet 127.0.0.1 4949'

实测回显:

node2
.

💡 说明:nodes 返回该 node 上报的主机名,行首的 . 是协议结束符;node 角色容器 docker compose logs 通常为空——munin-node 的连接日志写在容器内 /var/log/munin/munin-node.log,用 docker compose exec munin-node2 tail /var/log/munin/munin-node.log 查看。

十一、常见问题(FAQ)

Q1:node 容器反复重启,日志报 Couldn't open pid file "/var/run/munin/munin-node.pid" [No such file or directory]? 实测定位:Net::Server 写 pid 前要求 /var/run/munin 存在;systemd 场景由单元文件的 RuntimeDirectory 自动创建,容器前台运行无人创建。entrypoint 中 mkdir -p /var/run/munin 已固化修复;自建镜像漏掉此行必现该故障。

Q2:CGI 出图 500,Apache 错误日志 Can't locate CGI/Fast.pm in @INC ... at /usr/lib/munin/cgi/munin-cgi-graph line 36? 实测定位:Dockerfile 用了 --no-install-recommends,推荐依赖 libcgi-fast-perl(提供 CGI::Fast)未装。修复:依赖清单显式加 libcgi-fast-perl 后 docker compose up -d --build;静态出图(munin-cron 预渲染)不受此影响。

Q3:master 采不到 node,update 日志出现 No old data available for failed worker node2;node2? 实测定位:node 端 ACL 拒绝 master 来源(/var/log/munin/munin-node.log 出现 Denying connection from: ::ffff:10.89.60.10)。compose 已通过 MUNIN_NODE_CIDR_ALLOW=10.89.60.0/24 自动放行;自建配置漏掉 cidr_allow 即复现。修复后 docker compose restart munin-node2。

Q4:页面 200 但图形 404? 首轮 munin-cron 未跑或 URL 路径层级写错。容器内路径为 <htmldir>/<组名>/<主机名>/<插件名>-<日|周|月|年>.png,如 node2 的负载日图为 /munin/node2/node2/load-day.png(组名与主机名同名导致出现两层 node2);先跑 4.3 的首轮采集再核对 URL。

Q5:节点改了 IP 或加了节点怎么扩容? 三步:compose 文件复制一个 node 服务段(改 container_name/hostname/ipv4_address)→ munin.conf 追加对应 host 段 → docker compose up -d + 首轮采集。IPv4 固定在 10.89.60.0/24 内即可,无需动 ACL(网段已放行)。

Q6:想升级 Munin 到 2.0.75/2.0.76? 镜像 FROM 换 ubuntu:24.04(仓库 munin 2.0.75)或 ubuntu:25.10(2.0.76),tag 名与 compose image: 同步更新后重建;RRD 卷可跨版本复用(RRD 格式向下兼容),升级前建议 down 后对卷做备份(见十、运维命令)。

十二、参考链接