Skip to content

iamindrajitdan/Voting-app-cloud-native-EKS

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

6 Commits
 
 
 
 
 
 

Repository files navigation

Cloud-Native Web Voting Application with Kubernetes

A production-ready voting application demonstrating cloud-native architecture patterns on Amazon EKS. Users can vote for their preferred programming language from six options: C#, Python, JavaScript, Go, Java, and Node.js.

Architecture Overview

This application follows a microservices architecture with three main components:

  • Frontend: React-based web interface (2 replicas)
  • API: Go-based REST API backend (2 replicas)
  • Database: MongoDB replica set (3 nodes) with persistent storage

All components are deployed on Amazon EKS with LoadBalancer services for external access.

Technical Stack

Component Technology Details
Frontend React + JavaScript Responsive UI for voting interface
Backend API Go (Golang) REST API handling vote requests
Database MongoDB 4.2 Replica set with 3 nodes for HA
Orchestration Kubernetes (EKS) Container orchestration and management
Storage AWS EBS (gp2) Persistent volumes for MongoDB data
Networking EBS CSI Driver Dynamic volume provisioning with IAM roles

Kubernetes Resources Used

  • Namespace: cloudchamp - Isolated environment for all application components
  • Deployments: Frontend and API with rolling update strategy
  • StatefulSet: MongoDB replica set with stable network identities
  • Services:
    • Headless service for MongoDB inter-pod communication
    • LoadBalancer services for frontend and API external access
  • Secrets: MongoDB credentials stored securely
  • PersistentVolumeClaims: 0.5Gi storage per MongoDB pod
  • StorageClass: gp2 for dynamic EBS volume provisioning

Key Features

  • High Availability: Multi-replica deployments with pod anti-affinity rules
  • Data Persistence: MongoDB replica set with persistent storage
  • Health Checks: Liveness and readiness probes on all containers
  • Rolling Updates: Zero-downtime deployments with controlled surge/unavailability
  • Security: Kubernetes secrets for credential management
  • Scalability: Independently scalable frontend, API, and database tiers
  • EKS Auto Mode: Simplified cluster management with automatic node provisioning
  • EBS CSI Integration: IAM roles for secure EBS volume access

Learning Outcomes

This project demonstrates:

  1. Containerization: Docker-based application packaging
  2. Kubernetes Orchestration: Deployment, scaling, and management of containerized workloads
  3. Microservices Architecture: Decoupled, independently deployable services
  4. Database Replication: MongoDB replica set for redundancy and high availability
  5. Secrets Management: Secure credential handling in Kubernetes
  6. Stateful Applications: Managing stateful workloads with StatefulSets
  7. Persistent Storage: Kubernetes storage provisioning and management
  8. Service Discovery: DNS-based inter-service communication
  9. EKS Auto Mode: Automated cluster operations and node management
  10. IAM Integration: IRSA (IAM Roles for Service Accounts) for secure AWS resource access

Deployment Guide

Prerequisites

  • AWS Account with appropriate permissions
  • EKS cluster with Auto Mode enabled
  • kubectl installed and configured
  • AWS CLI configured
  • git

Step 1: Create EKS Cluster with Auto Mode

Create an EKS cluster with Auto Mode enabled:

aws eks create-cluster \
  --name voting-app-cluster \
  --version 1.29 \
  --region us-west-2 \
  --compute-config computeType=ec2,autoScalingGroupConfigs=[{minSize=1,maxSize=5}] \
  --logging '{"clusterLogging":[{"enabled":true,"types":["api","audit","authenticator","controllerManager","scheduler"]}]}'

Configure kubectl:

aws eks update-kubeconfig --name voting-app-cluster --region us-west-2
kubectl get nodes

Step 2: Configure EBS CSI Driver with IAM Roles

Create an IAM policy for EBS CSI:

cat > ebs-csi-policy.json << 'EOF'
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "ec2:CreateSnapshot",
        "ec2:AttachVolume",
        "ec2:DetachVolume",
        "ec2:ModifyVolume",
        "ec2:DescribeAvailabilityZones",
        "ec2:DescribeCreateVolumePermissions",
        "ec2:DescribeInstanceAttribute",
        "ec2:DescribeInstanceTypes",
        "ec2:DescribeInstances",
        "ec2:DescribeSnapshots",
        "ec2:DescribeTags",
        "ec2:DescribeVolumes",
        "ec2:DescribeVolumesModifications"
      ],
      "Resource": "*"
    },
    {
      "Effect": "Allow",
      "Action": [
        "ec2:CreateTags"
      ],
      "Resource": [
        "arn:aws:ec2:*:*:volume/*",
        "arn:aws:ec2:*:*:snapshot/*"
      ],
      "Condition": {
        "StringEquals": {
          "ec2:CreateAction": [
            "CreateVolume",
            "CreateSnapshot"
          ]
        }
      }
    },
    {
      "Effect": "Allow",
      "Action": [
        "ec2:DeleteTags"
      ],
      "Resource": [
        "arn:aws:ec2:*:*:volume/*",
        "arn:aws:ec2:*:*:snapshot/*"
      ]
    }
  ]
}
EOF

Create the IAM policy:

aws iam create-policy \
  --policy-name EBSCSIDriverPolicy \
  --policy-document file://ebs-csi-policy.json

Create an IAM role for the EBS CSI driver:

cat > trust-policy.json << 'EOF'
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Federated": "arn:aws:iam::ACCOUNT_ID:oidc-provider/oidc.eks.us-west-2.amazonaws.com/id/EXAMPLED539D4633E53DE1B716D3041E"
      },
      "Action": "sts:AssumeRoleWithWebIdentity",
      "Condition": {
        "StringEquals": {
          "oidc.eks.us-west-2.amazonaws.com/id/EXAMPLED539D4633E53DE1B716D3041E:sub": "system:serviceaccount:kube-system:ebs-csi-controller-sa"
        }
      }
    }
  ]
}
EOF

Replace ACCOUNT_ID and the OIDC provider ID with your actual values:

ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)
OIDC_ID=$(aws eks describe-cluster --name voting-app-cluster --region us-west-2 --query 'cluster.identity.oidc.issuer' --output text | cut -d '/' -f 5)

sed -i "s/ACCOUNT_ID/$ACCOUNT_ID/g" trust-policy.json
sed -i "s/EXAMPLED539D4633E53DE1B716D3041E/$OIDC_ID/g" trust-policy.json

Create the role:

aws iam create-role \
  --role-name EBSCSIDriverRole \
  --assume-role-policy-document file://trust-policy.json

Attach the policy to the role:

aws iam attach-role-policy \
  --role-name EBSCSIDriverRole \
  --policy-arn arn:aws:iam::$ACCOUNT_ID:policy/EBSCSIDriverPolicy

Add the EBS CSI driver to your cluster:

aws eks create-addon \
  --cluster-name voting-app-cluster \
  --addon-name aws-ebs-csi-driver \
  --service-account-role-arn arn:aws:iam::$ACCOUNT_ID:role/EBSCSIDriverRole \
  --region us-west-2

Step 3: Clone Repository and Setup Namespace

git clone https://github.com/N4si/K8s-voting-app.git
cd K8s-voting-app

# Create and switch to cloudchamp namespace
kubectl create ns cloudchamp
kubectl config set-context --current --namespace cloudchamp

Step 4: Deploy MongoDB Replica Set

Deploy the MongoDB StatefulSet with persistent storage:

kubectl apply -f manifests/mongo-statefulset.yaml
kubectl apply -f manifests/mongo-service.yaml

Verify DNS resolution for MongoDB pods:

kubectl run --rm utils -it --image praqma/network-multitool -- bash
# Inside the pod:
for i in {0..2}; do nslookup mongo-$i.mongo; done
exit

Initialize the MongoDB replica set:

cat << EOF | kubectl exec -it mongo-0 -- mongo
rs.initiate();
sleep(2000);
rs.add("mongo-1.mongo:27017");
sleep(2000);
rs.add("mongo-2.mongo:27017");
sleep(2000);
cfg = rs.conf();
cfg.members[0].host = "mongo-0.mongo:27017";
rs.reconfig(cfg, {force: true});
sleep(5000);
EOF

Verify replica set status:

kubectl exec -it mongo-0 -- mongo --eval "rs.status()" | grep "PRIMARY\|SECONDARY"

Load initial data:

cat << EOF | kubectl exec -it mongo-0 -- mongo
use langdb;
db.languages.insert({"name" : "csharp", "codedetail" : { "usecase" : "system, web, server-side", "rank" : 5, "compiled" : false, "homepage" : "https://dotnet.microsoft.com/learn/csharp", "download" : "https://dotnet.microsoft.com/download/", "votes" : 0}});
db.languages.insert({"name" : "python", "codedetail" : { "usecase" : "system, web, server-side", "rank" : 3, "script" : false, "homepage" : "https://www.python.org/", "download" : "https://www.python.org/downloads/", "votes" : 0}});
db.languages.insert({"name" : "javascript", "codedetail" : { "usecase" : "web, client-side", "rank" : 7, "script" : false, "homepage" : "https://en.wikipedia.org/wiki/JavaScript", "download" : "n/a", "votes" : 0}});
db.languages.insert({"name" : "go", "codedetail" : { "usecase" : "system, web, server-side", "rank" : 12, "compiled" : true, "homepage" : "https://golang.org", "download" : "https://golang.org/dl/", "votes" : 0}});
db.languages.insert({"name" : "java", "codedetail" : { "usecase" : "system, web, server-side", "rank" : 1, "compiled" : true, "homepage" : "https://www.java.com/en/", "download" : "https://www.java.com/en/download/", "votes" : 0}});
db.languages.insert({"name" : "nodejs", "codedetail" : { "usecase" : "system, web, server-side", "rank" : 20, "script" : false, "homepage" : "https://nodejs.org/en/", "download" : "https://nodejs.org/en/download/", "votes" : 0}});
db.languages.find().pretty();
EOF

Create MongoDB secret:

kubectl apply -f manifests/mongo-secret.yaml

Step 5: Deploy API Backend

Deploy the Go API:

kubectl apply -f manifests/api-deployment.yaml
kubectl apply -f manifests/api-service.yaml

Wait for the API LoadBalancer to get an external hostname and test connectivity:

API_ELB_PUBLIC_FQDN=$(kubectl get svc api -ojsonpath="{.status.loadBalancer.ingress[0].hostname}")
until nslookup $API_ELB_PUBLIC_FQDN >/dev/null 2>&1; do sleep 2 && echo "Waiting for DNS..."; done
curl $API_ELB_PUBLIC_FQDN/ok

Test API endpoints:

curl -s $API_ELB_PUBLIC_FQDN/languages | jq .
curl -s $API_ELB_PUBLIC_FQDN/languages/go | jq .
curl -s $API_ELB_PUBLIC_FQDN/languages/java | jq .

Step 6: Deploy Frontend

Deploy the React frontend:

kubectl apply -f manifests/frontend-deployment.yaml
kubectl apply -f manifests/frontend-service.yaml

Wait for the frontend LoadBalancer and verify it's ready:

FRONTEND_ELB_PUBLIC_FQDN=$(kubectl get svc frontend -ojsonpath="{.status.loadBalancer.ingress[0].hostname}")
until nslookup $FRONTEND_ELB_PUBLIC_FQDN >/dev/null 2>&1; do sleep 2 && echo "Waiting for DNS..."; done
curl -I $FRONTEND_ELB_PUBLIC_FQDN

Get the application URL:

echo "Application URL: http://$FRONTEND_ELB_PUBLIC_FQDN"

Step 7: Test the Application

  1. Open the frontend URL in your browser
  2. Click the +1 buttons to vote for programming languages
  3. Verify votes are recorded in MongoDB:
kubectl exec -it mongo-0 -- mongo langdb --eval "db.languages.find().pretty()"

Troubleshooting

  • EBS volumes not provisioning: Verify the EBS CSI driver addon is installed and the IAM role has correct permissions
  • Pods not starting: Check logs with kubectl logs <pod-name> -n cloudchamp
  • DNS not resolving: Wait a few minutes for AWS to propagate DNS records
  • MongoDB replica set issues: Verify all three pods are running with kubectl get pods -n cloudchamp
  • Frontend can't reach API: Ensure the API LoadBalancer hostname is correctly set

Cleanup

To remove all resources:

# Delete the application
kubectl delete ns cloudchamp

# Delete the EBS CSI addon
aws eks delete-addon --cluster-name voting-app-cluster --addon-name aws-ebs-csi-driver --region us-west-2

# Delete the cluster
aws eks delete-cluster --name voting-app-cluster --region us-west-2

# Delete IAM resources
aws iam detach-role-policy --role-name EBSCSIDriverRole --policy-arn arn:aws:iam::$ACCOUNT_ID:policy/EBSCSIDriverPolicy
aws iam delete-role --role-name EBSCSIDriverRole
aws iam delete-policy --policy-arn arn:aws:iam::$ACCOUNT_ID:policy/EBSCSIDriverPolicy

Summary

This deployment demonstrates a complete cloud-native application stack on EKS Auto Mode with:

  • Multi-tier microservices architecture
  • Stateful database with replica set
  • High availability through multiple replicas
  • Persistent data storage with EBS CSI driver
  • Secure credential management
  • External access via LoadBalancer services
  • Automated cluster operations with EKS Auto Mode
  • IAM-based security for AWS resource access

About

This is a 3-tier application deployed in EKS.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published