Friday, April 10, 2026

 This is a runbook for migrating a set of microservices in the form of a UI and many APIs from one region to another  

  1. Step 1. Create all the containers in the destination. 

#!/usr/bin/env bash 

set -euo pipefail 

 

# ----------------------------- 

# CONFIGURATION 

# ----------------------------- 

SOURCE_RG="rg-microservices" 

DEST_SUFFIX="eus2" 

DEST_LOCATION="eastus2" 

 

DEST_RG="${SOURCE_RG}-${DEST_SUFFIX}" 

 

echo "Source RG: ${SOURCE_RG}" 

echo "Destination RG: ${DEST_RG}" 

echo "Destination Region: ${DEST_LOCATION}" 

echo "" 

 

# ----------------------------- 

# CREATE DESTINATION RG 

# ----------------------------- 

echo "Creating destination resource group..." 

az group create \ 

  --name "${DEST_RG}" \ 

  --location "${DEST_LOCATION}" \ 

  --output none 

 

echo "Destination RG created." 

echo "" 

 

# ----------------------------- 

# ENUMERATE RESOURCES 

# ----------------------------- 

echo "Enumerating resources in ${SOURCE_RG}..." 

RESOURCE_IDS=$(az resource list -g "${SOURCE_RG}" --query "[].id" -o tsv) 

 

if [[ -z "${RESOURCE_IDS}" ]]; then 

  echo "No resources found in ${SOURCE_RG}" 

  exit 1 

fi 

 

echo "Found resources:" 

echo "${RESOURCE_IDS}" 

echo "" 

 

# ----------------------------- 

# EXPORT EACH RESOURCE WITH aztfexport 

# ----------------------------- 

EXPORT_DIR="./export-${SOURCE_RG}-${DEST_SUFFIX}" 

mkdir -p "${EXPORT_DIR}" 

 

for RID in ${RESOURCE_IDS}; do 

  NAME=$(basename "${RID}") 

  NEW_NAME="${NAME}-${DEST_SUFFIX}" 

 

  echo "Exporting resource:" 

  echo "  Source ID: ${RID}" 

  echo "  New Name:  ${NEW_NAME}" 

  echo "" 

 

  aztfexport resource \ 

    --resource "${RID}" \ 

    --resource-group "${DEST_RG}" \ 

    --location "${DEST_LOCATION}" \ 

    --name-mapping "${NAME}=${NEW_NAME}" \ 

    --output-directory "${EXPORT_DIR}" \ 

    --append 

 

done 

 

echo "" 

echo "----------------------------------------" 

echo "Export completed. Terraform files stored in:" 

echo "  ${EXPORT_DIR}" 

echo "----------------------------------------" 

  1. Step 2. Copy all the configurations for each web service. 

#!/usr/bin/env bash 

set -euo pipefail 

 

SOURCE_RG="rg-microservices" 

DEST_SUFFIX="eus2" 

DEST_RG="${SOURCE_RG}-${DEST_SUFFIX}" 

 

echo "Source RG: ${SOURCE_RG}" 

echo "Destination RG: ${DEST_RG}" 

echo "" 

 

# --------------------------------------------- 

# ENUMERATE ALL WEB APPS IN SOURCE RG 

# --------------------------------------------- 

echo "Enumerating Web Apps in ${SOURCE_RG}..." 

APPS=$(az webapp list -g "${SOURCE_RG}" --query "[].name" -o tsv) 

 

if [[ -z "${APPS}" ]]; then 

  echo "No Web Apps found in ${SOURCE_RG}" 

  exit 1 

fi 

 

echo "Found Web Apps:" 

echo "${APPS}" 

echo "" 

 

# --------------------------------------------- 

# COPY CONFIG FOR EACH APP 

# --------------------------------------------- 

for APP in ${APPS}; do 

  DEST_APP="${APP}-${DEST_SUFFIX}" 

 

  echo "---------------------------------------------" 

  echo "Copying configuration:" 

  echo "  Source: ${APP}" 

  echo "  Dest:   ${DEST_APP}" 

  echo "---------------------------------------------" 

 

  # ----------------------------- 

  # GET SOURCE CONFIG 

  # ----------------------------- 

  CONFIG=$(az webapp config show -g "${SOURCE_RG}" -n "${APP}") 

  KIND=$(echo "${CONFIG}" | jq -r '.kind') 

  LINUX_FX=$(echo "${CONFIG}" | jq -r '.linuxFxVersion') 

  WINDOWS_FX=$(echo "${CONFIG}" | jq -r '.windowsFxVersion') 

  STARTUP_CMD=$(echo "${CONFIG}" | jq -r '.appCommandLine') 

 

  # ----------------------------- 

  # COPY RUNTIME STACK 

  # ----------------------------- 

  if [[ "${LINUX_FX}" != "null" && "${LINUX_FX}" != "" ]]; then 

    echo "Applying Linux runtime stack: ${LINUX_FX}" 

    az webapp config set \ 

      -g "${DEST_RG}" \ 

      -n "${DEST_APP}" \ 

      --linux-fx-version "${LINUX_FX}" \ 

      --startup-file "${STARTUP_CMD}" \ 

      --output none 

  fi 

 

  if [[ "${WINDOWS_FX}" != "null" && "${WINDOWS_FX}" != "" ]]; then 

    echo "Applying Windows runtime stack: ${WINDOWS_FX}" 

    az webapp config set \ 

      -g "${DEST_RG}" \ 

      -n "${DEST_APP}" \ 

      --windows-fx-version "${WINDOWS_FX}" \ 

      --output none 

  fi 

 

  # ----------------------------- 

  # COPY APP SETTINGS 

  # ----------------------------- 

  echo "Copying app settings..." 

  az webapp config appsettings list \ 

    -g "${SOURCE_RG}" \ 

    -n "${APP}" \ 

    | jq -r '.[] | "\(.name)=\(.value)"' \ 

    > /tmp/appsettings.txt 

 

  if [[ -s /tmp/appsettings.txt ]]; then 

    az webapp config appsettings set \ 

      -g "${DEST_RG}" \ 

      -n "${DEST_APP}" \ 

      --settings $(cat /tmp/appsettings.txt) \ 

      --output none 

  fi 

 

  # ----------------------------- 

  # COPY CONTAINER SETTINGS (IF ANY) 

  # ----------------------------- 

  if [[ "${LINUX_FX}" == *"DOCKER"* ]]; then 

    echo "Detected container-based app. Copying container settings..." 

 

    IMAGE=$(echo "${LINUX_FX}" | sed 's/DOCKER|//') 

    REGISTRY=$(az webapp config container show -g "${SOURCE_RG}" -n "${APP}") 

 

    SERVER=$(echo "${REGISTRY}" | jq -r '.dockerRegistryServerUrl') 

    USER=$(echo "${REGISTRY}" | jq -r '.dockerRegistryServerUserName') 

    PASS=$(echo "${REGISTRY}" | jq -r '.dockerRegistryServerPassword') 

 

    az webapp config container set \ 

      -g "${DEST_RG}" \ 

      -n "${DEST_APP}" \ 

      --docker-custom-image-name "${IMAGE}" \ 

      --docker-registry-server-url "${SERVER}" \ 

      --docker-registry-server-user "${USER}" \ 

      --docker-registry-server-password "${PASS}" \ 

      --output none 

  fi 

 

  echo "Completed configuration copy for ${APP} → ${DEST_APP}" 

  echo "" 

done 

 

echo "---------------------------------------------" 

echo "All Web App configurations copied successfully." 

echo "---------------------------------------------" 

  1. Step 3. Repoint the dns alias, certificates and deploy images 

#!/usr/bin/env bash 

set -euo pipefail 

 

SOURCE_RG="rg-microservices" 

DEST_SUFFIX="eus2" 

DEST_RG="${SOURCE_RG}-${DEST_SUFFIX}" 

 

# DNS zone (example: example.com) 

DNS_ZONE_RG="rg-dns" 

DNS_ZONE_NAME="example.com" 

 

echo "Source RG: ${SOURCE_RG}" 

echo "Destination RG: ${DEST_RG}" 

echo "DNS Zone: ${DNS_ZONE_NAME}" 

echo "" 

 

# --------------------------------------------- 

# ENUMERATE ALL WEB APPS IN SOURCE RG 

# --------------------------------------------- 

echo "Enumerating Web Apps in ${SOURCE_RG}..." 

APPS=$(az webapp list -g "${SOURCE_RG}" --query "[].name" -o tsv) 

 

if [[ -z "${APPS}" ]]; then 

  echo "No Web Apps found in ${SOURCE_RG}" 

  exit 1 

fi 

 

echo "Found Web Apps:" 

echo "${APPS}" 

echo "" 

 

# --------------------------------------------- 

# PROCESS EACH APP 

# --------------------------------------------- 

for APP in ${APPS}; do 

  DEST_APP="${APP}-${DEST_SUFFIX}" 

 

  echo "---------------------------------------------" 

  echo "Repointing DNS:" 

  echo "  Source App: ${APP}" 

  echo "  Dest App:   ${DEST_APP}" 

  echo "---------------------------------------------" 

 

  # Get default hostnames 

  SRC_HOST="${APP}.azurewebsites.net" 

  DEST_HOST="${DEST_APP}.azurewebsites.net" 

 

  # Get custom hostnames bound to the source app 

  HOSTNAMES=$(az webapp config hostname list \ 

    -g "${SOURCE_RG}" \ 

    -n "${APP}" \ 

    --query "[].name" -o tsv) 

 

  if [[ -z "${HOSTNAMES}" ]]; then 

    echo "No custom hostnames found for ${APP}" 

    continue 

  fi 

 

  echo "Custom hostnames:" 

  echo "${HOSTNAMES}" 

  echo "" 

 

  # --------------------------------------------- 

  # UPDATE DNS CNAME RECORDS 

  # --------------------------------------------- 

  for HOST in ${HOSTNAMES}; do 

    # Extract the relative record name (e.g., api.example.com → api) 

    RECORD_NAME=$(echo "${HOST}" | sed "s/.${DNS_ZONE_NAME}//") 

 

    echo "Updating DNS CNAME:" 

    echo "  Host:        ${HOST}" 

    echo "  Record name: ${RECORD_NAME}" 

    echo "  New target:  ${DEST_HOST}" 

 

    # Create or update the CNAME record 

    az network dns record-set cname set-record \ 

      --resource-group "${DNS_ZONE_RG}" \ 

      --zone-name "${DNS_ZONE_NAME}" \ 

      --record-set-name "${RECORD_NAME}" \ 

      --cname "${DEST_HOST}" \ 

      --output none 

 

    echo "DNS updated: ${HOST} → ${DEST_HOST}" 

    echo "" 

  done 

 

done 

 

echo "---------------------------------------------" 

echo "All DNS aliases repointed successfully." 

echo "---------------------------------------------" 

 

 

No comments:

Post a Comment