- Add Legal Office of the Master seal (SVG design with Maltese Cross, scales of justice, legal scroll) - Create legal-office-manifest-template.json for Legal Office credentials - Update SEAL_MAPPING.md and DESIGN_GUIDE.md with Legal Office seal documentation - Complete Azure CDN infrastructure deployment: - Resource group, storage account, and container created - 17 PNG seal files uploaded to Azure Blob Storage - All manifest templates updated with Azure URLs - Configuration files generated (azure-cdn-config.env) - Add comprehensive Azure CDN setup scripts and documentation - Fix manifest URL generation to prevent double slashes - Verify all seals accessible via HTTPS
133 lines
4.6 KiB
Bash
Executable File
133 lines
4.6 KiB
Bash
Executable File
#!/bin/bash
|
|
# Deploy Identity Service with Entra VerifiedID to Production
|
|
# Uses blue-green deployment strategy for zero downtime
|
|
|
|
set -euo pipefail
|
|
|
|
GREEN='\033[0;32m'
|
|
BLUE='\033[0;34m'
|
|
YELLOW='\033[1;33m'
|
|
RED='\033[0;31m'
|
|
NC='\033[0m'
|
|
|
|
log_info() { echo -e "${BLUE}[INFO]${NC} $1"; }
|
|
log_success() { echo -e "${GREEN}[SUCCESS]${NC} $1"; }
|
|
log_warning() { echo -e "${YELLOW}[WARNING]${NC} $1"; }
|
|
log_error() { echo -e "${RED}[ERROR]${NC} $1"; }
|
|
|
|
cd "$(dirname "$0")/../.."
|
|
|
|
# Safety check
|
|
log_warning "This will deploy to PRODUCTION. Are you sure?"
|
|
read -p "Type 'deploy-production' to confirm: " CONFIRM
|
|
|
|
if [ "${CONFIRM}" != "deploy-production" ]; then
|
|
log_error "Deployment cancelled"
|
|
exit 1
|
|
fi
|
|
|
|
# Check prerequisites
|
|
log_info "Checking prerequisites..."
|
|
|
|
if ! command -v kubectl &> /dev/null; then
|
|
log_error "kubectl not found"
|
|
exit 1
|
|
fi
|
|
|
|
if ! kubectl cluster-info &> /dev/null; then
|
|
log_error "Not connected to Kubernetes cluster"
|
|
exit 1
|
|
fi
|
|
|
|
NAMESPACE="the-order-prod"
|
|
|
|
# Verify production namespace
|
|
if ! kubectl get namespace "${NAMESPACE}" &> /dev/null; then
|
|
log_error "Production namespace not found: ${NAMESPACE}"
|
|
exit 1
|
|
fi
|
|
|
|
# Verify secrets exist
|
|
log_info "Verifying Entra secrets..."
|
|
if ! kubectl get secret entra-verifiedid-secrets -n "${NAMESPACE}" &> /dev/null; then
|
|
log_error "Entra secrets not found in production!"
|
|
log_info "Create secrets first: kubectl apply -f infra/k8s/identity-service-entra-secrets.yaml -n ${NAMESPACE}"
|
|
exit 1
|
|
fi
|
|
|
|
# Build and push image
|
|
IMAGE_TAG="prod-$(date +%Y%m%d-%H%M%S)"
|
|
IMAGE_NAME="ghcr.io/the-order/identity-service:${IMAGE_TAG}"
|
|
|
|
log_info "Building production image: ${IMAGE_NAME}"
|
|
docker build -t "${IMAGE_NAME}" -f services/identity/Dockerfile .
|
|
docker push "${IMAGE_NAME}"
|
|
log_success "Image built and pushed"
|
|
|
|
# Blue-Green Deployment Strategy
|
|
log_info "Starting blue-green deployment..."
|
|
|
|
# Create green deployment
|
|
log_info "Creating green deployment..."
|
|
sed "s|ghcr.io/the-order/identity-service:latest|${IMAGE_NAME}|g" \
|
|
infra/k8s/identity-service-deployment-entra.yaml | \
|
|
sed 's/name: identity-service/name: identity-service-green/' | \
|
|
sed 's/app: identity-service/app: identity-service-green/' > /tmp/identity-green.yaml
|
|
|
|
kubectl apply -f /tmp/identity-green.yaml -n "${NAMESPACE}"
|
|
|
|
# Wait for green to be ready
|
|
log_info "Waiting for green deployment to be ready..."
|
|
kubectl rollout status deployment/identity-service-green -n "${NAMESPACE}" --timeout=10m
|
|
|
|
# Health check on green
|
|
log_info "Running health checks on green deployment..."
|
|
GREEN_POD=$(kubectl get pod -n "${NAMESPACE}" -l app=identity-service-green -o jsonpath='{.items[0].metadata.name}')
|
|
|
|
if kubectl exec -n "${NAMESPACE}" "${GREEN_POD}" -- curl -sf http://localhost:4002/health > /dev/null; then
|
|
log_success "Green deployment is healthy"
|
|
else
|
|
log_error "Green deployment health check failed!"
|
|
log_info "Rolling back..."
|
|
kubectl delete deployment identity-service-green -n "${NAMESPACE}"
|
|
exit 1
|
|
fi
|
|
|
|
# Switch traffic to green
|
|
log_info "Switching traffic to green deployment..."
|
|
kubectl patch service identity-service -n "${NAMESPACE}" -p '{"spec":{"selector":{"app":"identity-service-green"}}}'
|
|
|
|
# Wait and verify
|
|
sleep 10
|
|
log_info "Verifying service after switch..."
|
|
if curl -sf https://api.theorder.org/health > /dev/null; then
|
|
log_success "Service is responding"
|
|
else
|
|
log_warning "Service health check failed (may need more time)"
|
|
fi
|
|
|
|
# Scale down blue (old) deployment
|
|
log_info "Scaling down blue deployment..."
|
|
if kubectl get deployment identity-service -n "${NAMESPACE}" &> /dev/null; then
|
|
kubectl scale deployment identity-service -n "${NAMESPACE}" --replicas=0
|
|
log_success "Blue deployment scaled down"
|
|
fi
|
|
|
|
# Rename green to main
|
|
log_info "Promoting green to main deployment..."
|
|
kubectl delete deployment identity-service -n "${NAMESPACE}" 2>/dev/null || true
|
|
kubectl patch deployment identity-service-green -n "${NAMESPACE}" -p '{"metadata":{"name":"identity-service"},"spec":{"selector":{"matchLabels":{"app":"identity-service"}}},"template":{"metadata":{"labels":{"app":"identity-service"}}}}'
|
|
kubectl patch service identity-service -n "${NAMESPACE}" -p '{"spec":{"selector":{"app":"identity-service"}}}'
|
|
|
|
log_success "Production deployment complete!"
|
|
log_info "Deployment details:"
|
|
kubectl get deployment identity-service -n "${NAMESPACE}"
|
|
kubectl get pods -n "${NAMESPACE}" -l app=identity-service
|
|
|
|
log_info "Next steps:"
|
|
echo "1. Monitor metrics: kubectl logs -n ${NAMESPACE} deployment/identity-service -f | grep entra"
|
|
echo "2. Verify webhook URL: https://api.theorder.org/vc/entra/webhook"
|
|
echo "3. Test credential issuance"
|
|
echo "4. Monitor for 24 hours"
|
|
|