From Laptop Hardware to a Local Kind Platform
Turn one laptop into a disposable Kubernetes analogue and prove both healthy scheduling and bounded recovery.
Run it in the public monorepo
This course is built around the public Zheta Kubernetes Lab monorepo. The excerpt below is runnable source, not pseudocode.
Source: compose.yaml
control-plane:
build: { context: ., dockerfile: services/Dockerfile, args: { SERVICE: control_plane } }
environment: { ENVIRONMENT: local, GENERATOR_URL: "http://generator:8080", RUNTIME_URL: "http://runtime:8080", EVIDENCE_URL: "http://evidence:8080", SERVICE_TOKEN: "local-service-token-32-characters-minimum", JWT_SECRET: "local-jwt-secret-32-characters-minimum", CONTROL_DATABASE_URL: "sqlite:////data/control.db", ARTIFACT_DATABASE_URL: "sqlite:////data/artifacts.db", BROKER_TOPIC: "http://broker:8080" }
volumes: ["control-data:/data"]
ports: ["8080:8080"]
depends_on: [generator, runtime, evidence, broker]
Code to reality
- Declared intent
- Run six explicit local responsibilities: web, control plane, generator, runtime, broker, and evidence.
- Interpreter
- Docker Compose resolves the service graph, builds images, creates networks and volumes, and starts containers.
- Software effect
- The control plane calls generator and runtime, then its outbox publishes to the broker for the independently progressing evidence subscriber.
- Hardware effect
- Six containers and four persistent volumes consume laptop CPU, memory, storage, and network namespaces.
- Observable evidence
- docker compose ps proves web, control-plane, generator, runtime, broker, and evidence processes; restart queries prove four durable volumes.
Start with the people and the result they need
The source tables below remain the detailed contract. Begin with these customer paths:
- D02-UC-01
- Person: Platform developer
- Job: Run the Zheta Forge control-plane shell locally before paying for cloud capacity
- Observable result: A pod is scheduled, becomes Ready, and answers a customer probe
- D02-UC-02
- Person: Platform reviewer
- Job: Distinguish a multi-node simulation from physical failure-domain isolation
- Observable result: Layer map identifies shared laptop CPU, RAM, disk, and network
Turn each customer job into a testable story
Now turn each customer job into a story with a result that an engineer can check:
- D02-US-01
- Story: As a platform developer, I want a disposable local cluster, so that I can observe scheduling and reconciliation before AWS
- Observable acceptance: Node, pod, event, replacement UID, and HTTP evidence share one run ID
- D02-US-02
- Story: As a platform reviewer, I want the simulation limits stated beside its AWS mapping, so that local success is not mistaken for production resilience
- Observable acceptance: Every local layer names its EKS counterpart and the shared laptop is recorded as one failure domain
Add real state and observable proof
Finally trace each story through the system that owns its state and the evidence that proves the outcome:
- D02-FLOW-01
- Trigger: Developer starts the local Zheta Forge environment
- Responsible systems: Docker, Kind, Kubernetes API, Deployment controller, kubelet, Zheta Forge shell
- Authoritative state: Kubernetes API desired/status state
- Owned record: LocalCluster
- Observable evidence: Docker container IDs, Node UIDs, Pod UID, readiness, HTTP body, local environment, timestamp, run ID
- Failure signal: Pending pod, readiness failure, event, or failed HTTP probe
- D02-FLOW-02
- Trigger: Developer deletes the labelled shell pod
- Responsible systems: Host OS and Docker runtime inspection
- Authoritative state: Host and Docker runtime inventory
- Owned record: LocalRecoveryRun
- Observable evidence: Deleted UID, ReplicaSet event, replacement UID, recovery duration, HTTP result, shared-substrate warning
- Failure signal: All nodes share one Docker host and physical resource pool
The enterprise problem and today’s slice
Enterprise problem: Teams copy cloud manifests into production without seeing which processes consume CPU, memory, disk, and network, so capacity and failure assumptions remain hidden until customers are affected.
Whole-course context: The incoming platform charter defines three planes and a create-to-retire lifecycle; today supplies a local hosted-runtime boundary for the first implementation slices.
Today’s slice: Create a multi-node Kind cluster, where Kind means Kubernetes nodes running as Docker containers, and map each local layer to its later EKS equivalent.
End-of-day evidence: Cluster, node, namespace, pod, failure, reconciliation, and HTTP probe observations are joined to one immutable lab run.
Still unsolved: Kind nodes share one physical laptop and therefore do not prove infrastructure high availability, cloud identity, managed storage, or production isolation.
Customer use cases
A local cluster is valuable only if it demonstrates the same control relationship as production. These use cases prove scheduling and recovery while refusing a false high-availability claim.
| Use case ID | Actor | Customer job | Success outcome | Denial or recovery evidence |
|---|---|---|---|---|
| D02-UC-01 | Platform developer | Run the Zheta Forge control-plane shell locally before paying for cloud capacity | A pod is scheduled, becomes Ready, and answers a customer probe | Deleted pod is replaced and the recovered endpoint answers again |
| D02-UC-02 | Platform reviewer | Distinguish a multi-node simulation from physical failure-domain isolation | Layer map identifies shared laptop CPU, RAM, disk, and network | HA claim is denied with the shared-substrate observation while the runtime remains usable |
Actor-centred user stories
Cluster status alone cannot establish the customer outcome. These stories require both Kubernetes evidence and an application response.
| Story ID | Use case IDs | User story | Observable acceptance conditions |
|---|---|---|---|
| D02-US-01 | D02-UC-01 | As a platform developer, I want a disposable local cluster, so that I can observe scheduling and reconciliation before AWS | Node, pod, event, replacement UID, and HTTP evidence share one run ID |
| D02-US-02 | D02-UC-02 | As a platform reviewer, I want the simulation limits stated beside its AWS mapping, so that local success is not mistaken for production resilience | Every local layer names its EKS counterpart and the shared laptop is recorded as one failure domain |
End-to-end product flows
The local customer action is opening the platform shell, not merely running kubectl. A recovery path deletes only one named disposable pod and watches the Deployment controller replace it.
| Flow ID | Use case IDs | Path | Trigger | Numbered steps | Terminal evidence |
|---|---|---|---|---|---|
| D02-FLOW-01 | D02-UC-01, D02-UC-02 | Happy | Developer starts the local Zheta Forge environment | 1. Docker supplies node containers.; 2. Kind creates the API and workers.; 3. Kubernetes schedules the shell pod.; 4. Readiness passes.; 5. HTTP probe returns the expected platform identity. | Docker container IDs, Node UIDs, Pod UID, readiness, HTTP body, local environment, timestamp, run ID |
| D02-FLOW-02 | D02-UC-01, D02-UC-02 | Recovery | Developer deletes the labelled shell pod | 1. Validate the namespace and label target.; 2. Delete one pod.; 3. Observe desired and actual replicas diverge.; 4. Watch replacement become Ready.; 5. Repeat HTTP probe. | Deleted UID, ReplicaSet event, replacement UID, recovery duration, HTTP result, shared-substrate warning |
The developer asks for a usable product endpoint. Kubernetes mechanics matter because they must eventually produce this observable action.
System design derived from the flows
Kind can teach orchestration while still misleading learners about hardware. The design therefore keeps the laptop, Docker node containers, Kubernetes controllers, and workload process visible.
| Use case ID | Entry point | Responsible services | Authoritative store | Failure evidence |
|---|---|---|---|---|
| D02-UC-01 | Local platform URL | Docker, Kind, Kubernetes API, Deployment controller, kubelet, Zheta Forge shell | Kubernetes API desired/status state | Pending pod, readiness failure, event, or failed HTTP probe |
| D02-UC-02 | Substrate review command | Host OS and Docker runtime inspection | Host and Docker runtime inventory | All nodes share one Docker host and physical resource pool |
The same laptop backs every simulated node. Docker runs node containers, Kubernetes reconciles the shell pod, and the process consumes the laptop's real resources.
Data model and ownership
Deleting a pod must not delete business data because today creates no business database. Kubernetes stores only disposable runtime state and lab evidence records what was observed.
Generated-application database: Not created in this slice — the shell is stateless and Kubernetes plus lab evidence are sufficient to prove scheduling and recovery.
| Record or entity | Store and owner | Primary key | Foreign key or opaque reference | Tenant key | Material constraint | Lifecycle and deletion | Use case IDs |
|---|---|---|---|---|---|---|---|
| LocalCluster | Kind configuration and Kubernetes API, owned by platform development | cluster name | Docker container and Node UIDs | environment=local | Cluster name and network are disposable and must not reuse cloud credentials | Created per lab; deleted after evidence capture | D02-UC-01, D02-UC-02 |
| LocalRecoveryRun | .lab/evidence, owned by the learner | run_id | Cluster, deleted Pod, and replacement Pod UIDs | environment=local | Exactly one validated target; before and after probes required | Immutable lab artifact; removable with the disposable lab | D02-UC-01, D02-UC-02 |
Kubernetes state explains why a replacement appeared; the probe proves that reconciliation restored a customer-visible outcome.
Run the local evidence loop
An unvalidated delete can target the wrong environment, so the lab creates its isolated kubeconfig through Terraform and uses the repository's validated failure script for mutation. Kind runs Kubernetes nodes as local container processes, so this proves orchestration behavior rather than independent-machine availability (Kind quick start). Read the exact cluster declaration in terraform/main.tf.
resource "kind_cluster" "zheta" {
name = var.cluster_name
wait_for_ready = true
kubeconfig_path = local.kubeconfig_path
kind_config {
kind = "Cluster"
api_version = "kind.x-k8s.io/v1alpha4"
node {
role = "control-plane"
}
dynamic "node" {
for_each = range(var.worker_count)
content {
role = "worker"
}
}
}
}
| Declared intent | Interpreter | Software effect | Hardware effect | Evidence |
|---|---|---|---|---|
| One Terraform-managed local Kind cluster and repository-local kubeconfig | Terraform and the tehcyx/kind provider call Kind, which calls the local container runtime | Records kind_cluster.zheta, starts node containers, and writes .kube/config; make product-deploy separately applies the local Forge overlay | Consumes one laptop's CPU, RAM, disk, power, and container networking; all simulated nodes share those failure domains | terraform state show kind_cluster.zheta, kubectl get nodes, kubectl -n zheta-forge get pods, and the product HTTP smoke run |
Decision rules
Use Kind to learn APIs, scheduling, and reconciliation cheaply. Do not use it to claim rack, availability-zone, IAM, load-balancer, or managed-control-plane resilience; those claims require later evidence from isolated AWS accounts and EKS clusters.