06 · Multi-Region & Disaster Recovery¶
Level 2's multi-zone VPC survives a zone outage. It does not survive a
regional outage — a rare but real event (network backbone failure, natural
disaster, regional control-plane incident). This module designs for that:
active-passive failover across us-south and us-east.
Decide the DR posture first¶
| Posture | RTO | RPO | Cost |
|---|---|---|---|
| Backup & restore | Hours | Hours (last backup) | Lowest |
| Pilot light | 10s of minutes | Minutes | Low-medium |
| Warm standby | Minutes | Seconds-minutes | Medium-high |
| Active-active | Near zero | Near zero | Highest |
This module builds a warm standby: infrastructure exists in both
regions, but us-east runs at reduced capacity until a failover promotes
it.
Mirror the VPC topology to a second region¶
Reuse the Level 2 Terraform module, parameterized by region, rather than hand-building a second copy that drifts from the first:
module "vpc_primary" {
source = "./modules/ha-vpc"
region = "us-south"
address_prefix = "10.10.0.0/16"
worker_count = 3
}
module "vpc_dr" {
source = "./modules/ha-vpc"
region = "us-east"
address_prefix = "10.20.0.0/16"
worker_count = 1 # warm standby: scaled down, not zero
}
Non-overlapping CIDRs (10.10.0.0/16 vs 10.20.0.0/16) matter here for
the same reason as Module 2's Transit Gateway note — if the two regions
are ever connected (for replication traffic or a global Transit Gateway),
overlap breaks routing.
Database replication: Databases for PostgreSQL cross-region read replica¶
ibmcloud cdb deployment-create orders-db-dr \
--datacenter us-east \
--plan standard \
--version 15 \
--replica-of $(ibmcloud cdb deployment orders-db --output json | jq -r .id)
A read replica is a live standby, not a promoted primary — promoting it during a real failover is a separate, deliberate action:
Promoting orders-db-dr to a standalone deployment...
Warning: this action is irreversible and breaks replication with the source.
Practice the promotion path in a drill well before a real incident — "we've never actually run this command" is the most common reason DR plans fail under pressure.
Cross-Region Cloud Object Storage for anything stateless-durable¶
ibmcloud cos bucket-create --bucket orders-archive-cr \
--ibm-service-instance-id <cos-guid> \
--region us-geo \
--class standard
us-geo (cross-region) buckets replicate objects across us-south,
us-east, and us-central automatically — the simplest DR story in this
module, because IBM operates the replication, not you.
DNS-based failover with Global Load Balancer (GLB)¶
ibmcloud cis glb-create \
--instance cis-mastery \
--name app.example.com \
--fallback-pool pool-us-south \
--default-pools pool-us-south \
--health-check-region us-south \
--proxy true
ibmcloud cis glb-pool-create \
--instance cis-mastery \
--name pool-us-east \
--origins '[{"name":"us-east-lb","address":"198.51.100.20","enabled":true}]' \
--check-regions WNAM \
--minimum-origins 1
Attach pool-us-east as the GLB's failover pool so a health check failure
against us-south automatically shifts DNS answers to us-east without
a manual DNS change during an incident — the difference between a runbook
step and an automated response.
Terraform for the GLB failover pool¶
resource "ibm_cis_origin_pool" "us_east_pool" {
cis_id = data.ibm_cis.cis_instance.id
name = "pool-us-east"
origins {
name = "us-east-lb"
address = ibm_is_lb.dr_lb.hostname
enabled = true
}
check_regions = ["WNAM"]
}
resource "ibm_cis_global_load_balancer" "app_glb" {
cis_id = data.ibm_cis.cis_instance.id
domain_id = data.ibm_cis_domain.example.domain_id
name = "app.example.com"
fallback_pool_id = ibm_cis_origin_pool.us_east_pool.id
default_pool_ids = [ibm_cis_origin_pool.us_south_pool.id]
proxied = true
}
Run a failover drill¶
- Simulate the primary being down: disable the
us-southhealth check origin, or scale its worker pool to 0. - Confirm GLB shifts traffic (
dig app.example.comshould resolve to theus-eastload balancer's address within the health-check interval). - Promote the read replica.
- Point application config/secrets at the promoted database.
- Time the whole exercise — that measured duration is your real RTO, not the number in the DR document.
Gotchas¶
- Read replica promotion is one-way — there is no "un-promote"; a failback to the original region needs a fresh replica built in the reverse direction, which takes as long as the original replica did.
- Cross-region COS costs more per GB than regional storage and has
slightly different consistency characteristics (eventual consistency
across the replicated regions) — don't default every bucket to
us-geowithout a reason. - GLB health checks have their own latency — a check interval of 60s plus a few failed-check threshold means real failover detection takes minutes, not seconds; factor that into RTO expectations.
- DR infrastructure that's never exercised typically doesn't work when actually needed — treat the failover drill as a recurring calendar event, not a one-time setup task.
How It Actually Works¶
- A cross-region read replica streams WAL over the public/backbone
network across regions the same way an in-region replica does within
Level 2's module — the only real difference is the distance the bytes
travel. That extra round-trip latency is exactly why cross-region
replication lag runs seconds rather than the sub-second lag of an
in-region replica, and why RPO for a warm-standby posture is quoted in
seconds-to-minutes instead of near-zero: any writes still in flight when
the primary region goes dark haven't reached
us-eastyet and are genuinely lost on promotion. - Promotion is irreversible because it's a control-plane action that severs the replication stream and reconfigures the standby's own internal cluster metadata to declare itself a primary — there's no "reconnect as replica" path back to the old primary because the promoted deployment has already diverged (accepted new writes the old primary never saw) the instant it starts serving. Rebuilding replication in the reverse direction is mechanically the same as building the original replica: a fresh base backup plus WAL streaming from whichever side is now authoritative.
- A GLB failover is a DNS-answer change, not a network reroute — CIS's health checker polls each pool's origin from checker nodes in the configured region on a fixed interval, and when the primary pool's origins fail enough consecutive checks to cross the unhealthy threshold, the GLB simply starts answering DNS queries for that hostname with the failover pool's address instead. Clients that already resolved and cached the old answer (respecting the record's TTL) keep hitting the dead primary until their cache expires, which is the real, unavoidable floor under any DNS-based failover's RTO — no configuration removes that TTL-bound tail.
us-geoCross-Region buckets replicate by asynchronously copying object writes to COS clusters in the other constituent regions after the initial write acknowledges — aPUTreturns success once it's durably erasure-coded in the region that received it, and propagation to the other regions happens afterward. That's the source of the "eventual consistency across regions" caveat: a read immediately afterward against a different region's endpoint can briefly miss the object even though the write already succeeded.
Cheat sheet¶
| Task | Command |
|---|---|
| Create cross-region replica | ibmcloud cdb deployment-create <name> --datacenter <region> --replica-of <id> |
| Promote replica | ibmcloud cdb deployment-promote-read-replica <name> |
| Create cross-region bucket | ibmcloud cos bucket-create --bucket <n> --region us-geo |
| Create GLB | ibmcloud cis glb-create --instance <cis> --name <fqdn> --default-pools <pool> |
| Create origin pool | ibmcloud cis glb-pool-create --instance <cis> --name <pool> --origins '[...]' |
Exercise¶
- Design (Terraform, parameterized module) a warm-standby VPC pair across two regions with non-overlapping CIDRs.
- Create a cross-region database read replica and describe what changes (and what doesn't) when you promote it.
- Configure a Global Load Balancer with a primary and failover pool.
- Run a timed failover drill against your own setup and record the measured RTO versus your target.