5 min read
Multi-Cloud Management with Azure
Multi-cloud strategies allow organizations to leverage the best services from different cloud providers. Azure provides tools to manage resources across Azure, AWS, GCP, and on-premises environments from a single pane of glass.
Azure Arc for Multi-Cloud
Connecting AWS Resources
# Connect AWS EKS cluster to Azure Arc
# First, configure AWS credentials
aws configure
# Get EKS cluster credentials
aws eks update-kubeconfig --name my-eks-cluster --region us-east-1
# Connect to Azure Arc
az connectedk8s connect \
--resource-group "MultiCloudK8s" \
--name "aws-eks-cluster" \
--location "eastus" \
--distribution eks
# Verify connection
az connectedk8s show \
--resource-group "MultiCloudK8s" \
--name "aws-eks-cluster"
Connecting GCP Resources
# Connect GKE cluster to Azure Arc
# Configure GCP credentials
gcloud auth login
gcloud config set project my-gcp-project
# Get GKE cluster credentials
gcloud container clusters get-credentials my-gke-cluster --zone us-central1-a
# Connect to Azure Arc
az connectedk8s connect \
--resource-group "MultiCloudK8s" \
--name "gcp-gke-cluster" \
--location "eastus" \
--distribution gke
# List all connected clusters
az connectedk8s list --output table
Multi-Cloud Monitoring
using Azure.Monitor.Query;
using Azure.Identity;
public class MultiCloudMonitoringService
{
private readonly LogsQueryClient _logsClient;
public MultiCloudMonitoringService()
{
_logsClient = new LogsQueryClient(new DefaultAzureCredential());
}
public async Task<MultiCloudStatus> GetClusterStatusAsync(string workspaceId)
{
var query = @"
KubeNodeInventory
| summarize
NodeCount = dcount(Computer),
ReadyNodes = dcountif(Computer, Status == 'Ready'),
LastHeartbeat = max(TimeGenerated)
by ClusterName
| extend
CloudProvider = case(
ClusterName contains 'eks', 'AWS',
ClusterName contains 'gke', 'GCP',
ClusterName contains 'aks', 'Azure',
'Unknown'
)
| project ClusterName, CloudProvider, NodeCount, ReadyNodes, LastHeartbeat";
var response = await _logsClient.QueryWorkspaceAsync(
workspaceId,
query,
new QueryTimeRange(TimeSpan.FromHours(1)));
var status = new MultiCloudStatus();
foreach (var row in response.Value.Table.Rows)
{
status.Clusters.Add(new ClusterStatus
{
ClusterName = row["ClusterName"].ToString(),
CloudProvider = row["CloudProvider"].ToString(),
NodeCount = Convert.ToInt32(row["NodeCount"]),
ReadyNodes = Convert.ToInt32(row["ReadyNodes"]),
LastHeartbeat = (DateTime)row["LastHeartbeat"]
});
}
return status;
}
public async Task<List<CostByCloud>> GetMultiCloudCostsAsync()
{
// Aggregate costs from multiple sources
var costs = new List<CostByCloud>();
// Azure costs from Cost Management API
var azureCosts = await GetAzureCostsAsync();
costs.Add(new CostByCloud { Provider = "Azure", Cost = azureCosts });
// AWS costs (would need AWS Cost Explorer API)
// GCP costs (would need GCP Billing API)
return costs;
}
}
public class MultiCloudStatus
{
public List<ClusterStatus> Clusters { get; set; } = new();
}
public class ClusterStatus
{
public string ClusterName { get; set; }
public string CloudProvider { get; set; }
public int NodeCount { get; set; }
public int ReadyNodes { get; set; }
public DateTime LastHeartbeat { get; set; }
}
Unified Policy Management
// Azure Policy for multi-cloud governance
{
"mode": "All",
"policyRule": {
"if": {
"allOf": [
{
"field": "type",
"equals": "Microsoft.Kubernetes/connectedClusters"
},
{
"field": "Microsoft.Kubernetes/connectedClusters/distribution",
"in": ["eks", "gke", "aks"]
},
{
"field": "tags['CostCenter']",
"exists": false
}
]
},
"then": {
"effect": "deny"
}
},
"parameters": {}
}
GitOps Across Clouds
# Flux configuration for multi-cloud GitOps
apiVersion: source.toolkit.fluxcd.io/v1beta2
kind: GitRepository
metadata:
name: multi-cloud-configs
namespace: flux-system
spec:
interval: 5m
url: https://github.com/org/multi-cloud-k8s
ref:
branch: main
---
# Azure AKS configuration
apiVersion: kustomize.toolkit.fluxcd.io/v1beta2
kind: Kustomization
metadata:
name: azure-aks-apps
namespace: flux-system
spec:
interval: 10m
path: ./clusters/azure-aks
sourceRef:
kind: GitRepository
name: multi-cloud-configs
prune: true
---
# AWS EKS configuration
apiVersion: kustomize.toolkit.fluxcd.io/v1beta2
kind: Kustomization
metadata:
name: aws-eks-apps
namespace: flux-system
spec:
interval: 10m
path: ./clusters/aws-eks
sourceRef:
kind: GitRepository
name: multi-cloud-configs
prune: true
---
# GCP GKE configuration
apiVersion: kustomize.toolkit.fluxcd.io/v1beta2
kind: Kustomization
metadata:
name: gcp-gke-apps
namespace: flux-system
spec:
interval: 10m
path: ./clusters/gcp-gke
sourceRef:
kind: GitRepository
name: multi-cloud-configs
prune: true
Terraform Multi-Cloud
# main.tf - Multi-cloud infrastructure
terraform {
required_providers {
azurerm = {
source = "hashicorp/azurerm"
version = "~> 3.0"
}
aws = {
source = "hashicorp/aws"
version = "~> 4.0"
}
google = {
source = "hashicorp/google"
version = "~> 4.0"
}
}
}
# Azure AKS
resource "azurerm_kubernetes_cluster" "aks" {
name = "multi-cloud-aks"
location = "eastus"
resource_group_name = azurerm_resource_group.main.name
dns_prefix = "multicloud"
default_node_pool {
name = "default"
node_count = 3
vm_size = "Standard_D2_v2"
}
identity {
type = "SystemAssigned"
}
tags = {
Environment = "Production"
ManagedBy = "Terraform"
}
}
# AWS EKS
resource "aws_eks_cluster" "eks" {
name = "multi-cloud-eks"
role_arn = aws_iam_role.eks.arn
vpc_config {
subnet_ids = aws_subnet.eks[*].id
}
tags = {
Environment = "Production"
ManagedBy = "Terraform"
}
}
# GCP GKE
resource "google_container_cluster" "gke" {
name = "multi-cloud-gke"
location = "us-central1"
remove_default_node_pool = true
initial_node_count = 1
labels = {
environment = "production"
managed-by = "terraform"
}
}
# Connect all to Azure Arc
resource "azurerm_arc_kubernetes_cluster" "eks" {
name = "aws-eks-cluster"
resource_group_name = azurerm_resource_group.arc.name
location = "eastus"
agent_public_key_certificate = file("eks-agent-cert.pem")
identity {
type = "SystemAssigned"
}
depends_on = [aws_eks_cluster.eks]
}
Cost Optimization
# Multi-cloud cost analysis
class MultiCloudCostAnalyzer:
def __init__(self, azure_client, aws_client, gcp_client):
self.azure = azure_client
self.aws = aws_client
self.gcp = gcp_client
def get_total_costs(self, start_date, end_date):
costs = {
'azure': self.get_azure_costs(start_date, end_date),
'aws': self.get_aws_costs(start_date, end_date),
'gcp': self.get_gcp_costs(start_date, end_date)
}
total = sum(costs.values())
percentages = {k: (v/total)*100 for k, v in costs.items()}
return {
'costs': costs,
'total': total,
'percentages': percentages
}
def get_optimization_recommendations(self):
recommendations = []
# Check for idle resources across clouds
# Check for right-sizing opportunities
# Check for reserved instance opportunities
return recommendations
Best Practices
- Standardize on Kubernetes - Use K8s as the common platform
- Centralize monitoring - Azure Monitor for all clouds
- Unified policy - Azure Policy across Arc-enabled resources
- GitOps everywhere - Consistent deployment model
- Cost visibility - Aggregate costs for full picture
Multi-cloud management with Azure provides the flexibility to use best-of-breed services while maintaining operational consistency.