Topic 05

Meet Harborline

Harborline

Harborline (harborline.example) is an online ferry-booking service, and it is the system this entire book instruments — the examples accumulate on it chapter after chapter instead of resetting. It is five Docker services on two Ubuntu VMs plus three backing stores, run by a team whose complete diagnostic toolkit today is ssh, docker logs, and htop.

This topic fixes the names, draws the map, and opens the wound the book spends seven chapters healing. Learn the names now — every scrape config, every query, and every alert from here to Chapter 14 uses them.

The Five Services

web is the customer-facing frontend: nginx serving a single-page app. bookings is the core API — Python/FastAPI behind gunicorn on port 8000 — and it is where checkout lives, which makes it the most instrumented service in the book. search handles schedule and route search on port 8001: the high-QPS, cache-heavy one, peaking around 300 requests per second on summer Saturdays.

payments, on port 8002, charges cards through a third-party processor whose published SLA is 99.95% — it has the lowest error tolerance of the five, because its errors cost money directly. And notifier is a background worker consuming a queue to send email and SMS, with no HTTP port at all. That last detail will matter more than it looks: most instrumentation tutorials quietly assume everything speaks HTTP, and notifier is the standing counterexample this book keeps returning to.

The Hosts and Stores

The services run on two application VMs, app-01 and app-02 (Ubuntu LTS, Docker). Behind them: PostgreSQL on db-01 holding bookings and payments data, Redis on cache-01 doing double duty as the search cache and a connection-pooled session store, and RabbitMQ on mq-01 feeding notifier. One more VM exists: obs-01, currently empty, reserved for the observability stack this book builds. Six machines' worth of names — that is the entire inventory, and it is worth memorizing.

Harborline — five services, three stores, one reserved host
app-01 & app-02 · Ubuntu LTS, Docker
Five serviceswebbookingssearchpaymentsnotifier
Backing stores & the reserved observability host
Three storesdb-01cache-01mq-01
Reservedobs-01

Why This Shape Generates the Book's Problems

Harborline is small, but its shape natively produces every story an observability book needs. Summer Saturdays triple the traffic — there is the spike story. Checkout crosses web → bookings → payments synchronously, so its latency is the sum of three services and two stores — there is the latency story, and the reason a per-service view will never explain a slow checkout. payments errors cost money directly — the error story. And notifier fails silently, because no user is standing there waiting for an email — the async-invisibility story, the one that check-based monitoring misses for weeks.

Checkout is synchronous — its latency is the sum of the path
web
bookings
payments

Flying Blind

Now the honest assessment of the current toolkit. docker logs shows one container's unstructured stdout — and the next deploy recreates the container and deletes it. htop shows this machine, right now, with no memory of an hour ago. ssh reaches one host at a time, and whatever an engineer finds there lives in their scrollback and nowhere else.

Run the three tools against the questions that matter and the pattern is total: none of them can answer anything about last Saturday, anything about a request that crossed services, or anything about a trend. No history, no cross-service view, no aggregation. By the new-question test of topic 01, Harborline is not observable — it is barely even monitored.

The Saturday Complaint

A customer writes in: checkout "sometimes takes forever" on Saturday mornings. Mara — the SRE who carries Harborline's pager, and who builds the stack through this book — cannot confirm the complaint happened, cannot count how often it happens, and cannot name a suspect among the five services. Saturday's evidence died with the last deploy's containers; Tuesday's htop shows a bored machine. Is it bookings? The Redis session store? The payment processor having a slow morning? Nothing on hand can even rank those guesses. This complaint is the book's opening wound. It stays open — deliberately — until the traces land in Chapter 8, and each chapter until then adds one instrument that narrows the search.

What Rises on obs-01

Here is the destination map, so the build-out ahead has a shape. Onto obs-01, via Compose: Prometheus (:9090), Grafana (:3000), Loki (:3100), Tempo (:3200), and Alertmanager (:9093). Onto every host: node_exporter (:9100) and Grafana Alloy as the local agent. By Chapter 10 this stack carries a real SLO — 99.9% checkout availability over a 28-day window, with 95% of checkout requests under 500 ms — and the Saturday complaint has become a number on a burn-rate chart instead of a rumor in a support ticket.

Common Mistakes
  • Relying on docker logs with no log-driver or rotation configuration — the next deploy recreates the bookings container and deletes the only record of Saturday morning, which is precisely the evidence Mara needed.
  • Debugging an intermittent problem by watching htop live — it shows the machine now, so a spike that ended three hours ago leaves no trace, and staring at a quiet Tuesday proves nothing about a loaded Saturday.
  • Investigating via ad-hoc ssh and one-off greps — the findings live in one engineer's scrollback, the method is unrepeatable at 02:40 by anyone else, and nothing accumulates between incidents.
  • Closing the ticket as "cannot reproduce" — an issue that only appears at 3× Saturday load will never reproduce under a Tuesday curl, and no-repro is a statement about the test, not the system.
  • Planning to run the observability stack on app-01 "to save a VM" — when the app hosts are in trouble is exactly when you need the telemetry, and co-hosting means the observer dies with the observed.
Best Practices
  • Write down the questions the team cannot currently answer — "is the Saturday complaint real, how often, where" — before choosing any tool, and let that list drive the build order.
  • Keep a living inventory of services, hosts, and ports — this topic is Harborline's. It becomes the scrape config, the dashboard layout, and the alert routing table in later chapters.
  • Give the observability stack its own host (obs-01), isolated from application failure domains, so the telemetry survives the incidents it exists to explain.
  • Start instrumenting at the business transaction — checkout across web → bookings → payments — and work down toward host metrics, because that is the path from complaint to answer.
Comparable toolsOfficial demo OpenTelemetry Demo (Astronomy Shop) — the ecosystem's multi-service instrumentation targetKubernetes-era Online Boutique, Sock Shop — the same canonical-demo role for cluster tutorials

Knowledge Check

What can none of ssh, docker logs, and htop answer, regardless of skill?

  • What a container is printing right now
  • Questions about last Saturday, cross-service requests, or trends
  • Which process is using the most CPU on this machine at this instant
  • Whether all five containers are currently running

The Saturday checkout issue never reproduces when engineers test on Tuesday. What does "cannot reproduce" actually establish?

  • That the complaint was mistaken and the ticket can close, since the curl returned 200
  • That the problem must be in the web frontend
  • That intermittent problems are not real problems
  • That the test conditions did not match the failure conditions

Why does the observability stack get its own VM instead of sharing app-01?

  • Prometheus needs more CPU than the app services allow
  • So the telemetry survives the incidents it exists to explain
  • Because the observability ports would conflict with gunicorn
  • Grafana's license requires a dedicated machine

Which Harborline service is the standing counterexample to HTTP-centric instrumentation tutorials, and why?

  • search, because its cache makes requests invisible
  • payments, because the third-party processor hides its traffic
  • notifier, because it consumes a queue and has no HTTP port
  • web, because nginx cannot be instrumented

You got correct