> ## Documentation Index
> Fetch the complete documentation index at: https://docs.akua.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Cross-Cluster Comparison

> Compare Kubernetes versions, images, and configurations across multiple clusters in one call

<Frame>
  <img className="block dark:hidden" src="https://mintcdn.com/akua-1dce587a/AEEz0U2s7Do2sYaM/images/heros/ai-cross-cluster-comparison-light.svg?fit=max&auto=format&n=AEEz0U2s7Do2sYaM&q=85&s=9ea85802dcd7d80967c09ff16924ecc8" alt="One parallel call across a fleet of clusters producing a comparison matrix that flags the cluster whose Kubernetes version, image, and CRD count have drifted" width="1536" height="864" data-path="images/heros/ai-cross-cluster-comparison-light.svg" />

  <img className="hidden dark:block" src="https://mintcdn.com/akua-1dce587a/AEEz0U2s7Do2sYaM/images/heros/ai-cross-cluster-comparison-dark.svg?fit=max&auto=format&n=AEEz0U2s7Do2sYaM&q=85&s=6e7079db77a46c77d776144ee950c314" alt="One parallel call across a fleet of clusters producing a comparison matrix that flags the cluster whose Kubernetes version, image, and CRD count have drifted" width="1536" height="864" data-path="images/heros/ai-cross-cluster-comparison-dark.svg" />
</Frame>

When managing multiple clusters, drift happens: different Kubernetes versions, mismatched images, inconsistent configurations. An agent can audit all clusters in parallel, comparing everything from node versions to installed CRDs.

## Version drift check

An agent asked "are my clusters running the same versions?" fans out across all clusters in a single `execute` call:

```js expandable theme={null}
async () => {
  // Get all clusters
  const clusters = await platform.request({
    method: "GET", path: "/v1/clusters"
  }).then(r => r.body.data);

  const kube = (clusterId, path) => platform.request({
    method: "GET",
    path: `/v1/clusters/${clusterId}/kube_proxy/${path}`,
  }).then(r => r.body).catch(() => null);

  // Parallel fetch across all clusters
  const results = await Promise.all(clusters.map(async (cluster) => {
    const [nodes, version] = await Promise.all([
      kube(cluster.id, "api/v1/nodes"),
      kube(cluster.id, "version"),
    ]);

    if (!nodes) return { cluster: cluster.name, status: "unreachable" };

    return {
      cluster: cluster.name,
      k8s_version: version?.gitVersion,
      nodes: nodes.items.map(n => ({
        name: n.metadata.name,
        kubelet: n.status.nodeInfo.kubeletVersion,
        os: n.status.nodeInfo.osImage,
        runtime: n.status.nodeInfo.containerRuntimeVersion,
        kernel: n.status.nodeInfo.kernelVersion,
      })),
    };
  }));

  // Find drift
  const versions = [...new Set(results.filter(r => r.k8s_version).map(r => r.k8s_version))];
  return {
    cluster_count: clusters.length,
    unique_k8s_versions: versions,
    drift_detected: versions.length > 1,
    clusters: results,
  };
}
```

## Image consistency

Compare which container images are running across clusters, catching cases where one cluster is on `v1.2.3` and another is still on `v1.1.0`:

```js expandable theme={null}
async () => {
  const clusters = await platform.request({
    method: "GET", path: "/v1/clusters"
  }).then(r => r.body.data);

  const kube = (clusterId, path) => platform.request({
    method: "GET",
    path: `/v1/clusters/${clusterId}/kube_proxy/${path}`,
  }).then(r => r.body).catch(() => null);

  const results = await Promise.all(clusters.map(async (cluster) => {
    const pods = await kube(cluster.id, "api/v1/pods");
    if (!pods) return { cluster: cluster.name, images: [] };

    // Deduplicate images
    const images = [...new Set(
      pods.items.flatMap(p =>
        p.spec.containers.map(c => c.image)
      )
    )].sort();

    return { cluster: cluster.name, images };
  }));

  // Find images that differ across clusters
  const allImages = new Map();
  for (const r of results) {
    for (const img of r.images) {
      const name = img.split(":")[0];
      if (!allImages.has(name)) allImages.set(name, new Map());
      allImages.get(name).set(r.cluster, img);
    }
  }

  const drift = [];
  for (const [name, clusterVersions] of allImages) {
    const tags = [...new Set(clusterVersions.values())];
    if (tags.length > 1) {
      drift.push({ image: name, versions: Object.fromEntries(clusterVersions) });
    }
  }

  return { drift_count: drift.length, image_drift: drift };
}
```

## CRD comparison

Check which Custom Resource Definitions are installed in each cluster, useful for ensuring all clusters have the same operators and extensions:

```js theme={null}
async () => {
  const clusters = await platform.request({
    method: "GET", path: "/v1/clusters"
  }).then(r => r.body.data);

  const kube = (clusterId, path) => platform.request({
    method: "GET",
    path: `/v1/clusters/${clusterId}/kube_proxy/${path}`,
  }).then(r => r.body).catch(() => null);

  const results = await Promise.all(clusters.map(async (cluster) => {
    const crds = await kube(cluster.id, "apis/apiextensions.k8s.io/v1/customresourcedefinitions");
    return {
      cluster: cluster.name,
      crds: crds?.items.map(c => c.metadata.name).sort() || [],
    };
  }));

  // Find CRDs unique to specific clusters
  const allCrds = new Set(results.flatMap(r => r.crds));
  const missing = [];
  for (const crd of allCrds) {
    const present = results.filter(r => r.crds.includes(crd)).map(r => r.cluster);
    if (present.length < results.length) {
      const absent = results.filter(r => !r.crds.includes(crd)).map(r => r.cluster);
      missing.push({ crd, present_in: present, missing_from: absent });
    }
  }

  return { total_unique_crds: allCrds.size, inconsistencies: missing };
}
```

## Why this matters

Multi-cluster management typically requires dedicated tools (fleet managers, policy engines, GitOps controllers). For ad-hoc checks and audits, Code Mode gives agents the same cross-cluster visibility without any additional infrastructure.

The agent uses the Akua API to list clusters, then fans out through each cluster's kube proxy in parallel. It composes the comparison logic (version matching, image diffing, CRD set intersection) inside the sandbox. One conversation, full fleet visibility.

## Related topics

<CardGroup cols={2}>
  <Card title="CRD discovery" icon="magnifying-glass-chart" href="/ai/examples/crd-discovery">
    Discover and interact with custom resources on a single cluster.
  </Card>

  <Card title="Security audit" icon="shield-halved" href="/ai/examples/security-audit">
    Audit pod security, RBAC, and network policies in one call.
  </Card>

  <Card title="Kubernetes access" icon="dharmachakra" href="/ai/kubernetes-access">
    The kube proxy endpoints agents use for cluster inspection.
  </Card>

  <Card title="Code Mode in action" icon="bolt" href="/ai/code-mode-in-action">
    How the parallel fan-out pattern works.
  </Card>
</CardGroup>
