Skip to main content

Command Palette

Search for a command to run...

Deploying 8 Microservices to AWS EKS with Docker Compose: A Step-by-Step Walkthrough

A walk through

Updated
5 min read
Deploying 8 Microservices to AWS EKS with Docker Compose: A Step-by-Step Walkthrough
V
I build production-grade cloud infrastructure and agentic AI pipelines on AWS. With a background in biochemistry and biotechnology, I bring scientific precision to the systems I design. Every pipeline I build has deliberate safety guardrails -- minimal permissions, read-only auditors, plan-before-apply gates. Safety is architecture, not discipline. Currently writing a 7-part series documenting the Agentic Infrastructure project: a complete Claude Code pipeline from environment setup to live AWS deployment, SubAgents, MCP integration, and safety hooks. Portfolio: viviancloud.site

Introduction

Spring PetClinic Microservices is a production-grade distributed application used by the Spring community to demonstrate microservices architecture. It consists of 8 independent services, a service registry, a config server, and a full observability stack including Prometheus, Grafana, and Zipkin.

As part of DMI Cohort 2, I deployed this application both locally using Docker Compose and to AWS EKS using Terraform and ArgoCD. This post documents the full process, the commands, the startup order, the observability stack, and the key lessons.

Prerequisites

Before starting, the following tools must be installed:

  • Docker Desktop (version 24+)

  • Git

  • AWS CLI (configured with appropriate IAM credentials)

  • Terraform 1.5+

  • kubectl

  • Helm 3

Part 1: Local Deployment with Docker Compose

Step 1: Clone the Repository

git clone https://github.com/Petcare-Clinic/petcareClinic-cloudops.git cd petcareClinic-cloudops

Confirm you are in the right directory: ls

You should see: docker-compose.yml, helm/, terraform/, upstream/, .github/

Step 2: Start All Services

docker compose up -d

This single command pulls all images, creates the network, and starts all containers in the correct order. The -d flag runs everything in detached mode.

Step 3: Verify All Containers Are Running

docker compose ps

You should see all containers with status Up. The most important thing to verify is that config-server and discovery-server show Healthy before the other 6 services start. This is enforced by the depends_on configuration in the Compose file.

The Startup Order — Why It Matters

The depends_on: condition: service_healthy configuration in docker-compose.yml means Docker will not start the API Gateway, Customers Service, Vets Service, Visits Service, GenAI Service, or Admin Server until both Config Server (port 8888) and Discovery Server (port 8761) have passed their health checks.

Config Server must start first because every other service reads its configuration from it on startup, database URLs, service ports, feature flags. If Config Server is not ready, the other services will fail to start correctly.

Discovery Server (Eureka) must start second because it is the service registry. Every service registers itself with Eureka on startup, and the API Gateway uses Eureka to discover the addresses of the services it routes traffic to. Without Eureka, the API Gateway cannot route requests.

This is the difference between docker compose up (starts all services together, respecting depends_on) and docker compose down (stops and removes all containers and the network, cleaning up the entire environment).

Step 4: Verify the Application

Open each URL to confirm all services are running:

Step 5: Functional Test

Navigate to localhost:8080, click Find Owners, and search without a filter. You should see a list of pre-loaded owners. Click an owner to view their pets and visit history. Add a visit by clicking a pet, selecting Add Visit, entering a date and description, and submitting. Confirm it appears in the history.

Navigate to Veterinarians to confirm the table of vets with their specialties loads correctly.

Part 2: The Observability Stack

Prometheus

Prometheus scrapes the /actuator/prometheus endpoint on each service every 15 seconds. Run this query in the Prometheus UI to see request counts across all services:

http_server_requests_seconds_count

You will see time-series data broken down by service, endpoint, HTTP method, and status code.

Grafana

The Grafana instance at localhost:3030 is pre-configured with a Prometheus datasource and the Spring Petclinic Metrics dashboard. Default credentials are admin / petclinic. The dashboard shows HTTP request rates, JVM heap memory usage per service, pod restart counts, and database connection pool health in real time.

Zipkin

Zipkin at localhost:9411 shows distributed traces. Each trace represents a single request flowing through the system. A request to GET /api/customer/owners, for example, will show the API Gateway receiving the request, routing it to Customers Service, and Customers Service querying the database — all as a single connected trace with timing for each step.

Part 3: AWS Deployment

Infrastructure Provisioning with Terraform

cd terraform terraform init terraform plan terraform apply -auto-approve

This creates the full AWS environment: VPC with public and private subnets, NAT gateway, Amazon EKS cluster (petclinic-cluster in us-east-1), ECR repositories for each of the 8 services, and all IAM roles with least-privilege policies.

GitOps Deployment with ArgoCD

Once the cluster is running, the bootstrap script sets up ArgoCD and registers the application:

bash scripts/bootstrap-argocd.sh

ArgoCD is configured to watch the Helm values files in the repository. When the CI/CD pipeline pushes a new image tag to values.yaml, ArgoCD detects the change and automatically syncs the cluster — pulling the new image from ECR and performing a rolling update with zero downtime.

Key AWS Challenge

The most challenging part of the AWS deployment was ensuring the EKS node group had sufficient IAM permissions to pull images from ECR without exposing credentials in the application. The solution was using IRSA (IAM Roles for Service Accounts) to attach the AmazonEC2ContainerRegistryReadOnly policy directly to the Kubernetes service account, so pods can pull images without any credentials in the manifest or environment variables.

Key Lessons

The startup order is not optional in distributed systems. Config Server and Discovery Server are dependencies of everything else — treat them like infrastructure, not application services.

Observability before features. Getting Prometheus and Grafana running before the first deployment meant we could see problems before users reported them.

Docker Compose and Kubernetes are not interchangeable. Compose is excellent for local development where startup order and port mapping are predictable. Kubernetes is for production where you need self-healing, auto-scaling, rolling updates, and multi-node scheduling.

Conclusion

This project is part of DMI Cohort 2, a DevOps Micro Internship programme focused on hands-on, production-grade engineering. If you want to build real skills in cloud engineering and DevOps in a team environment, DMI Cohort 3 starts 27 June 2026:

https://docs.google.com/forms/d/e/1FAIpQLSel7ai7nyb0P1qLW4vEyfB_nEsD4lUF1XG88vmAaFGBOb6hPA/viewform

R

That "Compose teaches the dependency logic, Kubernetes makes it production-worthy" framing is so accurate. Once you internalize service ordering with Compose, Kubernetes manifests feel way less intimidating.

A

Really enjoyed this walkthrough. Deploying multiple microservices to EKS is one of those things that sounds straightforward on paper, but in practice the number of moving parts can get messy very quickly. I like that you showed the process step by step instead of skipping straight to the “final architecture” part.

What stood out to me most was how Docker Compose helped bridge the local development setup with the Kubernetes/EKS deployment flow. That transition is often where people get stuck, so this makes the whole journey feel a lot more approachable.

I’m also working through more cloud and DevOps content lately, and posts like this are especially useful because they reflect the real operational side of microservices rather than just the theory. Solid write-up overall.

V

Thanks for this, Atul.

You put it perfectly: it sounds straightforward until you're actually in it watching services fail because the config server wasn't ready yet. That Docker Compose to Kubernetes bridge was honestly one of the biggest things I took away from this project too.

Compose taught me the dependency logic, and Kubernetes just made it production-worthy. They're not competing tools, they're a progression. Good luck with your cloud and DevOps journey. Keep building and keep sharing what you learn.

A

Thanks for sharing that perspective, really appreciate it.

I like how you framed Docker Compose and Kubernetes as a progression instead of competing approaches – that matches how I’ve been thinking about it too. Start with Compose to understand dependencies and behavior, then move to K8s/EKS once you’re ready to harden things for production.

I’m currently deep-diving into AWS, containers, and DevOps, so seeing real stories like yours definitely helps shape how I plan my own projects. I’ll keep experimenting and sharing what I learn along the way. Thanks again for taking the time to respond.