Graphite 1.1.10 Docker Compose 部署指南
官方一体化镜像 graphiteapp/graphite-statsd:1.1.10-5 的 Compose 从零部署:栈健康检查、端口规划、数据持久化、2003 明文打点与 statsd UDP 埋点端到端验证、render API 与 Web UI 曲线确认及常见问题排障。
Graphite 1.1.10 Docker Compose 部署指南
目标:在一台 Ubuntu 服务器上用官方一体化镜像
graphiteapp/graphite-statsd:1.1.10-5完成从零到可用的 Graphite 监控系统部署:Compose 编排、服务健康检查、向 carbon 2003 端口打点、并通过 render API 与 Web UI 端到端验证曲线数据。全文命令与回显均在 Ubuntu 22.04.4 LTS + Docker Compose v5.5.1 环境实测通过。
一、环境信息
- 操作系统:Ubuntu 22.04.4 LTS(x86_64)
- Docker Engine:29.8.1;Docker Compose:v5.5.1(
docker compose插件形态) - Graphite 版本:graphite-web / carbon / whisper 三件套 1.1.10,官方一体化镜像
graphiteapp/graphite-statsd:1.1.10-5(镜像内含 nginx、graphite-web、carbon-cache、carbon-aggregator、statsd,由 runit 托管) - 部署目录:
/opt/graphite-deploy(本文示例根目录,下同) - 服务端口规划:Web
8128、carbon 明文8129、carbon pickle8132、statsd UDP8133(宿主侧端口可按实际情况替换,容器内端口见环境变量表后的端口表)
二、镜像选型说明
Graphite 官方维护三种部署产物(来源:docker-graphite-statsd README,查询日期 2026-10-20):
| 方案 | 产物 | 适用 |
|---|---|---|
| 一体化镜像 | graphiteapp/graphite-statsd | 单机快速部署,一个服务包含全部组件(本文采用) |
| 分组件安装 | pip 包 / 源码(graphite-web、carbon、whisper 各自独立) | 需要多机分拆、精细控制进程的大型部署 |
| 实验特性 | 镜像内 GOCARBON=1(go-carbon 替换 carbon)、BRUBECK=1(brubeck 替换 statsd) | 特性评估,不建议生产 |
一体化镜像选择理由:官方出品(graphite-project 组织)、1.1.10-5 为该版本的最新稳定构建、Alpine 底座体积可控、内置 runit 与 healthcheck 所需工具,对单机部署与评估最友好。本镜像最新稳定 tag 为 1.1.10-5;latest 指向同一稳定线(2023-07-09 构建),master 为不稳定开发版,生产固定具体版本号。
三、前置条件
- 服务器已安装 Docker Engine 与 Compose 插件,验证:
docker --version
实测回显:
Docker version 29.8.1, build 4a63305
docker compose version
实测回显:
Docker Compose version v5.5.1
- 服务器可拉取 Docker Hub 镜像(内网环境请提前配置镜像加速或代理)。
- 规划端口未被占用,验证(本例 8128/8129/8132/8133):
ss -ltn | grep -E ':8128|:8129|:8132'
实测回显(无输出即空闲;若被占用请更换宿主端口,容器端口不变)。
四、部署步骤
4.1 创建部署目录
mkdir -p /opt/graphite-deploy/graphite/{conf,storage,statsd}
cd /opt/graphite-deploy
三个子目录分别对应镜像内的配置、whisper 数据、statsd 配置挂载点,首次启动为空目录时由镜像 entrypoint 自动初始化默认配置。
4.2 编写 docker-compose.yml
在 /opt/graphite-deploy 下创建 docker-compose.yml:
name: graphite-1.1.10-stack
services:
graphite:
image: graphiteapp/graphite-statsd:1.1.10-5
container_name: graphite-1.1.10-web
hostname: graphite-server
restart: unless-stopped
ports:
- "8128:80"
- "8129:2003"
- "8132:2004"
- "8133:8125/udp"
environment:
- GRAPHITE_TIME_ZONE=Asia/Shanghai
volumes:
- ./graphite/conf:/opt/graphite/conf
- ./graphite/storage:/opt/graphite/storage
- ./graphite/statsd:/opt/statsd/config
networks:
- graphite-net
healthcheck:
test: ["CMD-SHELL", "wget -q -O /dev/null http://127.0.0.1:8080/ || exit 1"]
interval: 15s
timeout: 5s
retries: 6
start_period: 60s
networks:
graphite-net:
driver: bridge
ipam:
config:
- subnet: 10.89.57.0/24
关键项说明:
name: graphite-1.1.10-stack:显式声明 Compose 项目名,避免多套部署共用目录名导致互相覆盖;container_name/hostname:固定实例名与主机名,carbon 内部指标路径默认使用主机名(carbon.agents.graphite-server-a.*),固定后指标名不漂移;healthcheck:通过访问 8080(gunicorn 直连端口)判断 Web 服务是否就绪,Alpine 自带 busybox wget;- 网络 subnet:多套监控栈并存时显式指定网段,避免与既有 Docker 网络冲突;
- 端口映射:宿主端口全部可自定义,容器内端口固定(见 4.4 端口表)。
4.3 启动并确认健康
docker compose up -d
实测回显:
[+] Running 2/2
✔ Network graphite-1.1.10-stack_graphite-net Created
✔ Container graphite-1.1.10-web Started
首次启动需要初始化配置与 Django 数据库,等待约 1 分钟后确认状态:
docker compose ps
实测回显:
NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS
graphite-1.1.10-web graphiteapp/graphite-statsd:1.1.10-5 "/entrypoint" graphite 50 seconds ago Up 50 seconds (healthy) 2013-2014/tcp, 2023-2024/tcp, 8080/tcp, 8125-8126/tcp, 0.0.0.0:8128->80/tcp, [::]:8128->80/tcp, 0.0.0.0:8129->2003/tcp, [::]:8129->2003/tcp, 0.0.0.0:8132->2004/tcp, [::]:8132->2004/tcp, 0.0.0.0:8133->8125/udp, [::]:8133->8125/udp
STATUS 出现 Up (healthy) 即健康检查通过。若长时间停留在 health: starting,查看启动日志:
docker compose logs graphite | tail -20
实测回显(节选,正常应出现各服务的 runit OK 行):
graphite-1.1.10-web | graphite-web: OK
graphite-1.1.10-web | carbon-cache: OK
graphite-1.1.10-web | carbon-aggregator: OK
graphite-1.1.10-web | statsd: OK
graphite-1.1.10-web | nginx: OK
4.4 端口表
| 宿主端口(本例) | 容器端口 | 服务 | 协议 |
|---|---|---|---|
| 8128 | 80 | nginx(graphite-web 反向代理入口) | TCP |
| 8129 | 2003 | carbon-cache 明文行协议接收 | TCP |
| 8132 | 2004 | carbon-cache pickle 批量接收 | TCP |
| 8133 | 8125 | statsd 指标接收 | UDP |
| 未映射 | 8080 | graphite-web gunicorn 直连端口(healthcheck 用) | TCP |
| 未映射 | 8126 | statsd 管理接口 | TCP |
| 未映射 | 2013/2014 | carbon-relay(默认未启用) | TCP |
| 未映射 | 2023/2024 | carbon-aggregator(默认启用) | TCP |
4.5 验证 Web 服务
curl -sS -o /dev/null -w '%{http_code}\n' http://127.0.0.1:8128/
实测回显:
200
curl -sS http://127.0.0.1:8128/ | grep -oE '<title>[^<]*</title>'
实测回显:
<title>Graphite Browser</title>
登录页验证(默认管理员账号 root,初始密码 root,首次登录后请立即在 /admin/password_change/ 修改):
curl -sS -o /dev/null -w '%{http_code}\n' http://127.0.0.1:8128/account/login
实测回显:
200
浏览器访问 http://<服务器IP>:8128/ 进入 Graphite Browser 图表界面,/dashboard 进入仪表盘编辑器。
五、数据持久化说明
数据全部落在宿主三个 bind mount 目录,重启/重建服务不丢数据:
| 宿主目录 | 容器路径 | 内容 |
|---|---|---|
| ./graphite/conf | /opt/graphite/conf | carbon.conf、storage-schemas.conf 等 12 个配置文件(首次启动自动生成) |
| ./graphite/storage | /opt/graphite/storage | whisper 指标数据(whisper/)、Django 元数据库(graphite.db)、各服务 pid |
| ./graphite/statsd | /opt/statsd/config | statsd 的 udp.js/tcp.js 配置(空目录时用内置默认) |
首次启动后确认宿主侧配置已生成:
ls /opt/graphite-deploy/graphite/conf/
实测回显:
aggregation-rules.conf blacklist.conf carbon.amqp.conf carbon.conf
dashboard.conf go-carbon.conf graphTemplates.conf relay-rules.conf
rewrite-rules.conf storage-aggregation.conf storage-schemas.conf whitelist.conf
whisper 数据目录结构(指标路径映射为子目录层级):
find /opt/graphite-deploy/graphite/storage/whisper -name '*.wsp' | head -6
实测回显(碳服务自监控指标在启动后即产生):
/opt/graphite-deploy/graphite/storage/whisper/carbon/agents/graphite-server-a/creates.wsp
/opt/graphite-deploy/graphite/storage/whisper/carbon/agents/graphite-server-a/errors.wsp
/opt/graphite-deploy/graphite/storage/whisper/carbon/agents/graphite-server-a/metricsReceived.wsp
/opt/graphite-deploy/graphite/storage/whisper/carbon/agents/graphite-server-a/timings/create.wsp
/opt/graphite-deploy/graphite/storage/whisper/carbon/agents/graphite-server-a/timings/updateOperation.wsp
/opt/graphite-deploy/graphite/storage/whisper/carbon/agents/graphite-server-a/updateOperations.wsp
六、环境变量表
镜像通过环境变量覆盖 carbon.conf / local_settings.py / statsd 配置(来源:docker-graphite-statsd README「Tunables」节,默认值为 README 原文),常用项:
| 环境变量 | 默认值 | 说明 |
|---|---|---|
| GRAPHITE_TIME_ZONE | Etc/UTC | Django 时区 |
| GRAPHITE_ALLOWED_HOSTS | * | Django 允许的 Host |
| GRAPHITE_WSGI_PROCESSES | 4 | gunicorn worker 进程数 |
| GRAPHITE_WSGI_THREADS | 1 | 每 worker 线程数 |
| GRAPHITE_WSGI_REQUEST_TIMEOUT | 65 | 请求超时秒数 |
| GRAPHITE_DEFAULT_CACHE_DURATION | 60 | 查询结果缓存秒数 |
| GRAPHITE_CARBONLINK_HOSTS | 127.0.0.1:7002 | carbonlink 缓存查询地址 |
| GRAPHITE_UTF8_METRICS | false | 允许 UTF-8 指标名(有性能代价) |
| CARBON_DISABLE_TAGS | false | 置 1 关闭 carbon 的 TagDB |
| REDIS_TAGDB | false | 置 1 用内置 Redis 存 TagDB |
| MEMCACHE_HOST | 未设 | 配置后启用 Memcached 查询缓存 |
| STATSD_INTERFACE | udp | 置 tcp 让 statsd 监听 TCP 8125 |
| RELAY | 未设 | 置 1 启用 carbon-relay |
| COLLECTD | 未设 | 置 1 启用内置 collectd 自监控 |
| <服务名>_DISABLED | 未设 | 置 1 关闭对应 runit 服务(如 CARBON_AGGREGATOR_DISABLED=1) |
七、端到端验证:打点 → 查询曲线
7.1 向 carbon 2003 端口打点
明文行协议格式:<指标路径> <值> <UNIX时间戳>,用 nc 直接推送:
now=$(date +%s)
for i in 1 2 3 4 5 6; do
t=$((now - (6 - i) * 10))
echo "servers.web1.requests $((i * 10)) $t" | nc -w 2 127.0.0.1 8129
done
carbon-cache 先入内存缓存再刷盘,等待约 5 秒后可查询。
7.2 render API 查询数据
curl -sS 'http://127.0.0.1:8128/render?target=servers.web1.requests&from=-2min&format=json'
实测回显(打点 6 个,全为非空数据点):
[{"target": "servers.web1.requests", "tags": {"name": "servers.web1.requests"}, "datapoints": [[10.0, 1792471260], [20.0, 1792471270], [30.0, 1792471280], [40.0, 1792471290], [50.0, 1792471300], [60.0, 1792471310], [null, 1792471320], [null, 1792471330], [null, 1792471340], [null, 1792471350], [null, 1792471360]]}]
点已从 carbon-cache 写入 whisper 并被 render API 读回,写路径与读路径全部打通。
7.3 指标发现 API 验证
curl -sS 'http://127.0.0.1:8128/metrics/find?query=servers.*'
实测回显:
[{"text": "web1", "id": "servers.web1", "allowChildren": 1, "expandable": 1, "leaf": 0}, {"text": "web2", "id": "servers.web2", "allowChildren": 1, "expandable": 1, "leaf": 0}]
curl -sS 'http://127.0.0.1:8128/metrics/index.json' | python3 -c 'import json,sys; m=json.load(sys.stdin); print(len(m), "metrics"); print(m[0])'
实测回显:
125 metrics
carbon.agents.graphite-server-a.activeConnections
7.4 statsd UDP 打点验证
counter 类型报文 key:value|c,用 nc 推 UDP:
for i in 1 2 3 4 5; do
echo -n "s7demo.pageview:$((i * 7))|c" | nc -w 1 -u 127.0.0.1 8133
done
statsd 每 10 秒 flush 一次(刷新周期由 /opt/statsd/config/udp.js 的 flushInterval 决定),等待后查询:
curl -sS 'http://127.0.0.1:8128/render?target=stats.s7demo.pageview&from=-5min&format=json'
实测回显(statsd 聚合出的速率值):
[{"target": "stats.s7demo.pageview", "datapoints": [[0.7, 1792471380], [9.8, 1792471390], [null, ...]}]
⚠️ 注意:statsd 的 flushInterval(默认 10 秒)必须不小于 storage-schemas.conf 中最高精度归档的间隔,否则聚合错位。默认 schema
10s:6h,...与默认 10 秒 flush 恰好匹配。
7.5 Web UI 查看曲线
浏览器打开 http://<服务器IP>:8128/,左侧 Composer 的 Graphite Metrics 树中展开 servers → web1 → requests 点击即出现曲线;或直接访问:
http://<服务器IP>:8128/render?target=servers.web1.requests&from=-10min
返回 PNG 曲线图即验证完成。
八、等价 docker run 命令
与上述 compose 等价的单命令启动(官方 README 原始形态,按本文端口规划改写):
docker run -d \
--name graphite-1.1.10-web \
--restart=always \
-p 8128:80 \
-p 8129:2003 \
-p 8132:2004 \
-p 8133:8125/udp \
-v /opt/graphite-deploy/graphite/conf:/opt/graphite/conf \
-v /opt/graphite-deploy/graphite/storage:/opt/graphite/storage \
-v /opt/graphite-deploy/graphite/statsd:/opt/statsd/config \
-e GRAPHITE_TIME_ZONE=Asia/Shanghai \
graphiteapp/graphite-statsd:1.1.10-5
九、常用运维命令
docker compose ps # 栈状态与健康检查
docker compose logs -f graphite # 跟踪全部 runit 服务日志
docker compose stop # 停栈(保留容器)
docker compose start # 再启动
docker compose down # 删容器与网络(数据在宿主 bind mount 不丢)
docker compose up -d # 变更 compose 后重建
修改配置(conf 目录下任一文件,如 storage-schemas.conf)后,重启栈生效:
docker compose restart graphite
十、常见问题
Q1:栈一直 health: starting 或 unhealthy?
healthcheck 访问的是容器内 8080 gunicorn 端口。进入容器排障:docker compose exec graphite wget -q -O- http://127.0.0.1:8080/,若报错查看 /var/log/graphite/exception.log;常见原因是宿主内存过小导致 gunicorn 被 OOM 杀,可用 GRAPHITE_WSGI_PROCESSES=2 降进程数。
Q2:打点成功但查询全为 null?
carbon-cache 默认缓存刷盘有秒级延迟,打点后等 5–10 秒再查;仍为空则确认时间戳是 UNIX 秒且未写未来时间,并检查 storage-schemas.conf 是否保留了你打点的时间范围。
Q3:宿主端口冲突如何改? 只改 compose 中冒号左侧的宿主端口即可,容器内端口(80/2003/2004/8125)固定不动;UDP 8125 对应 statsd 埋点,漏映射会导致 stats.* 指标收不到。
Q4:忘记 Web 管理员密码?
默认账号 root/root;修改入口是 Web 界面 /admin/password_change/。遗忘后可删除 graphite/storage/graphite.db(Django 元数据库,不含指标数据)后重启栈重新初始化,同时重建管理员。
Q5:磁盘写满有什么表现?
whisper 预分配文件写满失败时 carbon 日志出现 Disk I/O error,carbon.agents.*.errors 指标升高。whisper 文件是固定大小,磁盘不足主要发生在新建指标时(MAX_CREATES_PER_MINUTE 同时受 CPU 限制),扩容磁盘后 docker compose restart graphite 恢复。
十一、参考链接
- 官方一体化镜像仓库与 README(端口表/环境变量/runit 说明):https://github.com/graphite-project/docker-graphite-statsd
- Graphite 官方文档安装章节:https://graphite.readthedocs.io/en/latest/install.html
- feeding-carbon(明文/pickle 协议):https://graphite.readthedocs.io/en/latest/feeding-carbon.html
- 本库系列:《Graphite 1.1.10 介绍与选型指南》《Graphite 1.1.10 配置参数详解》《Graphite 1.1.10 常用 CLI 命令与工具详解》