{"slug": "from-docker-compose-up-d-to-aws-eks-building-a-repeatable-spring-petclinic-with", "title": "From docker compose up -d to AWS EKS: Building a Repeatable Spring Petclinic Deployment with Terraform, Helm, ArgoCD and Claude", "summary": "A developer built a repeatable deployment pipeline for the eight-service Spring Petclinic microservices application, moving from local Docker Compose to AWS EKS using Terraform, Helm, ArgoCD, and GitHub Actions, with Claude assisting in writing a deploy.sh orchestration script. The project also added Prometheus, Grafana, and Zipkin observability, where the developer found that Zipkin received no traces until the services were correctly configured to export tracing data. The work was completed as a DMI capstone and DevOps portfolio project.", "body_md": "What started with a simple command—\n\n`docker compose up -d`\n\n—grew into a project involving eight microservices, observability, Infrastructure as Code, Kubernetes, AWS EKS, Helm, ArgoCD, CI/CD, and AI-assisted engineering.\n\nI started this project as part of my DMI capstone. It became one of the central projects in my DevOps portfolio because it gave me the opportunity to work through the journey from a local microservices deployment to an automated cloud deployment on AWS.\n\nMore importantly, I learned that getting an application running is only part of the job. Understanding its behavior, troubleshooting failures, automating deployments, and verifying the results are equally important.\n\n**From Local Microservices to Observability;**\n\nSpring Petclinic is a microservices-based application made up of independent services that work together. For this deployment, I worked with eight application services:\n\nI also deployed the following observability components:\n\nMy goal wasn't simply to get the application running. I wanted to understand what was happening inside it.\n\n*Gateway communicating with the application services, with Config and Discovery Server supporting them and Prometheus, Grafana, and Zipkin providing observability.*\n\n**Running Spring Petclinic Locally**\n\nI started locally because Docker Compose provided a controlled environment for understanding the application before moving to AWS.\n\n`docker compose up -d`\n\ndocker compose ps\n\nOnce the containers were running, I accessed Petclinic through the API Gateway and checked Eureka to confirm that the services were registering correctly.\n\n*All eight microservices running with their port mappings.*\n\n*Eureka showing the registered services*\n\n**Observability: Metrics Collection and Distributed Tracing**\n\nPrometheus collected application metrics while Grafana provided dashboards for visualizing and interpreting them.\n\nThe initial observability setup was relatively straightforward, but I encountered an issue with Zipkin;\n\nThe Zipkin container was running, yet no traces were appearing. After checking the logs and configuration, I discovered that the services were not properly configured to send tracing data to Zipkin.\n\nI corrected the relevant configuration, restarted the services, and generated new requests to verify the result.\n\n*A trace showing a request flowing across multiple Petclinic services.*\n\nThat taught me an important lesson:\n\nHaving an observability tool running is not the same as having observability. The application must actually send useful data to it.\n\nThe experience also helped me understand three basic concepts:\n\n**TAKING THE APPLICATION TO AWS**\n\nOnce the local deployment was working, I wanted to go beyond Docker Compose and deploy the application to Amazon EKS.\n\nThe cloud deployment involved:\n\n**Terraform · EKS · ECR · Kubernetes · Helm · ArgoCD · AWS Load Balancer Controller · IAM · GitOps**\n\nI didn't want to rely on a long sequence of commands that I would have to remember and execute manually every time. I wanted a deployment process that was easier to manage, repeat, and tear down.\n\nOne Script to Set Up the Environment\n\nWith help from Claude, I developed a deployment script, `deploy.sh`, to coordinate the major setup steps.\n\nThe process looks like this:\n\ndeploy.sh\n\n    ↓\n\nAWS credential check\n\n    ↓\n\nTerraform infrastructure provisioning\n\n    ↓\n\nEKS and kubectl configuration\n\n    ↓\n\nArgoCD installation\n\n    ↓\n\nAWS Load Balancer Controller installation\n\n    ↓\n\nArgoCD project and application manifests\n\n    ↓\n\nTrigger initial CI pipeline for image build\n\n    ↓\n\nArgoCD synchronizes deployment configuration\n\nThe important distinction is that the script sets up the environment and triggers the deployment workflow. The application build, image publishing, and Helm image-tag updates are handled by GitHub Actions, while ArgoCD manages deployment synchronization.\n\n**DEPLOYMENT STAGES;**\n\n**1. Terraform + EKS + ECR**\n\nTerraform handled infrastructure provisioning:\n\n`terraform init -input=false`\n\nterraform apply -auto-approve\n\nTerraform uses configuration files to provision the infrastructure required for the EKS environment, including supporting AWS resources and ECR repositories.\n\n*Terraform provisioning the infrastructure and supporting resources*\n\nAmazon ECR provided the container image registry. The deployment script obtained the AWS account ID dynamically and replaced the `YOUR_ACCOUNT_ID` placeholder in the relevant Helm values files.\n\nThis allowed the configuration to reference the ECR image locations for the AWS account being used.\n\n*AWS Console showing the petclinic-prod EKS cluster running in us-east-1*.\n\n**GitHub Actions: Building and Publishing the Images**\n\nThe GitHub Actions workflow, `ci.yml`, automates testing and image publishing.\n\nHere is how it works:\n\n**1. Pull requests to main:** The workflow runs the tests. It does not build and publish the application images for a pull request.\n\n**2. Pushes to main:** The workflow runs the tests and, if they pass, builds eight service images in parallel.\n\n**3. Publish to ECR:** The workflow pushes each image using both the Git commit SHA and the latest tag.\n\n**4. Update Helm values:** After all eight image builds and pushes succeed, another job updates the image tag in the eight Helm values files to the commit SHA.\n\n**5. Commit the updates:** GitHub Actions commits and pushes the updated Helm files. The commit includes [skip ci] to prevent the image-tag update from triggering another CI run.\n\nThe commit SHA is useful because it identifies the specific version of the code associated with each image. It also makes it easier to see which version the Helm configuration is requesting.\n\nThe workflow uses GitHub Actions OIDC to obtain AWS credentials through an IAM role rather than storing long-lived AWS access keys in GitHub Secrets. This reduces the need to manage permanent AWS credentials in the repository's CI/CD settings.\n\n**How the Deployment Pieces Work Together**\n\nThe overall workflow can be understood in two parts.\n\n**Part 1: Environment setup**\n\ndeploy.sh → Terraform → EKS and supporting AWS resources → ArgoCD and AWS Load Balancer Controller → ArgoCD application manifests → CI trigger.\n\n**Part 2: Application delivery**\n\nGit push to main → tests → build eight images → push images to ECR → update Helm image tags → ArgoCD syncs the desired configuration → Kubernetes runs the application.\n\nThis distinction is important because the deployment script does not itself build all eight images or directly deploy every service. It coordinates the setup and starts the workflow that handles those steps.\n\n**2. Helm, ArgoCD and GitOps**\n\nWith EKS ready, I used Helm to package and configure the Kubernetes deployments instead of maintaining completely separate manifests for every service or environment.\n\nArgoCD provided the GitOps layer, managing the applications from Git and reconciling the cluster with the desired configuration.In simple terms, Git stores the desired deployment configuration, and ArgoCD checks that configuration and works to keep the Kubernetes cluster aligned with it.\n\nThe relationship looks like this:\n\nGit repository → ArgoCD → Helm configuration → Kubernetes resources → running application.\n\n*ArgoCD showing the Petclinic applications as Synced and Healthy*\n\nThis helped me understand how GitOps can reduce manual deployment work by allowing the cluster to reconcile its state with the configuration stored in Git.\n\n**3. Making the Application Accessible**\n\nThe final part was exposing the application outside the Kubernetes cluster.\n\nI installed the AWS Load Balancer Controller. This component watches Kubernetes resources such as Ingress and manages the AWS load balancers required by their configuration.\n\nThe controller is not a step that application traffic passes through. Instead, it manages the load balancer and its routing configuration.\n\nThe application request path is:\n\nInternet / Browser → AWS Application Load Balancer → Kubernetes Ingress routing → API Gateway Service → Petclinic microservice\n\n*AWS Console showing the provisioned Application Load Balancer*\n\nI used the deployment script to coordinate the setup:\n\n`bash scripts/deploy.sh`\n\nThe script provisions the infrastructure, installs the required deployment components, applies the ArgoCD application configuration, and triggers the CI workflow. After the workflow and application deployment completed, I verified access through the load balancer URL.\n\n*Spring Petclinic loading through the Application Load Balancer*\n\nThis was an important milestone: I had moved from running the application locally to accessing it through an AWS-hosted Kubernetes environment.\n\nThe deployment script also included a teardown process. With:\n\n`bash teardown.sh`\n\nI could run the teardown workflow to remove the environment and destroy the resources managed by the relevant configuration. This helped reduce the time spent on manual cleanup and avoid unnecessary cloud costs. After teardown, I still needed to verify that the intended resources had been removed.\n\n**Testing Idempotency and Repeatability**\n\nAutomation should not only work once. It should also behave predictably when run again. One important part of this project was testing whether the deployment process could be safely repeated.\n\nI tested the deployment workflow in two ways.\n\n*Terraform showing `No changes`. Infrastructure matches the configuration*\n\nThese tests addressed two related but different goals:\n\n**Idempotency:** Repeating an operation against an existing environment should not introduce unintended changes or duplicate resources.\n\n**Repeatability:** The deployment process should be capable of recreating the intended environment under the required conditions/process.\n\nI also tested how repeated runs behaved because part of the deployment script creates an empty Git commit to trigger the CI/CD workflow. Since this can start another pipeline run, I needed to consider not only whether Terraform reported infrastructure changes2, but also whether that run produces unintended changes or safely maintains the desired application state. My repeated tests helped me evaluate that behavior.\n\nThe experience reinforced the importance of validating automation through observable results rather than assuming that a successful script execution guarantees the desired outcome.\n\n**Claude as Part of the Engineering Workflow**\n\nOne of the most interesting parts of this project was incorporating Claude into the engineering process.\n\nI used Claude as an AI engineering assistant for understanding requirements, reasoning through architecture, working through configuration, troubleshooting errors, and refining the deployment workflow.\n\nClaude helped me explore how the different layers connected, but I remained responsible for the decisions, execution, testing, and verification.\n\n*A Claude conversation showing assistance with the Helm configuration*\n\nAnother advantage was iteration speed. Instead of manually piecing together every configuration across Terraform, EKS, ECR, Helm, ArgoCD, the Load Balancer Controller, and CI/CD, I could provide the relevant error or configuration, ask Claude to explain the underlying issue, evaluate the proposed solution, and test it.\n\nThis helped me turn a collection of individual setup steps into a more repeatable deployment process. However, Claude's suggestions were not treated as proof that something worked. The configurations and changes still had to be tested in the actual environment.\n\n**Things That Didn't Go According to Plan**\n\nThe deployment wasn't completely smooth, and some of the most valuable learning came from troubleshooting.\n\n**Docker:** Existing containers caused name conflicts when restarting Compose.\n\n**Zipkin:** The container was running, but traces weren't appearing because the services were not correctly configured to send tracing data.\n\n**Kubernetes:** Some services initially used `localhost` for communication instead of Kubernetes service names, such as discovery-server.\n\n**AWS/EKS:** Moving from Compose to EKS introduced more components to understand and coordinate, including Terraform, ECR, Helm, ArgoCD, and the AWS Load Balancer Controller.Understanding how they worked together took time.\n\nWorking through these issues taught me to investigate the cause rather than simply rerun commands and hope the problem disappeared. Seeing the application become accessible after troubleshooting made the learning process especially rewarding.\n\n**What This Project Taught Me**\n\nThe biggest lesson wasn't learning another list of DevOps tools. It was understanding how the different layers work/fit together.\n\n**- Docker Compose** helped me develop and validate the microservices locally.\n\n**- Prometheus, Grafana, and Zipkin** helped me investigate application behavior through metrics, dashboards, and distributed traces.\n\n**- Terraform** enabled infrastructure provisioning through code.\n\n**- EKS and Kubernetes** provided the orchestration platform.\n\n**- ECR** stored the container images.\n\n**- Helm** helped manage Kubernetes application configurations.\n\n**- GitHub Actions** automated testing, image building, publishing, and image-tag updates.\n\n**- ArgoCD** managed GitOps-based deployment synchronization.\n\n**- Deployment and teardown scripts** made the process easier to repeat and clean up.\n\n**- Claude** helped me investigate errors, explore implementation options, and refine the automation, while I remained responsible for testing and validating the results.\n\nThe most valuable lessons came when things didn't work as expected. Missing traces, service-discovery issues, and cloud deployment challenges pushed me to investigate beyond the immediate error and understand the underlying system.\n\nWhat began as a local Spring Petclinic deployment became a practical exercise in cloud-native deployment, observability, Infrastructure as Code, CI/CD, GitOps, and AI-assisted engineering.\n\n**A deployment that works teaches you how to deploy. A deployment that breaks teaches you how to think like an engineer.**\n\nI'm grateful to Pravin Mishra for providing the DMI learning platform, my co-mentors, and my teammates for their support throughout DMI Cohort 2.\n\n🔗 Project Resources\n\nProject repository: [https://github.com/Crystal-Angie/spring-petclinic-ai-devops.git](https://github.com/Crystal-Angie/spring-petclinic-ai-devops.git) \n\nInterested in DMI Cohort 4? Join the waiting list:\n\n[https://forms.gle/t8AnbtieRmGAiFHw5](https://forms.gle/t8AnbtieRmGAiFHw5)", "url": "https://wpnews.pro/news/from-docker-compose-up-d-to-aws-eks-building-a-repeatable-spring-petclinic-with", "canonical_source": "https://dev.to/angela_bfc238/from-docker-compose-up-d-to-aws-eks-building-a-repeatable-spring-petclinic-deployment-with-424c", "published_at": "2026-10-15 09:06:04+00:00", "updated_at": "2026-10-15 09:19:27.723423+00:00", "lang": "en", "topics": ["mlops", "ai-tools", "developer-tools", "ai-infrastructure"], "entities": ["Spring Petclinic", "AWS EKS", "Terraform", "Helm", "ArgoCD", "Claude", "Prometheus", "Grafana"], "also_reported_by": [], "alternates": {"html": "https://wpnews.pro/news/from-docker-compose-up-d-to-aws-eks-building-a-repeatable-spring-petclinic-with", "markdown": "https://wpnews.pro/news/from-docker-compose-up-d-to-aws-eks-building-a-repeatable-spring-petclinic-with.md", "text": "https://wpnews.pro/news/from-docker-compose-up-d-to-aws-eks-building-a-repeatable-spring-petclinic-with.txt", "jsonld": "https://wpnews.pro/news/from-docker-compose-up-d-to-aws-eks-building-a-repeatable-spring-petclinic-with.jsonld"}}