zkt26/sk1/prepare-app.sh
2026-05-12 19:27:18 +02:00

228 lines
7.8 KiB
Bash
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/bin/bash
set -euo pipefail
# ==========================================
# LOGGER — source the shared library
# ==========================================
# shellcheck source=lib/logger.sh
source "$(dirname "$0")/lib/logger.sh" "deploy"
trap 'log_error "Failure at line $LINENO. See $LOG_FILE"' ERR
# ==========================================
# VARIABLES
# ==========================================
RESOURCE_GROUP="ExamApp-RG"
LOCATION="polandcentral"
ACR_NAME="examappregistrycharles"
AKS_NAME="ExamApp-AKS"
DB_NAME="postgres"
NODE_COUNT=2
NODE_VM_SIZE="Standard_B2als_v2"
# Fixed DNS label: avoids recreating a new label on every run
# (which would break the existing TLS certificate)
DNS_LABEL="vigimeteo-prod"
# DB credentials — required, never stored in Git
if [ -z "${DB_USER:-}" ] || [ -z "${DB_PASSWORD:-}" ]; then
log_error "DB_USER and DB_PASSWORD must be exported before running this script."
log_error " export DB_USER=\"postgres\""
log_error " export DB_PASSWORD=\"your_password\""
exit 1
fi
log_info "========================================"
log_info " Vigimeteo Deployment started"
log_info " Full log: $LOG_FILE"
log_info "========================================"
# ==========================================
log_info "STEP 1 — Cloud infrastructure"
# ==========================================
log_debug "Creating / verifying Resource Group '$RESOURCE_GROUP'..."
az group create --name "$RESOURCE_GROUP" --location "$LOCATION" --output none
log_info "Resource Group '$RESOURCE_GROUP' ready."
# ACR
if az acr show --name "$ACR_NAME" --resource-group "$RESOURCE_GROUP" --output none 2>/dev/null; then
log_info "ACR '$ACR_NAME' already exists."
else
log_info "Creating ACR '$ACR_NAME'..."
if ! az acr create \
--resource-group "$RESOURCE_GROUP" \
--name "$ACR_NAME" --sku Basic \
--location "$LOCATION" --output none; then
ACR_NAME="examapp$(date +%s | tail -c 8)"
log_warn "Name unavailable — using fallback name: $ACR_NAME"
az acr create \
--resource-group "$RESOURCE_GROUP" \
--name "$ACR_NAME" --sku Basic \
--location "$LOCATION" --output none
fi
log_info "ACR '$ACR_NAME' created."
fi
ACR_LOGIN_SERVER=$(az acr show \
--name "$ACR_NAME" --resource-group "$RESOURCE_GROUP" \
--query loginServer --output tsv)
log_debug "ACR login server: $ACR_LOGIN_SERVER"
# AKS
if az aks show \
--resource-group "$RESOURCE_GROUP" --name "$AKS_NAME" \
--output none 2>/dev/null; then
log_info "Cluster '$AKS_NAME' already exists."
else
log_info "Creating AKS cluster '$AKS_NAME' (35 min)..."
az aks create \
--resource-group "$RESOURCE_GROUP" \
--name "$AKS_NAME" \
--node-count "$NODE_COUNT" \
--node-vm-size "$NODE_VM_SIZE" \
--location "$LOCATION" \
--generate-ssh-keys \
--attach-acr "$ACR_NAME" \
--output none
log_info "Cluster '$AKS_NAME' created with $NODE_COUNT nodes ($NODE_VM_SIZE)."
fi
az aks get-credentials \
--resource-group "$RESOURCE_GROUP" --name "$AKS_NAME" \
--overwrite-existing
log_info "kubectl configured."
# ==========================================
log_info "STEP 2 — Build and push Docker images"
# ==========================================
az acr login --name "$ACR_NAME" --resource-group "$RESOURCE_GROUP"
for service in backend frontend; do
dir=""
[ "$service" = "backend" ] && dir="./Back-end/"
[ "$service" = "frontend" ] && dir="./Front-end/"
image="$ACR_LOGIN_SERVER/vigimeteo-$service:latest"
log_info "Building $service$image"
docker build -t "$image" "$dir"
log_info "Pushing $service..."
docker push "$image"
log_info "$service pushed successfully."
done
# ==========================================
log_info "STEP 3 — Kubernetes deployment"
# ==========================================
kubectl apply -f namespace.yaml
log_debug "Namespace applied."
kubectl create secret generic db-credentials \
--namespace vigimeteo \
--from-literal=host="vigimeteo-db.vigimeteo.svc.cluster.local" \
--from-literal=port="5432" \
--from-literal=dbname="$DB_NAME" \
--from-literal=username="$DB_USER" \
--from-literal=password="$DB_PASSWORD" \
--dry-run=client -o yaml | kubectl apply -f -
log_info "Secret 'db-credentials' applied."
kubectl create configmap vigimeteo-db-init \
--namespace vigimeteo \
--from-file=init_db.sql=./sql/init_db.sql \
--dry-run=client -o yaml | kubectl apply -f -
log_info "ConfigMap 'vigimeteo-db-init' applied."
kubectl apply -f statefulset.yaml
kubectl apply -f service.yaml
sed "s|MON_REGISTRE|$ACR_LOGIN_SERVER|g" deployment.yaml | kubectl apply -f -
log_info "StatefulSet, Services and Deployment applied."
# ==========================================
log_info "STEP 4 — HTTPS exposure (ingress + TLS)"
# ==========================================
log_info "Applying ingress-nginx..."
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.8.2/deploy/static/provider/cloud/deploy.yaml
# Wait for the ingress-nginx controller pod to be Ready before applying ingress.yaml.
# Without this wait the admission webhook has no endpoints yet and kubectl returns
# an InternalError when validating the Ingress resource.
log_info "Waiting for ingress-nginx controller to be Ready (up to 90s)..."
kubectl wait --namespace ingress-nginx \
--for=condition=ready pod \
--selector=app.kubernetes.io/component=controller \
--timeout=90s
log_info "ingress-nginx controller is Ready."
log_info "Applying cert-manager..."
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.13.1/cert-manager.yaml
log_info "Waiting for Azure public IP (up to 4 min)..."
PUBLIC_IP=""
ATTEMPTS=0
MAX_ATTEMPTS=24 # 24 × 10s = 4 min
while [ -z "$PUBLIC_IP" ] && [ "$ATTEMPTS" -lt "$MAX_ATTEMPTS" ]; do
sleep 10
ATTEMPTS=$((ATTEMPTS + 1))
PUBLIC_IP=$(kubectl get svc ingress-nginx-controller \
-n ingress-nginx \
-o jsonpath='{.status.loadBalancer.ingress[0].ip}' 2>/dev/null || true)
log_debug "Attempt $ATTEMPTS/$MAX_ATTEMPTS — IP: ${PUBLIC_IP:-pending}"
done
if [ -z "$PUBLIC_IP" ]; then
log_error "Public IP not obtained after 4 minutes."
log_error "Diagnose with: kubectl get svc -n ingress-nginx"
exit 1
fi
log_info "Public IP obtained: $PUBLIC_IP"
NODE_RG=$(az aks show \
--resource-group "$RESOURCE_GROUP" --name "$AKS_NAME" \
--query nodeResourceGroup -o tsv)
PUBLIC_IP_NAME=$(az network public-ip list \
--resource-group "$NODE_RG" \
--query "[?ipAddress!=null]|[?contains(ipAddress, '$PUBLIC_IP')].[name]" \
-o tsv)
# Fixed DNS label → idempotent, does not break an existing TLS certificate
az network public-ip update \
--resource-group "$NODE_RG" \
--name "$PUBLIC_IP_NAME" \
--dns-name "$DNS_LABEL" \
--output none
FQDN=$(az network public-ip show \
--resource-group "$NODE_RG" --name "$PUBLIC_IP_NAME" \
--query dnsSettings.fqdn -o tsv)
log_info "FQDN: $FQDN"
sed "s|MON_DOMAINE|$FQDN|g" ingress.yaml | kubectl apply -f -
kubectl apply -f cluster-issuer.yaml
# ==========================================
log_info "STEP 5 — Post-deployment health checks"
# ==========================================
log_info "Waiting for all vigimeteo pods to be Ready (up to 3 min)..."
if kubectl wait pod \
--all \
--namespace vigimeteo \
--for=condition=Ready \
--timeout=180s; then
log_info "All pods are Ready ✅"
else
log_warn "Some pods are not yet Ready — current state:"
kubectl get pods -n vigimeteo | tee -a "$LOG_FILE"
log_warn "Deployment was submitted — verify manually."
fi
log_debug "Detailed pod status:"
kubectl get pods -n vigimeteo -o wide 2>&1 | tee -a "$LOG_FILE"
log_info "========================================"
log_info "DEPLOYMENT COMPLETE"
log_info " URL : https://$FQDN"
log_info " DB : vigimeteo-db.vigimeteo.svc.cluster.local"
log_info " Log : $LOG_FILE"
log_info "========================================"