Introduction
Spring PetClinic is a well-known sample application built with Spring Boot and Spring Cloud. What makes it interesting from a DevOps perspective is that it is not a single application — it is a distributed system made up of 8 separate microservices that all need to work together. Each service has its own responsibility, its own port, and its own dependencies.
As part of my DMI Cohort 2 final project, I deployed the full Spring PetClinic Microservices stack locally on my Ubuntu Linux machine using Docker Compose. In this post I will walk you through exactly how I did it, what broke along the way, and what the observability stack showed me once everything was running.
Prerequisites
Before starting, make sure you have the following installed on your machine:
Docker — version 29.6.1 or later. Verify with: docker --version
Docker Compose — included with modern Docker installations
Git — to clone the repository
A stable internet connection — the config-server fetches configuration from GitHub on startup
Step 1 — Clone the Repository
git clone https://github.com/ossyzali/spring-petclinic-microservices.git
cd spring-petclinic-microservices
Verify the contents:
ls spring-petclinic-microservices
You should see folders for each microservice — spring-petclinic-api-gateway, spring-petclinic-customers-service, spring-petclinic-vets-service, spring-petclinic-visits-service, and more — along with the docker-compose.yml file.
Step 2 — Start Everything with One Command
docker compose up -d
This single command does everything — pulls all the Docker images, builds the custom Prometheus and Grafana images, creates the network, and starts all 11 containers. The -d flag runs everything in the background.
After a few minutes verify all containers are running:
docker compose ps
You should see all 11 containers with status Up:
admin-server Up 0.0.0.0:9090->9090/tcp
api-gateway Up 0.0.0.0:8080->8080/tcp
config-server Up 0.0.0.0:8888->8888/tcp (healthy)
customers-service Up 0.0.0.0:8081->8081/tcp
discovery-server Up 0.0.0.0:8761->8761/tcp (healthy)
genai-service Up 0.0.0.0:8084->8084/tcp
grafana-server Up 0.0.0.0:3030->3000/tcp
prometheus-server Up 0.0.0.0:9091->9090/tcp
tracing-server Up 0.0.0.0:9411->9411/tcp (healthy)
vets-service Up 0.0.0.0:8083->8083/tcp
visits-service Up 0.0.0.0:8082->8082/tcp
Step 3 — The Startup Order and Why It Matters
This was the most important lesson I learned during this deployment. Not all services can start at the same time. The depends_on setting in docker-compose.yml controls the startup order.
Config Server must start first. It holds the configuration for every other service — database settings, port numbers, application properties. Without it, every other service has nothing to read its settings from and crashes immediately on startup.
Discovery Server must start second. It is the Eureka service registry. Every microservice registers itself with Eureka when it starts so they can find each other on the network. Without it, services cannot communicate.
I experienced this first-hand. My discovery-server kept crashing with a ConfigClientFailFastException because my internet connection was unstable and config-server was slow to fetch its configuration from GitHub. The fix was to wait until config-server showed a healthy status and then restart discovery-server manually:
docker compose up -d discovery-server
Once discovery-server was healthy, all the remaining 6 services started without any issues.
Step 4 — Verify the Application
Open each URL in your browser to confirm everything is running:
ServiceURLSpring PetClinic Apphttp://localhost:8080Eureka Dashboardhttp://localhost:8761Spring Boot Adminhttp://localhost:9090Zipkin Tracinghttp://localhost:9411Prometheushttp://localhost:9091Grafanahttp://localhost:3030
The PetClinic app should show the welcome page with the Find Owners, Register Owner, and Veterinarians menu. Test it by clicking Find Owners, adding a visit to a pet, and browsing the vets list to confirm the full application is working end to end.
Step 5 — The Observability Stack
This was the most exciting part of the deployment. Three tools give you complete visibility into what the application is doing:
Prometheus scrapes metrics from every microservice every 15 seconds. Open the Targets page at http://localhost:9091/targets to see all services being monitored. Run this query in the Expression bar to see live request counts:
http_server_requests_seconds_count
The graph shows climbing lines for each service — proof that real traffic is flowing through the system.
Grafana turns all that Prometheus data into visual dashboards. Open http://localhost:3030 and navigate to the Spring PetClinic Metrics dashboard. You can see HTTP Request Latency, HTTP Request Activity, and business metrics like Owners Created and Visits Created — all updating in real time.
Zipkin gives you distributed tracing. But here is something important — Zipkin tracing is not enabled by default in the Docker Compose setup. I had to add two environment variables to all 5 microservice definitions in docker-compose.yml:
yamlenvironment:
- MANAGEMENT_ZIPKIN_TRACING_ENDPOINT=http://tracing-server:9411/api/v2/spans
- MANAGEMENT_TRACING_SAMPLING_PROBABILITY=1.0 After restarting the services with docker compose up -d --force-recreate, Zipkin immediately started showing live traces. I could see individual requests travelling through api-gateway, customers-service, visits-service, and vets-service — with the exact time each hop took. This is the same fix I had applied to our production AKS Helm charts on May 20th during the team project.
Step 6 — Clean Up
When you are done, stop and remove all containers with:
docker compose down
This stops every container and removes the network cleanly. Your images remain so the next startup is faster.
Key Takeaway
The biggest lesson from this deployment was understanding that microservices are not just about splitting an application into smaller pieces — they require careful orchestration. The startup order, service discovery, configuration management, and observability all need to be in place before you can say the system is truly running. Docker Compose makes it possible to experience all of this locally before touching a cloud environment.
About DMI
This deployment was completed as part of the DMI Micro-Internship Cohort 2, run by Pravin Mishra through CloudAdvisory Oy. DMI gives you real hands-on DevOps experience working in a team on production-grade infrastructure. If you want to build skills like this, join the DMI Cohort 4 waiting list here:
https://forms.gle/B5FqjrVryqxZ5UrX7
Top comments (0)