End-to-end automated deployment from source code to production on AWS
Code pushed to GitHub triggers a Jenkins pipeline that builds a Docker image, pushes it to Amazon ECR, and deploys it to a Kubernetes cluster running on AWS EC2. Every layer of the stack β from the EC2 instances themselves to the running pods β is provisioned or configured through code.
GitHub β Jenkins β Docker Build β Amazon ECR β Kubernetes (Minikube) β Running App
β
Terraform β AWS Infrastructure (EC2, VPC, Security Groups)
β
Ansible β Server Configuration (Java, Jenkins, Docker, Minikube)
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β DEVELOPER MACHINE β
β git push β GitHub Repository β
ββββββββββββββββββββββββββββββββ¬βββββββββββββββββββββββββββββββββββββ
β Webhook trigger
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β AWS EC2 β JENKINS SERVER β
β β
β ββββββββββββ ββββββββββββββββ ββββββββββββββββββββββββββ β
β β Checkout βββββΆβ Docker Build βββββΆβ Push to Amazon ECR β β
β β (GitHub) β β :v${BUILD} β β + kubectl deploy β β
β ββββββββββββ ββββββββββββββββ ββββββββββββββββββββββββββ β
βββββββββββββββββββββββββββββββββββββββββββββββββ¬ββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β AWS EC2 β APP SERVER β
β β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β Kubernetes (Minikube) β β
β β Deployment β ReplicaSet β Pod β Docker Container β β
β β (NGINX Β· Static App) β β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β
β π NodePort Service β http://<EC2-PUBLIC-IP>:<PORT> β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
| Layer | Tool | Purpose |
|---|---|---|
| βοΈ Cloud | AWS EC2 | Compute infrastructure |
| ποΈ IaC | Terraform | Provision EC2, VPC, security groups |
| βοΈ Config | Ansible | Install and configure Jenkins, Docker, Minikube |
| π CI/CD | Jenkins | Pipeline orchestration (build β push β deploy) |
| π¦ Containers | Docker | Application packaging and versioning |
| ποΈ Registry | Amazon ECR | Private Docker image storage |
| βΈοΈ Orchestration | Kubernetes | Pod scheduling, scaling, service exposure |
| π Web Server | NGINX | Serve static app inside the container |
| ποΈ SCM | GitHub | Source control and pipeline trigger |
multi-ec2-cicd-devops-project/
βββ terraform/
β βββ main.tf # EC2 instances, VPC, security groups
β βββ variables.tf # Input variables
β βββ outputs.tf # Public IPs, resource names
βββ ansible/
β βββ inventory.ini # EC2 host addresses
β βββ playbooks/ # Jenkins, Docker, Minikube setup
βββ docker/
β βββ Dockerfile # NGINX image definition
β βββ index.html # Static web application
βββ k8s/
β βββ deployment.yaml # Kubernetes Deployment
β βββ service.yaml # NodePort Service
β βββ kubernetes-beginner-guide.html # K8s conceptual learning guide
βββ jenkins/
βββ Jenkinsfile # Declarative pipeline definition
βββ ecr.tf # Amazon ECR repository
βββ .gitignore
- AWS account with IAM credentials configured (
aws configure) - Terraform
>= 1.0 - Ansible
>= 2.9 - An SSH key pair for EC2 access
cd terraform/
terraform init
terraform plan
terraform applyCreates EC2 instances, VPC, subnets, and security groups on AWS.
cd ansible/
ansible-playbook -i inventory.ini playbooks/setup.ymlInstalls Java, Jenkins, Docker, and Minikube on the target instances.
Open Jenkins at http://<JENKINS-EC2-IP>:8080, configure the pipeline to point at this repository, then push a commit. Jenkins picks it up automatically.
minikube service webapp-service --urlOpen the returned URL in your browser.
pipeline {
agent any
stages {
stage('Checkout') {
// Pull latest code from GitHub
}
stage('Build Docker Image') {
// docker build -t $ECR_REPO:v${BUILD_NUMBER} .
}
stage('Push to Amazon ECR') {
// aws ecr get-login-password | docker login
// docker push $ECR_REPO:v${BUILD_NUMBER}
}
stage('Deploy to Kubernetes') {
// kubectl apply -f k8s/deployment.yaml
// kubectl apply -f k8s/service.yaml
}
}
}Each stage is independently logged. Failures are easy to isolate and retry.
This project goes hands-on with the full Kubernetes workload model on Minikube:
- Pods β smallest deployable unit, wrapping the Docker container
- Deployments β declarative updates, rollback support, desired-state management
- ReplicaSets β maintain the specified number of pod replicas automatically
- Services (NodePort) β expose pods to external traffic outside the cluster
- Minikube β single-node cluster for zero-cost development on EC2
A companion interactive guide (k8s/kubernetes-beginner-guide.html) covers cluster architecture, the control plane, worker nodes, and the full request lifecycle from DNS to pod.
Why Minikube instead of EKS?
Keeps costs at zero while covering the same Kubernetes API surface. The deployment.yaml and service.yaml manifests are portable to any standard cluster β upgrading to EKS later requires no changes to the K8s config.
Why Amazon ECR instead of Docker Hub? ECR integrates natively with AWS IAM. The EC2 instance role grants pull access automatically β no credentials need to be stored in Jenkins.
Why Ansible instead of EC2 user data scripts? Ansible playbooks are idempotent and rerunnable. If server configuration drifts, re-running the playbook restores the desired state without re-provisioning the instance.
Why a declarative Jenkinsfile? The pipeline definition lives in version control alongside the application code. Every change is tracked, reviewable, and rollback-able like any other file in the repo.
- Migrate from Minikube to EKS for production-grade scaling
- Add automated rollback on deployment failure
- Set up Prometheus + Grafana monitoring dashboards
- Implement multi-environment pipelines β dev / staging / prod
- Move secrets to Jenkins Credentials Manager (no plain-text keys)
- Enable Slack / email notifications on pipeline success or failure
Anshu Sharma β Cloud & DevOps Engineer
Building production-grade infrastructure and automation on AWS.