🚀 Week 8: Capstone Project

Day 4: Integration & Testing

⏱ Duration: 5 Hours

📚 Learning Objectives

  • Connect all project components together
  • Test the complete CI/CD pipeline end-to-end
  • Verify application deployment and functionality
  • Troubleshoot and fix integration issues
  • Implement monitoring and health checks

📖 Core Concepts (2 Hours)

Integration Architecture

End-to-End Flow: ┌─────────────────────────────────────────────────────────────┐ │ DEVELOPER │ │ ┌─────────────┐ │ │ │ Code Change │ │ │ └──────┬──────┘ │ │ │ git push │ │ ▼ │ ├─────────────────────────────────────────────────────────────┤ │ GITHUB │ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────┐ │ │ │ Repository │→ │ Actions │→ │ Trigger Pipeline │ │ │ └─────────────┘ └─────────────┘ └──────────┬──────────┘ │ │ │ │ ├──────────────────────────────────────────────┼──────────────┤ │ CI/CD PIPELINE │ │ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ │ │ │ Test │→ │ Build │→ │ Push │ │ │ │ │ pytest │ │ Docker │ │ to Hub │ │ │ │ └────┬────┘ └────┬────┘ └────┬────┘ │ │ │ │ │ │ │ │ │ │ Pass │ Image │ Tagged │ │ │ ▼ ▼ ▼ ▼ │ ├─────────────────────────────────────────────────────────────┤ │ DEPLOYMENT │ │ ┌─────────────────────────────────────────────────────────┐│ │ │ SSH to EC2 ││ │ │ docker pull → docker stop → docker run → health check ││ │ └─────────────────────────────────────────────────────────┘│ │ │ │ ├────────────────────────────┼────────────────────────────────┤ │ AWS EC2 ▼ │ │ ┌─────────────────────────────────────────────────────────┐│ │ │ Docker Container Running ││ │ │ ┌─────────────────────────────────────────────────┐ ││ │ │ │ Python Flask App │ ││ │ │ │ • GET / → Welcome message │ ││ │ │ │ • GET /health → Health status │ ││ │ │ │ • GET /api/info → App information │ ││ │ │ └─────────────────────────────────────────────────┘ ││ │ └─────────────────────────────────────────────────────────┘│ └─────────────────────────────────────────────────────────────┘

Integration Verification Script

#!/bin/bash # scripts/verify-deployment.sh # Comprehensive deployment verification script set -e # Configuration APP_URL="${APP_URL:-http://localhost:8000}" MAX_RETRIES=30 RETRY_INTERVAL=10 echo "==========================================" echo " Deployment Verification Script" echo "==========================================" echo "Target URL: $APP_URL" echo "" # Function to check endpoint check_endpoint() { local endpoint=$1 local expected_status=$2 local description=$3 echo -n "Testing $description... " response=$(curl -s -w "\n%{http_code}" "$APP_URL$endpoint" 2>/dev/null) status_code=$(echo "$response" | tail -n1) body=$(echo "$response" | sed '$d') if [ "$status_code" -eq "$expected_status" ]; then echo "✅ PASS (HTTP $status_code)" return 0 else echo "❌ FAIL (Expected $expected_status, got $status_code)" return 1 fi } # Function to wait for app to be ready wait_for_app() { echo "Waiting for application to be ready..." for i in $(seq 1 $MAX_RETRIES); do if curl -s -f "$APP_URL/health" > /dev/null 2>&1; then echo "✅ Application is ready!" return 0 fi echo "Attempt $i/$MAX_RETRIES - Waiting ${RETRY_INTERVAL}s..." sleep $RETRY_INTERVAL done echo "❌ Application did not become ready" return 1 } # Main verification echo "Step 1: Checking application availability" echo "----------------------------------------" wait_for_app echo "" echo "Step 2: Testing API endpoints" echo "----------------------------------------" check_endpoint "/" 200 "Root endpoint" check_endpoint "/health" 200 "Health check" check_endpoint "/api/info" 200 "Info endpoint" check_endpoint "/api/status" 200 "Status endpoint" check_endpoint "/nonexistent" 404 "404 handling" echo "" echo "Step 3: Validating response content" echo "----------------------------------------" # Check health response content health_response=$(curl -s "$APP_URL/health") if echo "$health_response" | grep -q '"status":"healthy"'; then echo "✅ Health check returns healthy status" else echo "❌ Health check response invalid" exit 1 fi # Check info response content info_response=$(curl -s "$APP_URL/api/info") if echo "$info_response" | grep -q '"app_name"'; then echo "✅ Info endpoint returns app details" else echo "❌ Info endpoint response invalid" exit 1 fi echo "" echo "==========================================" echo " All Verification Tests Passed! ✅" echo "=========================================="

Troubleshooting Common Issues

Common Integration Issues and Solutions: ┌────────────────────────────────────────────────────────────┐ │ Issue: Pipeline fails at Docker push │ │ Symptoms: Authentication error to Docker Hub │ │ Solution: │ │ 1. Verify DOCKERHUB_USERNAME secret is correct │ │ 2. Verify DOCKERHUB_TOKEN is an access token (not pwd) │ │ 3. Regenerate token if expired │ ├────────────────────────────────────────────────────────────┤ │ Issue: SSH deployment fails │ │ Symptoms: Connection refused or permission denied │ │ Solution: │ │ 1. Verify EC2_HOST is the correct public IP │ │ 2. Verify EC2_SSH_KEY format (full key with headers) │ │ 3. Check security group allows port 22 from GitHub IPs │ │ 4. Verify key permissions on EC2 │ ├────────────────────────────────────────────────────────────┤ │ Issue: Container won't start on EC2 │ │ Symptoms: Docker run fails or container exits immediately │ │ Solution: │ │ 1. SSH into EC2 and check: docker logs capstone-app │ │ 2. Verify image was pulled: docker images │ │ 3. Check port conflicts: netstat -tlnp │ │ 4. Check system resources: free -h, df -h │ ├────────────────────────────────────────────────────────────┤ │ Issue: Application unreachable from internet │ │ Symptoms: Connection timeout when accessing app URL │ │ Solution: │ │ 1. Verify security group allows port 8000/80 │ │ 2. Verify EC2 has public IP/Elastic IP │ │ 3. Check container is running: docker ps │ │ 4. Check container port binding: docker port capstone-app│ ├────────────────────────────────────────────────────────────┤ │ Issue: Health check fails in CI/CD │ │ Symptoms: Deployment job fails at verification step │ │ Solution: │ │ 1. Increase wait time before health check │ │ 2. Check application logs: docker logs capstone-app │ │ 3. Verify health endpoint path: /health │ │ 4. Test locally first: curl http://localhost:8000/health │ └────────────────────────────────────────────────────────────┘

EC2 Debugging Commands

# SSH into EC2 instance ssh -i ~/.ssh/your-key.pem ec2-user@EC2_PUBLIC_IP # Check Docker status sudo systemctl status docker # List running containers docker ps -a # Check container logs docker logs capstone-app docker logs --tail 50 -f capstone-app # Check if app is listening netstat -tlnp | grep 8000 # Test locally on EC2 curl http://localhost:8000/health # Check system resources free -h # Memory df -h # Disk space top -bn1 | head # CPU usage # Check user-data script execution cat /var/log/user-data-complete.log cat /var/log/cloud-init-output.log # Restart container manually docker stop capstone-app docker rm capstone-app docker run -d --name capstone-app -p 80:8000 -p 8000:8000 your-image:latest # Check security group rules (from AWS CLI) aws ec2 describe-security-groups --group-ids sg-xxx

🔬 Hands-on Lab (2.5 Hours)

Lab 1: Trigger Full Pipeline

# Make a code change to trigger CI/CD cd capstone-project # Update app version sed -i 's/APP_VERSION = "1.0.0"/APP_VERSION = "1.1.0"/' app/main.py # Or add a new endpoint cat >> app/main.py << 'EOF' @app.route("/api/version") def version(): """Version endpoint""" return jsonify({ "version": APP_VERSION, "updated": "Day 4 Integration" }) EOF # Commit and push git add . git commit -m "Add version endpoint - trigger CI/CD" git push origin main # Monitor pipeline echo "Watch pipeline at: https://github.com/YOUR_USERNAME/capstone-project/actions"

Lab 2: Verify Deployment End-to-End

# Get EC2 public IP from Terraform cd terraform APP_IP=$(terraform output -raw instance_public_ip) echo "Application IP: $APP_IP" # Wait for pipeline to complete (check GitHub Actions) # Test all endpoints echo "Testing endpoints..." curl -s "http://$APP_IP:8000/" | jq . curl -s "http://$APP_IP:8000/health" | jq . curl -s "http://$APP_IP:8000/api/info" | jq . curl -s "http://$APP_IP:8000/api/version" | jq . # Verify version was updated VERSION=$(curl -s "http://$APP_IP:8000/api/info" | jq -r '.version') echo "Deployed version: $VERSION" # Test response times echo "Testing response times..." for i in {1..5}; do time curl -s "http://$APP_IP:8000/health" > /dev/null done

Lab 3: Implement Basic Monitoring

# Create monitoring script cat > scripts/monitor.sh << 'EOF' #!/bin/bash # Simple monitoring script APP_URL="${1:-http://localhost:8000}" LOG_FILE="monitoring.log" while true; do timestamp=$(date '+%Y-%m-%d %H:%M:%S') # Check health endpoint response=$(curl -s -w "%{http_code}:%{time_total}" "$APP_URL/health" 2>/dev/null) status_code=$(echo "$response" | grep -oE '[0-9]{3}:' | tr -d ':') response_time=$(echo "$response" | grep -oE ':[0-9.]+$' | tr -d ':') if [ "$status_code" = "200" ]; then echo "$timestamp | Status: UP | Response: ${response_time}s" | tee -a $LOG_FILE else echo "$timestamp | Status: DOWN | HTTP: $status_code" | tee -a $LOG_FILE # Could add alerting here (email, Slack, etc.) fi sleep 60 done EOF chmod +x scripts/monitor.sh # Run monitoring (in background) nohup ./scripts/monitor.sh "http://$APP_IP:8000" > /dev/null 2>&1 & echo "Monitoring started in background" # View monitoring log tail -f monitoring.log

Lab 4: Load Testing

# Simple load test with curl echo "Running simple load test..." APP_URL="http://$APP_IP:8000" REQUESTS=100 CONCURRENT=10 # Sequential test echo "Sequential requests:" time for i in $(seq 1 $REQUESTS); do curl -s "$APP_URL/health" > /dev/null done # Parallel test (if xargs available) echo "Parallel requests ($CONCURRENT concurrent):" time seq 1 $REQUESTS | xargs -P $CONCURRENT -I {} curl -s "$APP_URL/health" > /dev/null # Using Apache Bench (if installed) # ab -n 1000 -c 10 "$APP_URL/health" # Using hey (if installed) # hey -n 1000 -c 10 "$APP_URL/health" echo "Load test complete!"

Lab 5: Create Operations Runbook

# Create runbook documentation cat > docs/runbook.md << 'EOF' # Operations Runbook ## Quick Reference | Task | Command | |------|---------| | Check app status | `curl http://APP_IP:8000/health` | | SSH to EC2 | `ssh -i key.pem ec2-user@APP_IP` | | View logs | `docker logs capstone-app` | | Restart app | `docker restart capstone-app` | ## Deployment ### Manual Deployment ```bash ssh -i key.pem ec2-user@APP_IP docker pull your-user/capstone-app:latest docker stop capstone-app && docker rm capstone-app docker run -d --name capstone-app -p 80:8000 your-user/capstone-app:latest ``` ### Rollback ```bash # Deploy previous version docker run -d --name capstone-app -p 80:8000 your-user/capstone-app:v1.0.0 ``` ## Troubleshooting ### App Not Responding 1. Check if container is running: `docker ps` 2. Check container logs: `docker logs capstone-app` 3. Restart container: `docker restart capstone-app` ### High Memory Usage 1. Check memory: `free -h` 2. Check container stats: `docker stats capstone-app` 3. Restart if needed: `docker restart capstone-app` ### Deployment Failed 1. Check GitHub Actions logs 2. Verify secrets are configured 3. Test SSH connection manually ## Contacts - On-call: DevOps Team - Escalation: Platform Team EOF git add docs/runbook.md git commit -m "Add operations runbook" git push origin main

✅ Day 4 Checklist

  • Triggered full CI/CD pipeline with code change
  • Verified all API endpoints are accessible
  • Tested deployment automation end-to-end
  • Debugged and fixed any integration issues
  • Implemented basic health monitoring
  • Performed load testing
  • Created operations runbook