Free — no signup required

Abstraction Layers: The Universal Adapters

3 min read

To achieve portability across clouds, you need an abstraction layer — a common interface that hides the differences between underlying providers. Think of it like a universal power adapter: the device (your application) doesn't need to know whether the wall socket is US, European, or UK standard. The adapter handles the translation.

Kubernetes: The Compute Abstraction

Kubernetes (K8s) has become the de-facto standard for abstracting compute workloads across clouds.

Instead of deploying your application directly to AWS EC2 instances or Azure Virtual Machines, you package it in a Docker container and deploy it to a Kubernetes cluster. Kubernetes provides a standardized API for running containers, managing networking between them, scaling them up and down, and handling failures.

All three major cloud providers offer managed Kubernetes:
- AWS: Elastic Kubernetes Service (EKS)
- Azure: Azure Kubernetes Service (AKS)
- Google Cloud: Google Kubernetes Engine (GKE)

Your application's Kubernetes manifests (the YAML files that describe how to run your app) are largely portable across all three. Moving from EKS to AKS primarily involves reprovisioning the cluster and updating cloud-specific configurations like load balancer annotations and storage class names — not rewriting application code.

Terraform: The Provisioning Abstraction

Terraform (by HashiCorp) lets you define infrastructure using a single language — HashiCorp Configuration Language (HCL) — across any cloud provider. While the resource definitions are provider-specific (an aws_s3_bucket is different from an azurerm_storage_account), the workflow is identical: terraform plan, terraform apply, terraform destroy.

This means your team learns one tool, one state management system, and one CI/CD pipeline pattern for infrastructure provisioning — regardless of which cloud the resources live in.

# AWS S3 bucket
resource "aws_s3_bucket" "photos" {
  bucket = "my-app-photos-prod"
}

# Azure equivalent — same workflow, different resource type
resource "azurerm_storage_account" "photos" {
  name                     = "myappphotosprod"
  resource_group_name      = azurerm_resource_group.main.name
  location                 = "eastus"
  account_tier             = "Standard"
  account_replication_type = "LRS"
}

Both are provisioned with terraform apply. The workflow is the same; the underlying API calls are different.

SDK Abstraction Libraries

For application code that must interact with cloud storage, queues, or secrets, abstraction libraries provide a unified API across providers:

  • Apache Libcloud — Python library for compute and storage across multiple clouds
  • MinIO SDK — S3-compatible API that works against AWS S3, GCP Cloud Storage (via compatibility layer), and self-hosted MinIO
  • OpenTelemetry — Vendor-neutral observability SDK that exports metrics, logs, and traces to any backend (Datadog, Grafana, Cloud Monitoring)

The "Lowest Common Denominator" Problem

The fundamental downside of abstraction is that you can only use features that exist on all providers you support. If you build your storage layer against a generic S3-compatible API, you cannot use AWS S3 Intelligent-Tiering, S3 Object Lambda, or GCP's native lifecycle policies — because those features don't exist in the abstraction layer.

This is the "lowest common denominator" trap: your multi-cloud architecture ends up being less capable than what any single provider could offer. The engineering discipline is knowing which parts of your system can afford this trade-off (stateless compute, object storage) and which parts should deliberately accept lock-in to get the performance or features they need (analytics, ML pipelines).

This is one of 18 chapters

Every chapter is free — Kubernetes, Terraform, SRE, distributed systems, and more — with fast daily review built in.

Sign up free