Skip to main content

Multi-Cloud Data Management


1 - Data Gravity

1.1 The concept

Data Gravity: Massive data attracts workloads. It is more cost-effective and performant to move compute to the data than the other way around.

FactorImpact
Egress costs$0.08-0.12/GB between clouds
Latency10-100ms cross-cloud
ComplianceGDPR requires localization
BandwidthLimited between clouds

1.2 Strategies

StrategyDescriptionUse Case
ColocationApps near the dataAnalytics
CachingLocal copy of dataRead-heavy
ReplicationBidirectional syncActive-Active
Event streamingAsynchronous syncReal-time

2 - Database replication

2.1 Cross-Cloud PostgreSQL

-- On the primary (AWS RDS)
-- Create a publication
CREATE PUBLICATION my_publication FOR ALL TABLES;

-- On the replica (Azure)
-- Create a subscription
CREATE SUBSCRIPTION my_subscription
CONNECTION 'host=rds-primary.aws.com dbname=mydb user=repl password=xxx'
PUBLICATION my_publication;

2.2 Terraform configuration

# AWS RDS Primary
resource "aws_db_instance" "primary" {
identifier = "primary-db"
engine = "postgres"
engine_version = "15"
instance_class = "db.r6g.large"
allocated_storage = 100

# Enable logical replication
parameter_group_name = aws_db_parameter_group.logical_replication.name

publicly_accessible = true # For cross-cloud (VPN recommended)
}

resource "aws_db_parameter_group" "logical_replication" {
family = "postgres15"
name = "logical-replication"

parameter {
name = "rds.logical_replication"
value = "1"
}
}

2.3 MySQL with Debezium

# Debezium CDC for MySQL
apiVersion: kafka.strimzi.io/v1beta2
kind: KafkaConnector
metadata:
name: mysql-source
spec:
class: io.debezium.connector.mysql.MySqlConnector
tasksMax: 1
config:
database.hostname: mysql.aws.example.com
database.port: 3306
database.user: debezium
database.password: ${MYSQL_PASSWORD}
database.server.id: 184054
database.server.name: aws-mysql
database.include.list: mydb
schema.history.internal.kafka.bootstrap.servers: kafka:9092
schema.history.internal.kafka.topic: schema-changes.mydb

3 - Cross-Cloud Object Storage

3.1 Architecture

3.2 Replication with rclone

# rclone configuration
# ~/.config/rclone/rclone.conf
[aws]
type = s3
provider = AWS
access_key_id = xxx
secret_access_key = xxx
region = eu-west-1

[azure]
type = azureblob
account = myaccount
key = xxx

[gcp]
type = google cloud storage
project_number = 123456789
service_account_file = /path/to/sa.json

# Bidirectional sync
rclone sync aws:my-bucket azure:my-container --progress

# Continuous sync
rclone sync aws:my-bucket gcp:my-bucket --checksum --progress

3.3 Multi-Cloud MinIO Gateway

# docker-compose.yml
version: '3'
services:
minio:
image: minio/minio
command: gateway s3 https://s3.amazonaws.com
environment:
MINIO_ROOT_USER: admin
MINIO_ROOT_PASSWORD: password
ports:
- "9000:9000"

4 - Event Streaming

4.1 Cross-Cloud Kafka

4.2 Kafka MirrorMaker 2

# mm2.properties
clusters = source, target

source.bootstrap.servers = msk.aws.example.com:9092
target.bootstrap.servers = kafka.azure.example.com:9092

source->target.enabled = true
source->target.topics = .*

replication.factor = 3
checkpoints.topic.replication.factor = 3
heartbeats.topic.replication.factor = 3

offset-syncs.topic.replication.factor = 3

sync.topic.acls.enabled = false

4.3 Confluent Cluster Linking

# Create a link between clusters
confluent kafka link create azure-link \
--cluster source-cluster-id \
--destination-cluster destination-cluster-id \
--destination-bootstrap-server kafka.azure.example.com:9092

# Create a mirror topic
confluent kafka mirror create my-topic \
--link azure-link \
--cluster destination-cluster-id

5 - Cross-Cloud Backup

5.1 3-2-1 strategy

3 copies - 2 storage types - 1 offsite (another cloud)

5.2 Velero for Kubernetes

# AWS Backup Location
velero backup-location create aws-backups \
--provider aws \
--bucket velero-backups-aws \
--config region=eu-west-1

# Azure Backup Location
velero backup-location create azure-backups \
--provider azure \
--bucket velero-backups-azure \
--config storageAccount=myaccount

# Backup to both
velero backup create daily-backup \
--storage-location aws-backups \
--snapshot-volumes

# Copy to Azure
velero backup copy daily-backup \
--destination-storage-location azure-backups

5.3 Database Backup Script

#!/bin/bash
# backup-db.sh

DATE=$(date +%Y%m%d)
DB_NAME="production"

# Dump PostgreSQL
pg_dump -h rds.aws.example.com -U admin $DB_NAME | gzip > /tmp/$DB_NAME-$DATE.sql.gz

# Upload to AWS
aws s3 cp /tmp/$DB_NAME-$DATE.sql.gz s3://backups-aws/db/

# Upload to Azure
az storage blob upload \
--account-name backups \
--container db \
--file /tmp/$DB_NAME-$DATE.sql.gz \
--name $DB_NAME-$DATE.sql.gz

# Upload to GCP
gsutil cp /tmp/$DB_NAME-$DATE.sql.gz gs://backups-gcp/db/

# Cleanup
rm /tmp/$DB_NAME-$DATE.sql.gz

6 - Data Compliance

6.1 GDPR and localization

RequirementSolution
Data in the EUEU regions only
PortabilityExport in standard formats
ErasureMulti-cloud procedures
Audit trailCentralized logs

6.2 Encryption at rest

# AWS S3
resource "aws_s3_bucket_server_side_encryption_configuration" "main" {
bucket = aws_s3_bucket.main.id

rule {
apply_server_side_encryption_by_default {
kms_master_key_id = aws_kms_key.main.arn
sse_algorithm = "aws:kms"
}
}
}

# Azure Blob
resource "azurerm_storage_account" "main" {
# ...

blob_properties {
versioning_enabled = true
}

identity {
type = "SystemAssigned"
}
}

# GCP Storage
resource "google_storage_bucket" "main" {
name = "my-bucket"
location = "EU"

encryption {
default_kms_key_name = google_kms_crypto_key.main.id
}
}

Summary

In this chapter, we learned:

  • The concept of Data Gravity
  • Database replication
  • Cross-cloud object storage
  • Multi-cloud event streaming
  • Backup strategies
  • Data compliance

Next step

In the next chapter, we will look at Multi-Cloud Monitoring.

→ Next chapter: Multi-Cloud Monitoring


← Back to table of contents