Most cloud architecture advice says: pick one cloud and go deep. We picked three. Here's why that was the right call for us — and the patterns that keep it manageable.
Why Multi-cloud
It wasn't an ideological choice. It started with a specific problem: our primary data vendor provides feeds via a GCP Pub/Sub topic. Our existing infrastructure was AWS. Our disaster recovery vendor offered significantly better pricing on Azure.
Rather than migrate everything to one cloud and lose the advantages of the others, we built an abstraction layer that treats cloud primitives as interchangeable where possible.
The Architecture
# Cloud responsibilities
AWS: Primary compute, RDS, S3 (primary data lake)
GCP: Data ingestion (Pub/Sub), BigQuery analytics
Azure: DR, cold storage, compliance backups
# Abstraction layer
class StorageClient:
def upload(self, key, data):
return self.backend.put(key, data)
# backend = S3Client | GCSClient | BlobClient
The Costs
Multi-cloud has real costs: increased IAM complexity, more networking cost, and engineers who need to know multiple cloud paradigms. We manage this by designating cloud owners — one engineer is the go-to for AWS, another for GCP.
The goal is not to be cloud-agnostic. The goal is to not be held hostage by a single vendor's pricing, reliability, or strategic direction.
Our 99.9% uptime over the past 18 months is partly attributable to this setup. When an AWS us-east-1 partial outage affected some services, our GCP-based data ingestion kept running without interruption.