Skip to content
Back to Blog
1 min read

Multi-Cloud Management with Azure

I wrote “Multi-Cloud Management with Azure” to share practical, production-minded guidance on this topic.

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\n\n## Takeaways\n\n*Add a concise, personal takeaway and recommended next steps here.*\n
Michael John Peña

Michael John Peña

Senior Data Engineer based in Sydney. Writing about data, cloud, and technology.