This is a runbook for migrating a set of microservices in the form of a UI and many APIs from one region to another
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 "----------------------------------------"
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 "---------------------------------------------"
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