mirror of
https://github.com/karpathy/nanochat.git
synced 2026-05-07 08:19:52 +00:00
- deploy.sh: single script to switch between EC2 and EKS modes - ec2: docker-compose with ECR images + nginx SSL reverse proxy - eks: terraform apply + helm install (for demos/grading) - eks-down: terraform destroy (stop costs) - docker-compose.prod.yml: ECR image overrides + nginx service - nginx/nginx.conf: reverse proxy with SSL, SSE streaming support - deploy-ec2.yml: auto-deploy to EC2 after images are built - Remove old single-server deploy.yml Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
265 lines
10 KiB
Bash
Executable File
265 lines
10 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
###############################################################################
|
|
# samosaChaat Deploy Switch
|
|
#
|
|
# Usage:
|
|
# ./deploy.sh ec2 Deploy monolith to EC2 via docker-compose
|
|
# ./deploy.sh ec2-down Stop services on EC2
|
|
# ./deploy.sh eks Provision EKS + deploy via Helm (demo/grading)
|
|
# ./deploy.sh eks-down Tear down EKS (save $$$)
|
|
# ./deploy.sh status Show what's currently running
|
|
###############################################################################
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
AWS_ACCOUNT="883107058766"
|
|
AWS_REGION="us-west-2"
|
|
ECR_REGISTRY="${AWS_ACCOUNT}.dkr.ecr.${AWS_REGION}.amazonaws.com"
|
|
EC2_HOST="52.10.243.118"
|
|
EC2_USER="ubuntu"
|
|
EC2_KEY="$HOME/.ssh/samosachaat.pem" # adjust if your key is elsewhere
|
|
DOMAIN="samosachaat.art"
|
|
|
|
# Colors
|
|
RED='\033[0;31m'
|
|
GREEN='\033[0;32m'
|
|
YELLOW='\033[1;33m'
|
|
NC='\033[0m'
|
|
|
|
log() { echo -e "${GREEN}[samosaChaat]${NC} $1"; }
|
|
warn() { echo -e "${YELLOW}[samosaChaat]${NC} $1"; }
|
|
err() { echo -e "${RED}[samosaChaat]${NC} $1" >&2; }
|
|
|
|
#─── EC2 MONOLITH ─────────────────────────────────────────────────────────────
|
|
|
|
ec2_deploy() {
|
|
log "Deploying to EC2 monolith at ${EC2_HOST}..."
|
|
|
|
# 1. Login to ECR locally to get credentials
|
|
log "Logging into ECR..."
|
|
aws ecr get-login-password --region ${AWS_REGION} | \
|
|
ssh -i "${EC2_KEY}" -o StrictHostKeyChecking=no ${EC2_USER}@${EC2_HOST} \
|
|
"docker login --username AWS --password-stdin ${ECR_REGISTRY}" 2>/dev/null
|
|
|
|
# 2. Sync repo to EC2
|
|
log "Syncing code to EC2..."
|
|
ssh -i "${EC2_KEY}" ${EC2_USER}@${EC2_HOST} bash -s << 'REMOTE_SCRIPT'
|
|
set -e
|
|
cd /home/ubuntu
|
|
|
|
# Clone or update repo
|
|
if [ -d samosachaat ]; then
|
|
cd samosachaat
|
|
git fetch origin master
|
|
git reset --hard origin/master
|
|
else
|
|
git clone https://github.com/manmohan659/nanochat.git samosachaat
|
|
cd samosachaat
|
|
fi
|
|
|
|
# Ensure .env exists
|
|
if [ ! -f .env ]; then
|
|
cp .env.example .env
|
|
echo "⚠️ Created .env from template — edit it with real values!"
|
|
fi
|
|
REMOTE_SCRIPT
|
|
|
|
# 3. Copy .env from local if it exists
|
|
if [ -f "${SCRIPT_DIR}/.env" ]; then
|
|
log "Syncing .env to EC2..."
|
|
scp -i "${EC2_KEY}" "${SCRIPT_DIR}/.env" ${EC2_USER}@${EC2_HOST}:/home/ubuntu/samosachaat/.env
|
|
fi
|
|
|
|
# 4. Pull images and start services
|
|
log "Pulling images and starting services..."
|
|
ssh -i "${EC2_KEY}" ${EC2_USER}@${EC2_HOST} bash -s << REMOTE_DEPLOY
|
|
set -e
|
|
cd /home/ubuntu/samosachaat
|
|
|
|
# Set ECR registry in environment
|
|
export ECR_REGISTRY=${ECR_REGISTRY}
|
|
export IMAGE_TAG=dev-latest
|
|
|
|
# Pull latest images
|
|
docker compose -f docker-compose.yml -f docker-compose.prod.yml pull
|
|
|
|
# Start everything
|
|
docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d
|
|
|
|
# Run DB migrations
|
|
echo "Running database migrations..."
|
|
sleep 5 # wait for postgres to be ready
|
|
docker compose exec -T chat-api alembic upgrade head 2>/dev/null || \
|
|
echo "Migrations skipped (may need manual .env setup)"
|
|
|
|
echo ""
|
|
docker compose ps
|
|
REMOTE_DEPLOY
|
|
|
|
# 5. Setup SSL if not already done
|
|
log "Checking SSL..."
|
|
ssh -i "${EC2_KEY}" ${EC2_USER}@${EC2_HOST} bash -s << 'SSL_CHECK'
|
|
if [ ! -d /etc/letsencrypt/live/samosachaat.art ]; then
|
|
echo "Setting up SSL with certbot..."
|
|
sudo apt-get update -qq && sudo apt-get install -y -qq certbot > /dev/null 2>&1
|
|
sudo certbot certonly --standalone --non-interactive \
|
|
--agree-tos -m manmohan659@gmail.com \
|
|
-d samosachaat.art -d www.samosachaat.art \
|
|
--pre-hook "docker compose -f /home/ubuntu/samosachaat/docker-compose.yml -f /home/ubuntu/samosachaat/docker-compose.prod.yml stop nginx" \
|
|
--post-hook "docker compose -f /home/ubuntu/samosachaat/docker-compose.yml -f /home/ubuntu/samosachaat/docker-compose.prod.yml start nginx"
|
|
else
|
|
echo "SSL already configured."
|
|
fi
|
|
SSL_CHECK
|
|
|
|
echo ""
|
|
log "EC2 deploy complete!"
|
|
log " App: https://${DOMAIN}"
|
|
log " Grafana: https://${DOMAIN}/grafana/"
|
|
log " EC2: ${EC2_HOST}"
|
|
}
|
|
|
|
ec2_down() {
|
|
log "Stopping services on EC2..."
|
|
ssh -i "${EC2_KEY}" ${EC2_USER}@${EC2_HOST} \
|
|
"cd /home/ubuntu/samosachaat && docker compose -f docker-compose.yml -f docker-compose.prod.yml down"
|
|
log "EC2 services stopped."
|
|
}
|
|
|
|
#─── EKS CLUSTER ──────────────────────────────────────────────────────────────
|
|
|
|
eks_deploy() {
|
|
local ENV="${1:-dev}"
|
|
log "Provisioning EKS cluster (${ENV})... This takes ~15-20 minutes."
|
|
|
|
cd "${SCRIPT_DIR}/terraform/environments/${ENV}"
|
|
|
|
# Init & apply Terraform
|
|
log "Running terraform init..."
|
|
terraform init
|
|
|
|
log "Running terraform apply..."
|
|
terraform apply -auto-approve
|
|
|
|
# Get cluster info
|
|
local CLUSTER_NAME=$(terraform output -raw eks_cluster_name 2>/dev/null || echo "samosachaat-${ENV}")
|
|
log "Configuring kubectl for ${CLUSTER_NAME}..."
|
|
aws eks update-kubeconfig --name "${CLUSTER_NAME}" --region ${AWS_REGION}
|
|
|
|
# Install ALB Ingress Controller
|
|
log "Installing ALB Ingress Controller..."
|
|
helm repo add eks https://aws.github.io/eks-charts 2>/dev/null || true
|
|
helm repo update
|
|
helm upgrade --install aws-load-balancer-controller eks/aws-load-balancer-controller \
|
|
-n kube-system \
|
|
--set clusterName="${CLUSTER_NAME}" \
|
|
--set serviceAccount.create=true \
|
|
--set serviceAccount.name=aws-load-balancer-controller \
|
|
--wait --timeout 5m 2>/dev/null || warn "ALB controller may need IRSA setup"
|
|
|
|
# Deploy observability stack
|
|
log "Deploying observability stack..."
|
|
helm dependency build "${SCRIPT_DIR}/helm/observability" 2>/dev/null || true
|
|
helm upgrade --install observability "${SCRIPT_DIR}/helm/observability" \
|
|
--namespace monitoring --create-namespace \
|
|
--wait --timeout 10m 2>/dev/null || warn "Observability deploy needs review"
|
|
|
|
# Deploy samosaChaat
|
|
local VALUES_FILE="${SCRIPT_DIR}/helm/samosachaat/values-${ENV}.yaml"
|
|
log "Deploying samosaChaat to EKS..."
|
|
helm upgrade --install samosachaat "${SCRIPT_DIR}/helm/samosachaat" \
|
|
-f "${VALUES_FILE}" \
|
|
--set global.imageRegistry="${ECR_REGISTRY}" \
|
|
--set global.imageTag="dev-latest" \
|
|
--set ingress.acmCertArn="$(terraform output -raw acm_certificate_arn 2>/dev/null || echo '')" \
|
|
--namespace samosachaat --create-namespace \
|
|
--wait --timeout 10m
|
|
|
|
echo ""
|
|
log "EKS deploy complete!"
|
|
log " Cluster: ${CLUSTER_NAME}"
|
|
kubectl get pods -n samosachaat
|
|
echo ""
|
|
kubectl get ingress -n samosachaat 2>/dev/null || true
|
|
}
|
|
|
|
eks_down() {
|
|
local ENV="${1:-dev}"
|
|
warn "Tearing down EKS cluster (${ENV})... This saves ~\$0.10/hr + node costs."
|
|
|
|
cd "${SCRIPT_DIR}/terraform/environments/${ENV}"
|
|
|
|
# Remove Helm releases first (cleans up ALB, etc.)
|
|
local CLUSTER_NAME=$(terraform output -raw eks_cluster_name 2>/dev/null || echo "samosachaat-${ENV}")
|
|
aws eks update-kubeconfig --name "${CLUSTER_NAME}" --region ${AWS_REGION} 2>/dev/null || true
|
|
|
|
log "Removing Helm releases..."
|
|
helm uninstall samosachaat -n samosachaat 2>/dev/null || true
|
|
helm uninstall observability -n monitoring 2>/dev/null || true
|
|
helm uninstall aws-load-balancer-controller -n kube-system 2>/dev/null || true
|
|
|
|
# Destroy infrastructure
|
|
log "Running terraform destroy..."
|
|
terraform destroy -auto-approve
|
|
|
|
log "EKS cluster destroyed. Costs stopped."
|
|
}
|
|
|
|
#─── STATUS ───────────────────────────────────────────────────────────────────
|
|
|
|
show_status() {
|
|
echo ""
|
|
log "=== samosaChaat Deployment Status ==="
|
|
echo ""
|
|
|
|
# Check EC2
|
|
echo "EC2 Monolith (${EC2_HOST}):"
|
|
if ssh -i "${EC2_KEY}" -o ConnectTimeout=5 ${EC2_USER}@${EC2_HOST} \
|
|
"docker compose -f /home/ubuntu/samosachaat/docker-compose.yml -f /home/ubuntu/samosachaat/docker-compose.prod.yml ps --format 'table {{.Name}}\t{{.Status}}'" 2>/dev/null; then
|
|
echo ""
|
|
else
|
|
echo " Not running or unreachable."
|
|
fi
|
|
|
|
# Check EKS
|
|
echo "EKS Cluster:"
|
|
if kubectl get nodes 2>/dev/null; then
|
|
echo ""
|
|
kubectl get pods -n samosachaat 2>/dev/null || echo " No samosachaat namespace."
|
|
else
|
|
echo " No EKS cluster configured."
|
|
fi
|
|
|
|
# Check ECR images
|
|
echo ""
|
|
echo "ECR Images (latest):"
|
|
for svc in frontend auth chat-api inference; do
|
|
TAG=$(aws ecr describe-images --repository-name samosachaat/${svc} --region ${AWS_REGION} \
|
|
--query 'sort_by(imageDetails,&imagePushedAt)[-1].imageTags[0]' --output text 2>/dev/null || echo "none")
|
|
echo " samosachaat/${svc}: ${TAG}"
|
|
done
|
|
}
|
|
|
|
#─── MAIN ─────────────────────────────────────────────────────────────────────
|
|
|
|
case "${1:-help}" in
|
|
ec2) ec2_deploy ;;
|
|
ec2-down) ec2_down ;;
|
|
eks) eks_deploy "${2:-dev}" ;;
|
|
eks-down) eks_down "${2:-dev}" ;;
|
|
status) show_status ;;
|
|
*)
|
|
echo "samosaChaat Deploy Switch"
|
|
echo ""
|
|
echo "Usage: ./deploy.sh <mode>"
|
|
echo ""
|
|
echo "Modes:"
|
|
echo " ec2 Deploy monolith to EC2 (cheap, always-on)"
|
|
echo " ec2-down Stop EC2 services"
|
|
echo " eks [env] Provision EKS + deploy (demo/grading) [dev|uat|prod]"
|
|
echo " eks-down Tear down EKS (save \$\$\$)"
|
|
echo " status Show what's running"
|
|
;;
|
|
esac
|