kind
The kind binary — and, with a config blob, a running Kubernetes cluster with ingress and a load balancer.
kind runs Kubernetes in Docker. This recipe has two modes.
Without a config blob it installs the static kind binary and stops there:
devtools:
- name: docker
- name: kindWith a config blob it also stands the cluster up during provisioning — creating
a named cluster, installing an ingress controller, and installing a LoadBalancer
provider — so the workstation arrives at Configured with a working cluster you can kubectl
against immediately.
devtools:
- name: docker
- name: kind
config:
cluster: dev
ingress: nginx
loadBalancer: cloud-provider-kind
expose:
- { port: 80, hostPort: 8080 }Always declare docker before kind.
The recipe waits for the Docker daemon to answer before creating the cluster, and
installs kubectl itself if it is not already present.
version
Selects the kind binary release (for example v0.24.0). Omit it for the recipe’s
pinned default.
config fields
| Field | Type | Default | Description |
|---|---|---|---|
cluster | string | kind | The cluster name. |
ingress | string | nginx | nginx installs the ingress-nginx controller bound to the node’s ports 80/443. none skips it. |
loadBalancer | string | cloud-provider-kind | The provider for type: LoadBalancer services: cloud-provider-kind, metallb, or none. |
expose | array | — | {port, hostPort} pairs. Each maps a container port on the cluster node to a port on the VM, listening on all interfaces. |
expose and reaching the cluster from your laptop
expose is how traffic gets in. Each entry publishes a node port as a VM-wide
listener, which a LocalBinding with
autoForward then forwards to your machine. The reachable path is the mapped
ingress port, not a LoadBalancer IP: expose the ingress controller’s port 80 to a VM
port, forward that, and your ingress routes resolve on localhost.
Load balancer providers
cloud-provider-kind(default) watches the Docker API and provisions a proxy container pertype: LoadBalancerservice. It is installed as a managed service and needs no address-pool configuration.metallbinstalls MetalLB and derives an L2 address pool from the cluster’s Docker network subnet.noneinstalls neither.type: LoadBalancerservices stay pending — fine when you reach everything through the ingress.
Example
A workstation that builds an image, loads it into a local cluster, and serves it through the
ingress on your laptop’s localhost:8080:
apiVersion: workstations.ringleader.dev/v1
kind: WorkstationConfig
metadata:
name: kind-box
namespace: local
spec:
selector:
matchLabels:
app: kind-demo
identity:
user: dev
shell: /bin/bash
sudo: true
packages:
- git
- curl
devtools:
- name: docker
- name: kind
config:
cluster: demo
ingress: nginx
loadBalancer: none # ingress-only: no LoadBalancer provider needed
expose:
- { port: 80, hostPort: 8080 }
defaultLocalBinding:
enabled: true
autoForward:
forwardAll: true
---
apiVersion: workstations.ringleader.dev/v1
kind: Workstation
metadata:
name: kind-demo-box
namespace: local
labels:
app: kind-demo
spec:
# A live cluster plus an image build needs real headroom.
providerConfig:
memory: 8
cpus: 4Then curl http://127.0.0.1:8080 on your laptop reaches whatever your ingress routes.
When it counts as installed
For a configured cluster, “installed” means the binary exists and the named cluster
exists. If the cluster is destroyed out-of-band — a docker system prune, a wiped
Docker data root — the next setup run recreates it. Creating a cluster that already
exists is skipped; the ingress and load-balancer steps are safe to re-apply.
Notes
- The login user gets a kubeconfig pointing at the cluster, so
kubectlworks from an interactive shell withoutsudo. - The cluster’s ingress controller can take a few minutes to pull its image on a slow link. That wait is a logged note, not a failure.
- Sizing matters: a control-plane node image plus ingress plus your own workloads
needs several GiB of RAM.
providerConfiglives on the Workstation, not on a config layer.