Production-ready Docker Compose stack running Glowroot Central Collector backed by Apache Cassandra. Designed for Linux hosts, plug-and-play deployment, fully configurable through environment variables.
- Overview
- Architecture
- Prerequisites
- Quick Start
- Configuration
- Service Details
- Agent Installation
- Day-to-Day Operations
- Backup and Restore
- Upgrading
- Performance Tuning
- Security Hardening
- Troubleshooting
- FAQ
Glowroot is an open-source Java APM (Application Performance Monitoring) tool. In central mode, multiple Glowroot agents (one per monitored JVM) stream trace data to a Central Collector, which persists everything in Cassandra and exposes a web UI for analysis.
This repository provides:
- A hardened
docker-compose.yamlwith healthchecks, resource limits, log rotation, and proper startup ordering. - A single
.envfile for all tunable parameters (heap sizes, ports, versions, memory limits). - Sane defaults that work on a typical 8 GB Linux server out of the box.
+-------------------+ +---------------------+ +------------------+
| Java App + Agent | ----> | Glowroot Central | ----> | Cassandra |
| (port 8181/HTTP2) | | (UI: 4000) | | (internal 9042) |
+-------------------+ +---------------------+ +------------------+
|
v
Web Browser :4000
- Cassandra stores all collected trace, aggregate, and gauge data. Its CQL port (9042) is not published to the host; only the Glowroot container can reach it through the internal Docker network
glowroot_net. - Glowroot Central exposes two ports:
4000— Web UI (HTTP).8181— Agent collector endpoint (HTTP/2 over plaintext by default).
- A bridge network isolates inter-container traffic.
- Two named volumes (
cassandra_data,glowroot_data) persist state across container restarts and image upgrades.
| Requirement | Minimum Version |
|---|---|
| Linux kernel | 4.x (any modern distribution) |
| Docker Engine | 20.10+ |
| Docker Compose | v2 (the docker compose CLI) |
| RAM | 8 GB (with default heap settings) |
| Disk | 20 GB free (grows with retention) |
| CPU | 2 cores minimum, 4+ recommended |
Verify:
docker --version
docker compose version
free -h
df -h .# 1. Clone the repository
git clone <your-repo-url>
cd Glowroot
# 2. (Optional) review and customize defaults
nano .env
# 3. Bring the stack up
docker compose up -d
# 4. Watch Cassandra become healthy (~60-90 seconds on first boot)
docker compose ps
docker compose logs -f cassandra
# 5. Once Cassandra is healthy, Glowroot starts automatically.
# Open the UI:
xdg-open http://localhost:4000 # or just visit it in your browserOn first launch Glowroot creates the Cassandra keyspace glowroot and schema automatically. No manual database setup is required.
All tunable values live in the .env file at the repository root. Compose reads it automatically.
| Variable | Default | Description |
|---|---|---|
GLOWROOT_VERSION |
0.14.2 |
Image tag for glowroot/glowroot-central. |
GLOWROOT_UI_PORT |
4000 |
Host port published for the web UI. |
GLOWROOT_AGENT_PORT |
8181 |
Host port published for the agent (HTTP/2) endpoint. |
CASSANDRA_CLUSTER_NAME |
GlowrootCluster |
Cassandra cluster name (must match across nodes if scaled). |
CASSANDRA_DC |
dc1 |
Cassandra datacenter name. |
CASSANDRA_RACK |
rack1 |
Cassandra rack name. |
CASSANDRA_HEAP_NEW |
512M |
Young generation heap size for Cassandra JVM. |
CASSANDRA_HEAP_MAX |
4G |
Maximum Java heap for Cassandra. |
CASSANDRA_MEM_LIMIT |
6G |
Container-level memory limit for Cassandra. |
GLOWROOT_HEAP_MIN |
2G |
-Xms for Glowroot JVM. |
GLOWROOT_HEAP_MAX |
4G |
-Xmx for Glowroot JVM. |
GLOWROOT_MEM_LIMIT |
6G |
Container-level memory limit for Glowroot. |
Rule of thumb: HEAP_MAX should be roughly 60-75% of MEM_LIMIT to leave room for off-heap memory (direct buffers, metaspace, native libraries, page cache).
After editing .env, apply changes:
docker compose up -dOnly containers whose configuration changed will be recreated.
- Image:
cassandra:4.1(pinned to the 4.1.x LTS line). - Persistence:
cassandra_datavolume mounted at/var/lib/cassandra. - Networking: only reachable inside
glowroot_net. Port 9042 is declared withexpose(documentation), notports(publish), so the host firewall does not need to block it. - Healthcheck:
nodetool status | grep '^UN'— passes once the node reports itself as Up/Normal. Glowroot waits for this before starting. - Tuning applied:
MAX_HEAP_SIZEandHEAP_NEWSIZEexported via env so the official entrypoint sets them incassandra-env.sh.CASSANDRA_ENDPOINT_SNITCH=GossipingPropertyFileSnitch(recommended for production over the defaultSimpleSnitch).ulimits.memlock=-1andnofile=100000to avoid swap and file-descriptor exhaustion.stop_grace_period: 2mto allow a clean shutdown (flushing memtables).
- Image:
glowroot/glowroot-central:${GLOWROOT_VERSION}. - Persistence:
glowroot_datavolume mounted at/glowroot-central(config, admin credentials, TLS material). - Networking: ports
4000(UI) and8181(agent) published to the host. - Startup ordering:
depends_on.cassandra.condition: service_healthy— Glowroot will not start until Cassandra reports healthy, eliminating a common race condition. - JVM flags (
JAVA_OPTS):-XX:+UseContainerSupport— respects container memory limits.-XX:+UseG1GC— low-pause garbage collector suitable for collectors.-Xmsand-Xmxset from.env.-XX:+ExitOnOutOfMemoryError— fail fast on OOM so Docker restarts the container instead of running degraded.
networks:
glowroot_net:
driver: bridge # standard isolated bridge network
volumes:
cassandra_data: # Cassandra SSTables, commit log, system tables
glowroot_data: # Glowroot config and local stateBoth volumes use the default local driver, which stores data under /var/lib/docker/volumes/ on the host. To inspect them:
docker volume ls | grep glowroot
docker volume inspect glowroot_cassandra_dataAll services use the json-file log driver with rotation:
max-size: 10mper log filemax-file: 5rotated files retained
This caps each container's log usage at roughly 50 MB and prevents log files from filling the disk.
View logs:
docker compose logs -f --tail=200 glowroot
docker compose logs -f --tail=200 cassandraOn every JVM you want to monitor:
-
Download the Glowroot agent matching the central collector version from the Glowroot releases page.
-
Unzip somewhere (for example
/opt/glowroot). -
Edit
/opt/glowroot/glowroot.properties:collector.address=http://<central-host>:8181 agent.id=my-service::production
collector.addressmust be reachable from the application JVM.agent.idis a free-form string; convention is<service-name>::<environment>.
-
Add the agent to your JVM launch arguments:
java -javaagent:/opt/glowroot/glowroot.jar -jar your-app.jar
-
Restart your application. Within a minute it appears in the Glowroot UI's agent dropdown.
For containerized applications, mount the agent directory and pass -javaagent through JAVA_TOOL_OPTIONS or your image's entrypoint.
# Service status and health
docker compose ps
# Follow logs
docker compose logs -f glowroot
docker compose logs -f cassandra
# Restart a single service (Glowroot, no data loss)
docker compose restart glowroot
# Stop everything (containers stopped, volumes preserved)
docker compose stop
# Start again
docker compose start
# Remove containers and network (volumes preserved)
docker compose down
# Remove containers AND volumes (DESTROYS ALL DATA)
docker compose down -v
# Exec into a running container
docker compose exec cassandra cqlsh
docker compose exec glowroot sh
# Check Cassandra cluster health
docker compose exec cassandra nodetool status
docker compose exec cassandra nodetool infoCassandra supports atomic snapshots while the database is running:
# Trigger snapshot
docker compose exec cassandra nodetool snapshot glowroot -t backup-$(date +%F)
# Copy snapshot files to host
docker compose exec cassandra sh -c 'cd /var/lib/cassandra/data/glowroot && tar czf - */snapshots/backup-*' \
> glowroot-snapshot-$(date +%F).tar.gz
# Clean up snapshot inside the container
docker compose exec cassandra nodetool clearsnapshot glowroot -t backup-$(date +%F)Requires stopping the stack:
docker compose stop
docker run --rm \
-v glowroot_cassandra_data:/data:ro \
-v "$(pwd)":/backup \
alpine tar czf /backup/cassandra-$(date +%F).tar.gz -C /data .
docker compose startdocker compose down
docker volume rm glowroot_cassandra_data
docker volume create glowroot_cassandra_data
docker run --rm \
-v glowroot_cassandra_data:/data \
-v "$(pwd)":/backup \
alpine sh -c 'cd /data && tar xzf /backup/cassandra-YYYY-MM-DD.tar.gz'
docker compose up -d# 1. Edit .env, bump GLOWROOT_VERSION (e.g. to 0.14.7)
# 2. Pull the new image
docker compose pull glowroot
# 3. Recreate the container
docker compose up -d glowroot
# 4. Verify
docker compose logs -f glowrootGlowroot performs any required schema migrations on startup. Roll back by reverting GLOWROOT_VERSION and recreating.
Minor patch upgrades inside the same major version (e.g. 4.1.5 → 4.1.9) are usually safe via docker compose pull cassandra && docker compose up -d cassandra. For major version jumps (e.g. 4.1 → 5.0), consult the official Cassandra upgrade documentation, as SSTable format changes may require nodetool upgradesstables and a documented procedure.
- For a single-node Glowroot deployment monitoring up to a few dozen JVMs,
4Gheap is sufficient. - For larger fleets, increase
CASSANDRA_HEAP_MAX(up to ~16G — beyond that, G1 pauses become a concern; consider multi-node clusters). - Keep heap size at most 50% of container memory; the rest is used by off-heap structures (bloom filters, key cache, compaction buffers) and Linux page cache for SSTables.
- Glowroot's memory footprint scales with the number of connected agents and trace volume.
- For 10–50 agents: 2–4 GB heap is typical.
- For 100+ agents: increase to 8–16 GB and monitor GC behavior via the JMX port (not exposed by default).
Cassandra is I/O sensitive. For production deployments:
- Use SSDs, ideally NVMe.
- Mount the Docker volume root (
/var/lib/docker) on a fast disk, or change the volumedriver_optsto point to a dedicated mount.
Glowroot data retention is configured in the UI under Configuration > Storage. Reducing retention lowers Cassandra disk usage.
The default configuration is suitable for a trusted internal network. For internet-facing or sensitive deployments:
-
Set an admin password immediately. In the UI: Configuration > Users > admin > Change password. Or pre-seed by exec'ing into the container before first browser visit:
docker compose exec glowroot java -jar glowroot-central.jar setup-admin-user admin <strong-password>
-
Enable HTTPS for the UI. Place
ui-cert.pemandui-key.peminside theglowroot_datavolume and setui.https=trueinglowroot-central.properties. Alternatively, terminate TLS at a reverse proxy (nginx, Traefik, Caddy) in front of port 4000. -
Restrict the agent port (8181) with host firewall rules so only your application subnets can reach it:
sudo ufw allow from 10.0.0.0/8 to any port 8181 sudo ufw deny 8181
-
Enable Cassandra authentication if you ever expose port 9042. By default it is internal-only in this stack; do not change that unless necessary.
-
Run regular image updates to pick up security patches:
docker compose pull docker compose up -d
docker compose logs --tail=200 glowrootCommon causes:
- Cassandra not yet healthy. Wait 60–90 seconds on first boot. Check with
docker compose exec cassandra nodetool status— you should see a single line beginning withUN. - OOM (
-XX:+ExitOnOutOfMemoryErrortriggered). IncreaseGLOWROOT_HEAP_MAXin.env, thendocker compose up -d glowroot. - Cassandra schema corruption after improper shutdown. As a last resort,
docker compose down -vand re-import from a backup.
docker compose exec cassandra nodetool status
docker compose logs --tail=200 cassandraLook for Starting listening for CQL clients. If the node is stuck on bootstrap, check disk space (df -h) and available memory (free -h).
Error: bind: address already in use
Change GLOWROOT_UI_PORT or GLOWROOT_AGENT_PORT in .env and re-run docker compose up -d.
- Verify connectivity from the agent host:
curl -v http://<central-host>:8181(you should see an HTTP/2 upgrade response). - Check the application log for
Glowroot startedand any collector errors. - Confirm
agent.idis unique — agents sharing an id collapse into a single entry.
docker compose exec cassandra df -h /var/lib/cassandra
docker compose exec cassandra nodetool tablestats glowrootLower data retention in the Glowroot UI, then run nodetool cleanup and nodetool compact glowroot.
Can I run this on Windows or macOS? Docker Desktop on Windows/macOS works for evaluation, but production deployments should use Linux. WSL2 path mapping and Docker Desktop's resource limits make it a poor fit for sustained APM workloads.
Can I scale Cassandra to multiple nodes?
Yes, but not with this single-host compose file. For multi-node clusters, deploy Cassandra on dedicated infrastructure (or Kubernetes via the Cassandra operator) and point CASSANDRA_CONTACT_POINTS in the glowroot service to that cluster.
Can I scale Glowroot Central horizontally? Yes — multiple Glowroot Central instances can share the same Cassandra cluster. Place them behind a load balancer and point agents at the load balancer hostname. Sessions are stateless on the agent endpoint.
Where does Glowroot store its configuration?
In Cassandra, not in the glowroot_data volume. The volume only holds the Glowroot startup config, admin password file, and optional TLS material.
How do I reset the admin password?
docker compose exec glowroot java -jar glowroot-central.jar setup-admin-user admin <new-password>
docker compose restart glowrootDoes this work behind a corporate proxy?
Yes for outbound traffic during docker compose pull. Set HTTP_PROXY / HTTPS_PROXY in your Docker daemon config. The Glowroot agent itself does not need a proxy because it talks directly to the central collector inside your network.