| name | test-minecraft-exporter |
| description | End-to-end docker-compose test harness for the minecraft-prometheus-exporter. Spins up an itzg/minecraft-server:latest vanilla server alongside a freshly built exporter and walks the user through verifying metrics in a live browser/Prometheus session. Use this skill whenever the user wants to "test the exporter end-to-end", "verify metrics against a real Minecraft server", "spin up a local MC server", "run the docker compose test", scrape /metrics from a vanilla MC server, or sanity-check a code change in this repo before opening a PR — including cases where the user just says "let me see if it works" or "run the exporter against MC" without naming the compose file. |
Test the minecraft-prometheus-exporter end-to-end
This is a runbook for booting docker-compose.test.yml and confirming the exporter scrapes a real Minecraft server. Run these steps in order from the repo root.
Files this skill depends on
Both live at the repo root and are checked into git:
docker-compose.test.yml — defines the minecraft (itzg/minecraft-server:latest, vanilla, RCON on, offline mode) and exporter services, plus a shared mc-data named volume so the exporter can read the world dir.
Dockerfile.dev — multi-stage golang:1.26-alpine → chainguard/static build of the exporter from source. Compose builds this image automatically with --build.
If either file is missing, do not improvise — flag it to the user. The compose setup has UID/volume specifics that are easy to get wrong.
1. Bring the stack up
docker compose -f docker-compose.test.yml up -d --build
First boot takes ~90 seconds because the vanilla MC server has to download the JAR (resolved from VERSION: LATEST) and generate a world. The compose file has a service_healthy dependency on the MC container's mc-health healthcheck, so the exporter will only start once MC is ready — but docker compose up returns earlier than that. Tell the user this is expected; subsequent boots are much faster.
2. Endpoints
Once both containers are up, tell the user:
3. Identify the MC version
VERSION: LATEST means "whatever itzg's image considers latest at pull time" — useful but not self-documenting. Show the user which version was resolved so they know which client to use:
docker exec mc-exporter-test-server bash -c 'ls /data/*.jar'
The jar filename embeds the version (e.g. minecraft_server.26.1.2.jar).
4. Connect a client
The server runs with ONLINE_MODE=FALSE, so any Java Edition client at the matching version can connect with any username — no Mojang/Microsoft auth needed. Just add a server pointed at localhost:25565.
Until a player connects at least once, MC doesn't create world/playerdata/, world/stats/, or world/advancements/. With an empty server, /metrics will only show minecraft_exporter_build_info. That's expected, not a bug.
5. Force a flush and inspect metrics
After the user has logged in and done a few things in-game (mine a block, walk around, jump), push MC to flush its in-memory stats:
docker exec mc-exporter-test-server rcon-cli save-all
Then re-scrape:
curl -s http://localhost:9150/metrics | grep '^minecraft_'
You should now see populated series — minecraft_blocks_mined_total, minecraft_jumps_total, minecraft_movement_meters_total{means="walk"}, minecraft_player_online{player="..."}, etc.
Quick sanity-check RCON too:
docker exec mc-exporter-test-server rcon-cli list
6. The label-name quirk
The compose sets MC_NAME_SOURCE=offline. This means:
- RCON-derived series (
minecraft_player_online) carry the readable player name (e.g. player="_diri"), because the RCON list command returns names directly.
- File-derived series (everything in
world/stats/, world/playerdata/, world/advancements/) carry the raw UUID (e.g. player="8d34c913-…"), because the exporter only resolves names when name-source is mojang (calls playerdb.co) or bukkit (reads bukkit.lastKnownName from NBT).
In vanilla + offline mode neither alternative works: the offline UUID isn't registered with Mojang, and vanilla doesn't write the Bukkit name field. So offline (UUID-as-label) is the only honest choice for this test stack. If the user wants names everywhere they need a real online server or a Paper/Spigot/Purpur server. Don't try to "fix" this by switching MC_NAME_SOURCE — it will silently make things worse.
7. Tear down
docker compose -f docker-compose.test.yml down -v
The -v flag wipes the mc-data volume, so the next run starts from a fresh world. Drop -v if the user wants to keep the world (and their player progress) between runs — first boot is the slow one, subsequent boots reuse the existing world and skip generation.
Troubleshooting
permission denied on /mc/world/playerdata in the exporter logs:
Confirm the exporter service in docker-compose.test.yml still has user: "1000:1000". The itzg image writes the world as UID 1000, and the chainguard/static base used by the exporter defaults to UID 65532, so without the UID override the read-only mount is unreadable. This is the single most likely thing to break if someone refactors the compose file.
Exporter starts before MC is ready and crashes on RCON dial:
Shouldn't happen — the compose file uses depends_on: minecraft: condition: service_healthy. If it does, check whether someone removed the healthcheck or the condition: block.
/metrics only ever shows minecraft_exporter_build_info:
No player has joined the server yet. Connect at least once, do something in-game, then rcon-cli save-all and re-scrape. The exporter has no synthetic mode — empty world means empty metrics.
MC won't pull a new version / boot loops:
VERSION: LATEST can occasionally lag behind a brand-new Minecraft release while itzg's image catches up. Pin to a specific version (e.g. VERSION: "1.21.4") in the compose file as a workaround.