Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ bin/
obj/
.vs/
node_modules/
SESSION_NOTES.MD
66 changes: 66 additions & 0 deletions .kiro/specs/voting-app-aws/spec.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# Voting App -- AWS EKS Deployment Spec

## Overview
Deploy the dockersamples/example-voting-app on AWS EKS using DevOps best practices. The app consists of 5 services: vote (Python), result (Node.js), worker (.NET), redis, and postgres.

## Architecture
```
Internet
|
|---> ALB ---> vote Service (port 80) -- "Vote: Cats vs Dogs"
'---> ALB ---> result Service (port 80) -- "Live Results"
|
+------+-------+
v v
Redis Postgres
| |
'---- Worker --+
```

## AWS Resources
- **EKS Cluster**: `voting-app-cluster` -- t3.medium x2 nodes, ap-southeast-2
- **ECR**: 3 private repos -- vote, result, worker (redis/postgres use public images)
- **CodeBuild**: builds images, pushes to ECR, deploys to EKS
- **ALB**: via AWS Load Balancer Controller -- exposes vote and result
- **IAM**: least-privilege roles for CodeBuild and EKS nodes
- **SNS**: deployment notifications to fahadkhalid695@gmail.com
- **CloudWatch**: Container Insights enabled on EKS cluster

## Requirements

### Requirement 1 -- ECR Repositories
- [ ] Create ECR repos: `voting-app/vote`, `voting-app/result`, `voting-app/worker`
- [ ] Enable image scanning on push
- [ ] Lifecycle policy: keep last 10 images

### Requirement 2 -- EKS Cluster
- [ ] Create EKS cluster `voting-app-cluster` in ap-southeast-2
- [ ] Managed node group: t3.medium, min=2 max=4, desired=2
- [ ] Enable CloudWatch Container Insights
- [ ] Install AWS Load Balancer Controller via Helm
- [ ] Configure OIDC provider for IRSA

### Requirement 3 -- IAM Roles
- [ ] CodeBuild role: ECR push, EKS describe/update, SNS publish
- [ ] EKS node role: ECR pull, CloudWatch, SSM
- [ ] ALB Controller role (IRSA): elasticloadbalancing:*, ec2:Describe*

### Requirement 4 -- CodeBuild Pipeline
- [ ] Source: GitHub repo (dockersamples/example-voting-app)
- [ ] Build: docker build vote, result, worker -- push to ECR
- [ ] Deploy: kubectl apply k8s manifests with ECR image URIs
- [ ] Notify: SNS on success/failure

### Requirement 5 -- Kubernetes Manifests
- [ ] Namespace: `voting`
- [ ] Deployments: vote, result, worker, redis, db (postgres)
- [ ] Services: ClusterIP for redis/db/worker, LoadBalancer for vote/result
- [ ] ConfigMap for postgres credentials
- [ ] Resource limits on all containers
- [ ] Liveness and readiness probes

### Requirement 6 -- Verification
- [ ] Vote app accessible via ALB URL on port 80
- [ ] Result app accessible via ALB URL on port 80
- [ ] Cast a vote -- appears in result within 5 seconds
- [ ] SNS deployment notification received
Binary file added .tools/kubectl.exe
Binary file not shown.
89 changes: 89 additions & 0 deletions aws/buildspec.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
version: 0.2

env:
variables:
AWS_REGION: "ap-southeast-2"
# ACCOUNT_ID and ECR_BASE are injected by CodeBuild project environment variables
# (set via deploy.ps1 when the project is created -- no hardcoded values needed here)
ACCOUNT_ID: "YOUR_AWS_ACCOUNT_ID"
CLUSTER_NAME: "voting-app-cluster"
ECR_BASE: "YOUR_AWS_ACCOUNT_ID.dkr.ecr.ap-southeast-2.amazonaws.com"

phases:
install:
runtime-versions:
python: 3.11
commands:
- echo Installing kubectl
- curl -LO "https://dl.k8s.io/release/$(curl -Ls https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
- chmod +x kubectl && mv kubectl /usr/local/bin/
- kubectl version --client

pre_build:
commands:
- echo ECR Login
- aws ecr get-login-password --region $AWS_REGION | docker login --username AWS --password-stdin $ECR_BASE

- echo Configure kubeconfig
- aws eks update-kubeconfig --region $AWS_REGION --name $CLUSTER_NAME

- export IMAGE_TAG=$(echo $CODEBUILD_RESOLVED_SOURCE_VERSION | cut -c1-8)
- echo IMAGE_TAG=$IMAGE_TAG

# ── AWS Load Balancer Controller setup ──────────────────────────────
# ── CloudWatch Container Insights ──────────────────────────────────
build:
commands:
- echo Building Docker images
- docker build -t $ECR_BASE/voting-app/vote:$IMAGE_TAG -t $ECR_BASE/voting-app/vote:latest ./vote
- docker build -t $ECR_BASE/voting-app/result:$IMAGE_TAG -t $ECR_BASE/voting-app/result:latest ./result
- docker build -t $ECR_BASE/voting-app/worker:$IMAGE_TAG -t $ECR_BASE/voting-app/worker:latest ./worker

post_build:
commands:
- echo Pushing images to ECR
- docker push $ECR_BASE/voting-app/vote:$IMAGE_TAG
- docker push $ECR_BASE/voting-app/vote:latest
- docker push $ECR_BASE/voting-app/result:$IMAGE_TAG
- docker push $ECR_BASE/voting-app/result:latest
- docker push $ECR_BASE/voting-app/worker:$IMAGE_TAG
- docker push $ECR_BASE/voting-app/worker:latest

- echo Deploying to EKS
- kubectl apply -f aws/k8s/postgres-secret.yaml
- kubectl apply -f aws/k8s/configmap.yaml
- kubectl apply -f aws/k8s/redis-deployment.yaml
- kubectl apply -f aws/k8s/redis-service.yaml
- kubectl apply -f aws/k8s/db-pvc.yaml
- kubectl apply -f aws/k8s/db-deployment.yaml
- kubectl apply -f aws/k8s/db-service.yaml
- kubectl apply -f aws/k8s/vote-deployment.yaml
- kubectl apply -f aws/k8s/vote-service.yaml
- kubectl apply -f aws/k8s/result-deployment.yaml
- kubectl apply -f aws/k8s/result-service.yaml
- kubectl apply -f aws/k8s/worker-deployment.yaml

- echo Waiting for rollouts
- kubectl rollout status deployment/vote -n voting --timeout=300s
- kubectl rollout status deployment/result -n voting --timeout=300s
- kubectl rollout status deployment/worker -n voting --timeout=300s

- echo Fetching service URLs
- kubectl get svc -n voting
- |
VOTE_URL=$(kubectl get svc vote -n voting \
-o jsonpath='{.status.loadBalancer.ingress[0].hostname}' 2>/dev/null || echo "pending")
RESULT_URL=$(kubectl get svc result -n voting \
-o jsonpath='{.status.loadBalancer.ingress[0].hostname}' 2>/dev/null || echo "pending")
echo "Vote App -- http://$VOTE_URL"
echo "Result App -- http://$RESULT_URL"

if [ -n "$SNS_ARN" ] && [ "$SNS_ARN" != "None" ]; then
aws sns publish \
--topic-arn "$SNS_ARN" \
--subject "DEPLOYED - Voting App" \
--message "Deployment complete. Tag: $IMAGE_TAG | Vote: http://$VOTE_URL | Result: http://$RESULT_URL" \
--region $AWS_REGION
else
echo "SNS_ARN not set -- skipping notification"
fi
Loading