Skip to content
cloudemu
Services

Kubernetes

EKS, AKS, and GKE control planes plus a shared in-memory Kubernetes data plane that real client-go and kubectl drive end-to-end

aws EKSazr AKSgcp GKE

Emulates managed Kubernetes as two layers: the cloud control plane (EKS/AKS/GKE — the API you call to create clusters and node groups) and a shared data plane — an in-memory Kubernetes API server that kubectl and client-go talk to. Create a cluster with the real cloud SDK, and the kubeconfig it hands back points at the data plane, so kubectl apply round-trips against actual resources.

Reach for it in tests when your code provisions clusters, or when it drives Kubernetes objects directly — deployments, informers, watch streams — so you can exercise controller logic without a real cluster or a kind container. The data plane is a fast, deterministic test double: it stores and serves objects, but deliberately runs no controllers or scheduler.

ProviderServiceSDK-compatDriver
AWSEKS (control plane + data plane)✓ Liveaws.EKS
AzureAKS (control plane + data plane)✓ Liveazure.AKS
GCPGKE (control plane + data plane)✓ Livegcp.GKE

Create a cluster and drive its data plane#

The recommended path points the real SDK at the SDK-compat server. Pass a shared *kubernetes.APIServer as K8sAPI and call SetBaseURL so the kubeconfigs the control plane issues point back at this server — then DescribeCluster returns a kubeconfig you can hand straight to client-go:

import (
    "github.com/aws/aws-sdk-go-v2/service/eks"
    "github.com/stackshy/cloudemu/v2"
    "github.com/stackshy/cloudemu/v2/services/kubernetes"
    awsserver "github.com/stackshy/cloudemu/v2/server/aws"
)

cloud := cloudemu.NewAWS()
k8s := kubernetes.NewAPIServer()

ts := httptest.NewServer(awsserver.New(awsserver.Drivers{
    EKS:    cloud.EKS,
    K8sAPI: k8s, // shared in-memory Kubernetes data plane
}))
k8s.SetBaseURL(ts.URL) // so issued kubeconfigs point back at this server

client := eks.NewFromConfig(cfg, func(o *eks.Options) {
    o.BaseEndpoint = aws.String(ts.URL)
})

client.CreateCluster(ctx, &eks.CreateClusterInput{Name: aws.String("prod")})
// DescribeCluster now returns a kubeconfig whose server URL is the in-memory
// data plane — point client-go at it and `kubectl apply` works.

The AKS and GKE control planes are equivalent (armcontainerservice, container/apiv1) and share the same data plane. See the SDK-Compat Server.

Portable Go API#

Drive the control plane through the driver, or the data plane through the kubernetes package, without the HTTP hop. Creating a cluster registers it into the same *kubernetes.APIServer the SDK-compat path uses, so both layers see identical state:

import "github.com/stackshy/cloudemu/v2/services/kubernetes"

k8s := kubernetes.NewAPIServer()
// The control-plane mock registers a cluster into k8s on CreateCluster and
// deregisters it on DeleteCluster; the same in-memory state backs both layers.

Because the data plane is a single *kubernetes.APIServer, passing it into awsserver.Drivers{K8sAPI: …}, azureserver.Drivers{K8sAPI: …}, and gcpserver.Drivers{K8sAPI: …} lands every provider's kubeconfig on the identical backend — just as the real Kubernetes REST API is provider-agnostic.

Behavior & fidelity#

  • Two layers, one backend. The control plane covers cluster, node-group/node-pool, addon, Fargate-profile, and maintenance-config lifecycle; the data plane is an in-memory Kubernetes API server that the issued kubeconfigs point at. kubectl apply -f deployment.yaml then kubectl get pods round-trips, and real client-go Informer / Reflector machinery works against it.
  • Data-plane kinds. Namespace, Pod, Service, ConfigMap, Secret, ServiceAccount, and Deployment (all Create/Get/List/Update/Delete/Patch/Watch), plus Endpoints (read-only, auto-created per Service). API groups served: core/v1 and apps/v1. Each new cluster starts with default, kube-system, and kube-public namespaces and a default ServiceAccount in each.
  • Patch and Watch. Patch is JSON-merge-patch (RFC 7396, application/merge-patch+json); ?watch=true streams ADDED / MODIFIED / DELETED as newline-delimited JSON so informers work. Strategic-merge and JSON-Patch (RFC 6902) are not supported.
  • Intentionally out of scope. To stay a fast, deterministic double, the data plane runs no controllers (a Deployment does not create ReplicaSets/Pods — spec.replicas mirrors straight to status.replicas), no scheduler (Pods stay Pending, no Node binding or Pod IPs), and omits RBAC, PersistentVolumes/PVCs, Nodes, and StatefulSet/DaemonSet/Job/CronJob/Ingress.
  • SDK-compat status — Live. Real eks, armcontainerservice, and container/apiv1 clients drive the control plane. EKS covers cluster CRUD + UpdateConfig/UpdateVersion, managed node groups, Fargate profiles, and addons; AKS covers ManagedClusters (+ RotateClusterCertificates), agent pools, and maintenance configs; GKE covers clusters + config setters (logging, monitoring, master auth, network policy, maintenance, resource labels, IP rotation), node pools (+ SetSize/SetAutoscaling/SetManagement/Rollback), and operations.

On this page

On this page