e1a7c71a87
Dockerfile: downloads linux/amd64 soul binary from Artifact Registry (foundation-dev/neuron-soul) into ubuntu:22.04 runtime image. Pushes to neuron-api Docker repo as neuron-soul:<sha>. scripts/blue-green-deploy.sh: swaps active slot on GKE — sets image, scales new slot to 1, flips service selector, scales old slot to 0. scripts/seed-engram-gke.sh: downloads latest GCS backup, extracts snapshot.json, copies into neuron-engram-data PVC via a seed Job. .gitea/workflows/deploy-gke.yaml: triggers on push to main, auto-detects idle slot, builds Docker image from Artifact Registry binary, blue-green deploys to neuron-prod on GKE neuron-platform cluster.
122 lines
3.7 KiB
Bash
Executable File
122 lines
3.7 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# blue-green-deploy.sh — swap the active soul slot on GKE
|
|
#
|
|
# Usage:
|
|
# blue-green-deploy.sh --image <image-tag> --slot <blue|green>
|
|
#
|
|
# What it does:
|
|
# 1. Sets the new image on the target slot deployment
|
|
# 2. Scales the target slot to 1 replica and waits for it to become ready
|
|
# 3. Patches the neuron-mcp Service selector to point at the new slot
|
|
# 4. Scales the old slot down to 0 replicas
|
|
#
|
|
# This script uses kubectl imperatively for the live traffic swap.
|
|
# After a successful swap, Argo CD manifests should be updated to reflect
|
|
# the new active slot (so Argo CD doesn't revert the replica counts on next sync).
|
|
#
|
|
# Prerequisites:
|
|
# - kubectl configured with access to neuron-platform cluster
|
|
# - Sufficient RBAC: get/patch/scale Deployments and Services in neuron-prod
|
|
#
|
|
# Examples:
|
|
# blue-green-deploy.sh --image us-central1-docker.pkg.dev/neuron-785695/neuron-api/neuron-soul:abc12345 --slot green
|
|
# blue-green-deploy.sh --image us-central1-docker.pkg.dev/neuron-785695/neuron-api/neuron-soul:latest --slot blue
|
|
|
|
set -euo pipefail
|
|
|
|
NAMESPACE="neuron-prod"
|
|
APP="neuron-mcp"
|
|
SERVICE="neuron-mcp"
|
|
|
|
IMAGE=""
|
|
NEW_SLOT=""
|
|
|
|
usage() {
|
|
echo "Usage: $0 --image <image-tag> --slot <blue|green>"
|
|
echo ""
|
|
echo " --image Full image URI including tag"
|
|
echo " --slot Target slot to deploy to: blue or green"
|
|
exit 1
|
|
}
|
|
|
|
while [[ $# -gt 0 ]]; do
|
|
case $1 in
|
|
--image)
|
|
IMAGE="$2"; shift 2 ;;
|
|
--slot)
|
|
NEW_SLOT="$2"; shift 2 ;;
|
|
-h|--help)
|
|
usage ;;
|
|
*)
|
|
echo "Unknown argument: $1"
|
|
usage ;;
|
|
esac
|
|
done
|
|
|
|
[[ -z "$IMAGE" ]] && { echo "ERROR: --image is required"; usage; }
|
|
[[ -z "$NEW_SLOT" ]] && { echo "ERROR: --slot is required"; usage; }
|
|
[[ "$NEW_SLOT" != "blue" && "$NEW_SLOT" != "green" ]] && {
|
|
echo "ERROR: --slot must be 'blue' or 'green'"; exit 1
|
|
}
|
|
|
|
# Determine the old (currently active) slot
|
|
if [[ "$NEW_SLOT" == "blue" ]]; then
|
|
OLD_SLOT="green"
|
|
else
|
|
OLD_SLOT="blue"
|
|
fi
|
|
|
|
NEW_DEPLOYMENT="${APP}-${NEW_SLOT}"
|
|
OLD_DEPLOYMENT="${APP}-${OLD_SLOT}"
|
|
|
|
echo "==> Deploying to slot: ${NEW_SLOT}"
|
|
echo " Image: ${IMAGE}"
|
|
echo " New deploy: ${NEW_DEPLOYMENT}"
|
|
echo " Old deploy: ${OLD_DEPLOYMENT}"
|
|
echo " Namespace: ${NAMESPACE}"
|
|
echo ""
|
|
|
|
# Step 1: Update the image on the new slot
|
|
echo "[1/4] Setting image on ${NEW_DEPLOYMENT}..."
|
|
kubectl set image deployment/"${NEW_DEPLOYMENT}" \
|
|
soul="${IMAGE}" \
|
|
--namespace="${NAMESPACE}"
|
|
|
|
# Step 2: Scale the new slot up (it may already be at 0)
|
|
echo "[2/4] Scaling ${NEW_DEPLOYMENT} to 1 replica..."
|
|
kubectl scale deployment/"${NEW_DEPLOYMENT}" \
|
|
--replicas=1 \
|
|
--namespace="${NAMESPACE}"
|
|
|
|
# Wait for rollout to complete (pod ready)
|
|
echo " Waiting for rollout to complete (timeout: 5m)..."
|
|
kubectl rollout status deployment/"${NEW_DEPLOYMENT}" \
|
|
--namespace="${NAMESPACE}" \
|
|
--timeout=5m
|
|
|
|
echo " ${NEW_DEPLOYMENT} is ready."
|
|
|
|
# Step 3: Patch the service selector to point at the new slot
|
|
echo "[3/4] Flipping service selector to slot=${NEW_SLOT}..."
|
|
kubectl patch service "${SERVICE}" \
|
|
--namespace="${NAMESPACE}" \
|
|
--type=merge \
|
|
--patch="{\"spec\":{\"selector\":{\"app\":\"${APP}\",\"slot\":\"${NEW_SLOT}\"}}}"
|
|
|
|
echo " Traffic now routing to ${NEW_SLOT}."
|
|
|
|
# Step 4: Scale down the old slot
|
|
echo "[4/4] Scaling ${OLD_DEPLOYMENT} down to 0 replicas..."
|
|
kubectl scale deployment/"${OLD_DEPLOYMENT}" \
|
|
--replicas=0 \
|
|
--namespace="${NAMESPACE}"
|
|
|
|
echo ""
|
|
echo "==> Blue-green swap complete."
|
|
echo " Active slot: ${NEW_SLOT} (${IMAGE})"
|
|
echo " Idle slot: ${OLD_SLOT} (scaled to 0)"
|
|
echo ""
|
|
echo "NOTE: Update Argo CD manifests to reflect new state:"
|
|
echo " - deployment-${NEW_SLOT}.yaml: replicas: 1, image: ${IMAGE}"
|
|
echo " - deployment-${OLD_SLOT}.yaml: replicas: 0"
|