mirror of
https://github.com/ghndrx/k8s-game-2048.git
synced 2026-02-10 14:54:59 +00:00
🚀 Complete automation pipeline with SSL, testing, and deployment
✨ Features: - Full SSL setup with Let's Encrypt for all environments - Automated CI/CD pipeline with GitHub Actions - Comprehensive smoke testing workflow - Auto-deploy to dev on main branch push - Manual staging/production deployments with confirmation - Istio + nginx SSL termination architecture 🔧 Infrastructure: - Migrated from Kourier to Istio for Knative ingress - nginx handles SSL termination and public traffic - Istio manages internal Knative service routing - Scale-to-zero configuration for all environments 🧪 Testing: - SSL certificate validation and expiry checks - Domain accessibility and content validation - Performance testing and redirect behavior validation - Automated smoke tests on every deployment 🌐 Domains: - Dev: https://2048-dev.wa.darknex.us - Staging: https://2048-staging.wa.darknex.us - Production: https://2048.wa.darknex.us 📦 Deployment: - Uses latest GHCR images with imagePullPolicy: Always - Automated secret management across namespaces - Environment-specific Knative service configurations - Clean manifest structure with proper labeling
This commit is contained in:
@@ -1,87 +1,101 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Deployment script for 2048 game environments
|
||||
# Usage: ./deploy.sh [dev|staging|prod] [image-tag]
|
||||
# Deployment script for 2048 game with Istio + nginx SSL setup
|
||||
# Usage: ./deploy.sh [env] where env = dev|staging|prod|all
|
||||
|
||||
set -e
|
||||
|
||||
ENVIRONMENT=${1:-dev}
|
||||
IMAGE_TAG=${2:-latest}
|
||||
ENVIRONMENT=${1:-all}
|
||||
REGISTRY="ghcr.io/ghndrx/k8s-game-2048"
|
||||
|
||||
echo "🚀 Deploying 2048 game to $ENVIRONMENT environment..."
|
||||
echo "🚀 Deploying 2048 game with Istio + nginx SSL..."
|
||||
echo "Environment: $ENVIRONMENT"
|
||||
|
||||
# Validate environment
|
||||
case $ENVIRONMENT in
|
||||
dev|staging|prod)
|
||||
dev|staging|prod|all)
|
||||
echo "✅ Valid environment: $ENVIRONMENT"
|
||||
;;
|
||||
*)
|
||||
echo "❌ Invalid environment. Use: dev, staging, or prod"
|
||||
echo "❌ Invalid environment. Use: dev, staging, prod, or all"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
# Check if kubectl is available
|
||||
# Check dependencies
|
||||
if ! command -v kubectl &> /dev/null; then
|
||||
echo "❌ kubectl is not installed. Please install kubectl first."
|
||||
echo "❌ kubectl is not installed"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check if cluster is accessible
|
||||
if ! kubectl cluster-info &> /dev/null; then
|
||||
echo "❌ Cannot access Kubernetes cluster. Please check your kubeconfig."
|
||||
echo "❌ Cannot access Kubernetes cluster"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Update image tag in manifests
|
||||
echo "🔧 Updating image tag to $IMAGE_TAG..."
|
||||
if [ "$ENVIRONMENT" = "dev" ]; then
|
||||
sed -i.bak "s|your-registry/game-2048:latest|$REGISTRY:$IMAGE_TAG|g" manifests/dev/service.yml
|
||||
elif [ "$ENVIRONMENT" = "staging" ]; then
|
||||
sed -i.bak "s|your-registry/game-2048:staging|$REGISTRY:$IMAGE_TAG|g" manifests/staging/service.yml
|
||||
# Deploy function for a single environment
|
||||
deploy_env() {
|
||||
local env=$1
|
||||
echo "📦 Deploying $env environment..."
|
||||
|
||||
# Apply namespace
|
||||
kubectl apply -f manifests/$env/namespace.yml
|
||||
|
||||
# Ensure GHCR secret exists in the namespace
|
||||
echo "🔐 Setting up GHCR secret for $env..."
|
||||
if kubectl get secret ghcr-secret -n default &>/dev/null; then
|
||||
kubectl get secret ghcr-secret -o yaml | \
|
||||
sed "s/namespace: default/namespace: game-2048-$env/" | \
|
||||
sed '/resourceVersion:/d' | \
|
||||
sed '/uid:/d' | \
|
||||
sed '/creationTimestamp:/d' | \
|
||||
kubectl apply -f -
|
||||
else
|
||||
echo "⚠️ Warning: No GHCR secret found in default namespace"
|
||||
fi
|
||||
|
||||
# Apply service
|
||||
kubectl apply -f manifests/$env/service.yml
|
||||
|
||||
# Wait for service to be ready
|
||||
echo "⏳ Waiting for $env service to be ready..."
|
||||
kubectl wait --for=condition=Ready ksvc/game-2048-$env -n game-2048-$env --timeout=300s || echo "Warning: Service may still be starting"
|
||||
}
|
||||
|
||||
# Deploy infrastructure (certificates, gateways, etc.)
|
||||
echo "🏗️ Setting up infrastructure..."
|
||||
kubectl apply -f manifests/ssl-certificate.yaml
|
||||
kubectl apply -f manifests/nginx-certificate.yaml
|
||||
kubectl apply -f manifests/knative-domain-config.yaml
|
||||
kubectl apply -f manifests/istio-gateway.yaml
|
||||
kubectl apply -f manifests/nginx-to-istio-proxy.yaml
|
||||
|
||||
# Deploy environments
|
||||
if [ "$ENVIRONMENT" = "all" ]; then
|
||||
deploy_env "dev"
|
||||
deploy_env "staging"
|
||||
deploy_env "prod"
|
||||
else
|
||||
sed -i.bak "s|your-registry/game-2048:v1.0.0|$REGISTRY:$IMAGE_TAG|g" manifests/prod/service.yml
|
||||
deploy_env "$ENVIRONMENT"
|
||||
fi
|
||||
|
||||
# Deploy to the specified environment
|
||||
echo "📦 Deploying to $ENVIRONMENT..."
|
||||
kubectl apply -f manifests/$ENVIRONMENT/
|
||||
|
||||
# Wait for deployment to be ready
|
||||
echo "⏳ Waiting for deployment to be ready..."
|
||||
kubectl wait --for=condition=Ready ksvc/game-2048-$ENVIRONMENT -n game-2048-$ENVIRONMENT --timeout=300s
|
||||
|
||||
# Get service details
|
||||
echo ""
|
||||
echo "✅ Deployment completed!"
|
||||
echo ""
|
||||
echo "🔍 Service details:"
|
||||
kubectl get ksvc game-2048-$ENVIRONMENT -n game-2048-$ENVIRONMENT -o wide
|
||||
|
||||
echo ""
|
||||
echo "🌐 Service URL:"
|
||||
kubectl get ksvc game-2048-$ENVIRONMENT -n game-2048-$ENVIRONMENT -o jsonpath='{.status.url}'
|
||||
echo ""
|
||||
|
||||
echo ""
|
||||
echo "🎯 Custom domain:"
|
||||
case $ENVIRONMENT in
|
||||
dev)
|
||||
echo "https://2048-dev.wa.darknex.us"
|
||||
;;
|
||||
staging)
|
||||
echo "https://2048-staging.wa.darknex.us"
|
||||
;;
|
||||
prod)
|
||||
echo "https://2048.wa.darknex.us"
|
||||
;;
|
||||
esac
|
||||
|
||||
# Restore original manifests
|
||||
echo "🔄 Restoring original manifests..."
|
||||
if [ -f "manifests/$ENVIRONMENT/service.yml.bak" ]; then
|
||||
mv manifests/$ENVIRONMENT/service.yml.bak manifests/$ENVIRONMENT/service.yml
|
||||
echo "<EFBFBD> Your 2048 game is available at:"
|
||||
if [ "$ENVIRONMENT" = "all" ] || [ "$ENVIRONMENT" = "dev" ]; then
|
||||
echo " Development: https://2048-dev.wa.darknex.us"
|
||||
fi
|
||||
if [ "$ENVIRONMENT" = "all" ] || [ "$ENVIRONMENT" = "staging" ]; then
|
||||
echo " Staging: https://2048-staging.wa.darknex.us"
|
||||
fi
|
||||
if [ "$ENVIRONMENT" = "all" ] || [ "$ENVIRONMENT" = "prod" ]; then
|
||||
echo " Production: https://2048.wa.darknex.us"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "🎮 Game deployed successfully! You can now access it at the custom domain."
|
||||
echo "🔧 Check status with:"
|
||||
echo " kubectl get ksvc -A"
|
||||
echo " kubectl get certificates -A"
|
||||
echo " kubectl get ingress -A"
|
||||
echo ""
|
||||
echo "📝 Architecture: Internet → nginx (SSL) → Istio → Knative"
|
||||
|
||||
@@ -1,105 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
echo "🔧 Setting up SSL for 2048 Game with Kourier..."
|
||||
|
||||
# Colors for output
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# Function to print colored output
|
||||
print_status() {
|
||||
echo -e "${GREEN}[INFO]${NC} $1"
|
||||
}
|
||||
|
||||
print_warning() {
|
||||
echo -e "${YELLOW}[WARN]${NC} $1"
|
||||
}
|
||||
|
||||
print_error() {
|
||||
echo -e "${RED}[ERROR]${NC} $1"
|
||||
}
|
||||
|
||||
# Check if kubectl is available
|
||||
if ! command -v kubectl &> /dev/null; then
|
||||
print_error "kubectl is not installed or not in PATH"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check if cluster is accessible
|
||||
if ! kubectl cluster-info &> /dev/null; then
|
||||
print_error "Cannot connect to Kubernetes cluster"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
print_status "Installing cert-manager..."
|
||||
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.13.0/cert-manager.yaml
|
||||
|
||||
print_status "Waiting for cert-manager to be ready..."
|
||||
kubectl wait --for=condition=ready pod -l app=cert-manager -n cert-manager --timeout=120s
|
||||
kubectl wait --for=condition=ready pod -l app=cainjector -n cert-manager --timeout=120s
|
||||
kubectl wait --for=condition=ready pod -l app=webhook -n cert-manager --timeout=120s
|
||||
|
||||
print_status "Applying SSL certificate configuration..."
|
||||
kubectl apply -f manifests/ssl-certificate.yaml
|
||||
|
||||
print_status "Configuring Knative domain..."
|
||||
kubectl apply -f manifests/knative-domain-config.yaml
|
||||
|
||||
print_status "Configuring Kourier for SSL..."
|
||||
kubectl apply -f manifests/kourier-ssl-config.yaml
|
||||
|
||||
print_status "Deploying all environments..."
|
||||
kubectl apply -f manifests/dev/
|
||||
kubectl apply -f manifests/staging/
|
||||
kubectl apply -f manifests/prod/
|
||||
|
||||
print_status "Waiting for certificate to be issued..."
|
||||
echo "This may take a few minutes..."
|
||||
|
||||
# Wait for certificate to be ready
|
||||
timeout=300
|
||||
counter=0
|
||||
while [ $counter -lt $timeout ]; do
|
||||
if kubectl get certificate darknex-wildcard-cert -n knative-serving -o jsonpath='{.status.conditions[?(@.type=="Ready")].status}' | grep -q "True"; then
|
||||
print_status "Certificate is ready!"
|
||||
break
|
||||
fi
|
||||
echo -n "."
|
||||
sleep 10
|
||||
counter=$((counter + 10))
|
||||
done
|
||||
|
||||
if [ $counter -ge $timeout ]; then
|
||||
print_warning "Certificate is taking longer than expected to be issued."
|
||||
print_warning "You can check the status with: kubectl describe certificate darknex-wildcard-cert -n knative-serving"
|
||||
fi
|
||||
|
||||
print_status "Checking deployment status..."
|
||||
echo ""
|
||||
echo "=== Certificate Status ==="
|
||||
kubectl get certificates -n knative-serving
|
||||
|
||||
echo ""
|
||||
echo "=== Domain Mappings ==="
|
||||
kubectl get domainmappings --all-namespaces
|
||||
|
||||
echo ""
|
||||
echo "=== Knative Services ==="
|
||||
kubectl get ksvc --all-namespaces
|
||||
|
||||
echo ""
|
||||
print_status "🎉 SSL setup complete!"
|
||||
echo ""
|
||||
echo "Your 2048 game should be accessible at:"
|
||||
echo " • Development: https://2048-dev.wa.darknex.us"
|
||||
echo " • Staging: https://2048-staging.wa.darknex.us"
|
||||
echo " • Production: https://2048.wa.darknex.us"
|
||||
echo ""
|
||||
echo "To test SSL is working:"
|
||||
echo " curl -I https://2048-dev.wa.darknex.us"
|
||||
echo " curl -I https://2048-staging.wa.darknex.us"
|
||||
echo " curl -I https://2048.wa.darknex.us"
|
||||
|
||||
250
scripts/smoke-test.sh
Normal file
250
scripts/smoke-test.sh
Normal file
@@ -0,0 +1,250 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Smoke test script for 2048 game deployment
|
||||
# Tests all environments and validates the complete flow
|
||||
|
||||
set -e
|
||||
|
||||
# Colors for output
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# Test configuration
|
||||
ENVIRONMENTS=("dev" "staging" "prod")
|
||||
DOMAINS=("2048-dev.wa.darknex.us" "2048-staging.wa.darknex.us" "2048.wa.darknex.us")
|
||||
CANONICAL_DOMAINS=("game-2048-dev.game-2048-dev.dev.wa.darknex.us" "game-2048-staging.game-2048-staging.staging.wa.darknex.us" "game-2048-prod.game-2048-prod.wa.darknex.us")
|
||||
TIMEOUT=30
|
||||
|
||||
echo -e "${BLUE}🧪 Starting 2048 Game Smoke Tests${NC}"
|
||||
echo "=================================="
|
||||
|
||||
# Function to test HTTP response
|
||||
test_http_response() {
|
||||
local url=$1
|
||||
local expected_status=$2
|
||||
local test_name=$3
|
||||
|
||||
echo -n " Testing $test_name... "
|
||||
|
||||
response=$(curl -s -w "%{http_code}" -o /tmp/response.html --max-time $TIMEOUT "$url" 2>/dev/null || echo "000")
|
||||
|
||||
if [ "$response" = "$expected_status" ]; then
|
||||
echo -e "${GREEN}✅ PASS${NC} (HTTP $response)"
|
||||
return 0
|
||||
else
|
||||
echo -e "${RED}❌ FAIL${NC} (HTTP $response, expected $expected_status)"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to test SSL certificate
|
||||
test_ssl_cert() {
|
||||
local domain=$1
|
||||
echo -n " Testing SSL certificate for $domain... "
|
||||
|
||||
if echo | openssl s_client -servername "$domain" -connect "$domain:443" -verify_return_error &>/dev/null; then
|
||||
echo -e "${GREEN}✅ VALID${NC}"
|
||||
return 0
|
||||
else
|
||||
echo -e "${RED}❌ INVALID${NC}"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to test content
|
||||
test_content() {
|
||||
local url=$1
|
||||
local expected_text=$2
|
||||
local test_name=$3
|
||||
|
||||
echo -n " Testing $test_name content... "
|
||||
|
||||
if curl -s --max-time $TIMEOUT "$url" | grep -q "$expected_text"; then
|
||||
echo -e "${GREEN}✅ FOUND${NC}"
|
||||
return 0
|
||||
else
|
||||
echo -e "${RED}❌ NOT FOUND${NC}"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to test Kubernetes resources
|
||||
test_k8s_resources() {
|
||||
local env=$1
|
||||
echo -e "${YELLOW}📋 Testing Kubernetes Resources for $env${NC}"
|
||||
|
||||
# Test namespace
|
||||
echo -n " Checking namespace game-2048-$env... "
|
||||
if kubectl get namespace "game-2048-$env" &>/dev/null; then
|
||||
echo -e "${GREEN}✅ EXISTS${NC}"
|
||||
else
|
||||
echo -e "${RED}❌ MISSING${NC}"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Test Knative service
|
||||
echo -n " Checking Knative service... "
|
||||
if kubectl get ksvc "game-2048-$env" -n "game-2048-$env" &>/dev/null; then
|
||||
local status=$(kubectl get ksvc "game-2048-$env" -n "game-2048-$env" -o jsonpath='{.status.conditions[?(@.type=="Ready")].status}')
|
||||
if [ "$status" = "True" ]; then
|
||||
echo -e "${GREEN}✅ READY${NC}"
|
||||
else
|
||||
echo -e "${YELLOW}⏳ NOT READY${NC} (Status: $status)"
|
||||
fi
|
||||
else
|
||||
echo -e "${RED}❌ MISSING${NC}"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Test GHCR secret
|
||||
echo -n " Checking GHCR secret... "
|
||||
if kubectl get secret ghcr-secret -n "game-2048-$env" &>/dev/null; then
|
||||
echo -e "${GREEN}✅ EXISTS${NC}"
|
||||
else
|
||||
echo -e "${RED}❌ MISSING${NC}"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to test ingress
|
||||
test_ingress() {
|
||||
echo -e "${YELLOW}🌐 Testing Ingress Configuration${NC}"
|
||||
|
||||
# Test nginx ingress controller
|
||||
echo -n " Checking nginx ingress controller... "
|
||||
if kubectl get pods -n ingress-nginx | grep -q "ingress-nginx-controller.*Running"; then
|
||||
echo -e "${GREEN}✅ RUNNING${NC}"
|
||||
else
|
||||
echo -e "${RED}❌ NOT RUNNING${NC}"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Test Istio ingress gateway
|
||||
echo -n " Checking Istio ingress gateway... "
|
||||
if kubectl get pods -n istio-system | grep -q "istio-ingressgateway.*Running"; then
|
||||
echo -e "${GREEN}✅ RUNNING${NC}"
|
||||
else
|
||||
echo -e "${RED}❌ NOT RUNNING${NC}"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Test cert-manager
|
||||
echo -n " Checking cert-manager... "
|
||||
if kubectl get pods -n cert-manager | grep -q "cert-manager.*Running"; then
|
||||
echo -e "${GREEN}✅ RUNNING${NC}"
|
||||
else
|
||||
echo -e "${RED}❌ NOT RUNNING${NC}"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to test certificates
|
||||
test_certificates() {
|
||||
echo -e "${YELLOW}🔒 Testing SSL Certificates${NC}"
|
||||
|
||||
for i in "${!ENVIRONMENTS[@]}"; do
|
||||
local env="${ENVIRONMENTS[$i]}"
|
||||
local domain="${DOMAINS[$i]}"
|
||||
|
||||
echo -n " Checking certificate for $domain... "
|
||||
local cert_status=$(kubectl get certificate "game-2048-$env-nginx-cert" -o jsonpath='{.status.conditions[?(@.type=="Ready")].status}' 2>/dev/null || echo "Unknown")
|
||||
|
||||
if [ "$cert_status" = "True" ]; then
|
||||
echo -e "${GREEN}✅ READY${NC}"
|
||||
test_ssl_cert "$domain"
|
||||
else
|
||||
echo -e "${RED}❌ NOT READY${NC} (Status: $cert_status)"
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
# Main test execution
|
||||
main() {
|
||||
local total_tests=0
|
||||
local passed_tests=0
|
||||
|
||||
# Test infrastructure
|
||||
test_ingress
|
||||
test_certificates
|
||||
|
||||
# Test each environment
|
||||
for i in "${!ENVIRONMENTS[@]}"; do
|
||||
local env="${ENVIRONMENTS[$i]}"
|
||||
local domain="${DOMAINS[$i]}"
|
||||
local canonical_domain="${CANONICAL_DOMAINS[$i]}"
|
||||
|
||||
echo ""
|
||||
echo -e "${BLUE}🎮 Testing $env Environment${NC}"
|
||||
echo "Domain: https://$domain"
|
||||
echo "Canonical: https://$canonical_domain"
|
||||
echo "----------------------------------------"
|
||||
|
||||
# Test Kubernetes resources
|
||||
if test_k8s_resources "$env"; then
|
||||
((total_tests++))
|
||||
((passed_tests++))
|
||||
else
|
||||
((total_tests++))
|
||||
fi
|
||||
|
||||
# Test custom domain accessibility
|
||||
if test_http_response "https://$domain" "200\|301\|302" "custom domain"; then
|
||||
((total_tests++))
|
||||
((passed_tests++))
|
||||
else
|
||||
((total_tests++))
|
||||
fi
|
||||
|
||||
# Test canonical domain accessibility
|
||||
if test_http_response "https://$canonical_domain" "200" "canonical domain"; then
|
||||
((total_tests++))
|
||||
((passed_tests++))
|
||||
else
|
||||
((total_tests++))
|
||||
fi
|
||||
|
||||
# Test content
|
||||
if test_content "https://$canonical_domain" "2048" "game content"; then
|
||||
((total_tests++))
|
||||
((passed_tests++))
|
||||
else
|
||||
((total_tests++))
|
||||
fi
|
||||
|
||||
# Test environment-specific content
|
||||
local env_name=""
|
||||
case $env in
|
||||
"dev") env_name="development" ;;
|
||||
"staging") env_name="staging" ;;
|
||||
"prod") env_name="Production" ;;
|
||||
esac
|
||||
|
||||
if test_content "https://$canonical_domain" "$env_name" "environment detection"; then
|
||||
((total_tests++))
|
||||
((passed_tests++))
|
||||
else
|
||||
((total_tests++))
|
||||
fi
|
||||
done
|
||||
|
||||
echo ""
|
||||
echo "=================================="
|
||||
echo -e "${BLUE}📊 Test Summary${NC}"
|
||||
echo "Total Tests: $total_tests"
|
||||
echo -e "Passed: ${GREEN}$passed_tests${NC}"
|
||||
echo -e "Failed: ${RED}$((total_tests - passed_tests))${NC}"
|
||||
|
||||
if [ $passed_tests -eq $total_tests ]; then
|
||||
echo -e "${GREEN}🎉 All tests passed!${NC}"
|
||||
exit 0
|
||||
else
|
||||
echo -e "${RED}❌ Some tests failed${NC}"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Run main function
|
||||
main "$@"
|
||||
Reference in New Issue
Block a user