One Command, Eight Microservices: Deploying Spring PetClinic with Docker Compose

Introduction
As part of my DevOps learning journey, I recently deployed the Spring PetClinic Microservices application locally using Docker Compose.
This wasn't a simple single-container application. The project consists of eight microservices, service discovery, centralized configuration management, API gateway routing, distributed tracing, metrics collection, and monitoring dashboards.
In one command:
docker compose up -d
I launched an entire cloud-native microservices environment.
This project gave me practical experience with:
Docker Compose
Microservices Architecture
Spring Cloud Config Server
Eureka Service Discovery
API Gateway
Prometheus Monitoring
Grafana Dashboards
Zipkin Distributed Tracing
Architecture Overview
The application consists of:
Core Infrastructure
| Service | Port |
|---|---|
| Config Server | 8888 |
| Discovery Server (Eureka) | 8761 |
Business Services
| Service | Port |
|---|---|
| API Gateway | 8080 |
| Customers Service | 8081 |
| Visits Service | 8082 |
| Vets Service | 8083 |
| GenAI Service | 8084 |
| Admin Server | 9090 |
Observability Stack
| Service | Port |
|---|---|
| Prometheus | 9091 |
| Grafana | 3030 |
| Zipkin | 9411 |
Why Config Server and Discovery Server Start First
One thing I learned quickly is that startup order matters.
The Config Server provides centralized configuration for every service.
The Discovery Server (Eureka) allows services to register themselves and discover other services dynamically.
Without these two services running first:
Other services cannot load configuration.
Service registration fails.
Inter-service communication breaks.
The Docker Compose file handles this using:
depends_on:
This ensures dependent services wait for healthy infrastructure services before starting.
Deployment Process
Clone the Repository
git clone https://github.com/spring-petclinic/spring-petclinic-microservices.git
cd spring-petclinic-microservices
Start the Environment
docker compose up -d
Docker automatically:
Pulled required images
Created a network
Started infrastructure services
Started business services
Started monitoring components
Verify Running Containers
docker compose ps
All services showed:
Up
Healthy
which confirmed successful deployment.
Verifying the Application
I tested the primary endpoints:
Spring PetClinic
http://localhost:8080
Eureka Dashboard
http://localhost:8761
Spring Boot Admin
http://localhost:9090
Prometheus
http://localhost:9091
Grafana
http://localhost:3030
Zipkin
http://localhost:9411
All dashboards loaded successfully.
An Interesting Challenge
One unexpected issue appeared during functional testing.
The backend services were healthy and responding correctly through API calls, but some frontend pages did not render data consistently in the browser.
For example:
curl -i http://localhost:8080/api/customer/owners?lastName=
returned a successful HTTP 200 response with owner data.
However, the browser occasionally showed:
405 Method Not Allowed
503 Service Unavailable
for some frontend requests.
This demonstrated an important DevOps lesson:
A healthy container does not automatically mean the entire user experience is healthy.
Observability and troubleshooting remain critical even when infrastructure appears operational.
Monitoring with Prometheus
Prometheus successfully scraped metrics from multiple services.
I queried:
http_server_requests_seconds_count
and received metrics from:
customers-service
visits-service
vets-service
Example metrics included:
GET /owners
GET /actuator/health
GET /actuator/prometheus
This provided visibility into request volume and application behaviour.
Visualising Metrics with Grafana
Grafana transformed raw Prometheus data into dashboards.
Through Grafana I could observe:
Request counts
Service activity
Health metrics
Runtime performance
This demonstrated why Grafana is one of the most widely used observability tools in production environments.
Distributed Tracing with Zipkin
Zipkin was deployed alongside the application to support distributed tracing.
In a microservices architecture, a single user request may travel through multiple services before a response is returned.
Zipkin enables engineers to:
Follow request paths
Measure latency
Identify bottlenecks
Troubleshoot failures
This becomes increasingly valuable as applications grow in complexity.
Cleaning Up
After testing:
docker compose down
Docker removed:
Containers
Networks
Temporary resources
leaving the environment clean.
Key Lessons Learned
This project taught me several important DevOps concepts:
Infrastructure Dependencies Matter
Services often rely on other services before they can start successfully.
Observability Is Essential
Prometheus, Grafana, and Zipkin provide visibility that logs alone cannot.
Healthy Containers ≠ Healthy Application
Verification must include API testing and user experience testing.
Docker Compose Is Powerful
A complete microservices ecosystem can be deployed with a single command.
Final Thoughts
Deploying Spring PetClinic Microservices provided hands-on experience with modern cloud-native architecture patterns.
Beyond simply running containers, I gained practical exposure to:
Service discovery
Centralized configuration
API gateways
Monitoring
Metrics collection
Distributed tracing
Projects like this bridge the gap between theory and real-world DevOps engineering.
As I continue building cloud and platform engineering skills, this project has strengthened my understanding of how production-grade microservices environments are deployed, monitored, and maintained.
If you want to learn DevOps through hands-on projects and real infrastructure challenges, DMI Cohort 3 starts on 27 June 👇
https://docs.google.com/forms/d/e/1FAIpQLSel7ai7nyb0P1qLW4vEyfB_nEsD4lUF1XG88vmAaFGBOb6hPA/viewform

