OCM with KinD
A containerlab topology that deploys 3 KinD clusters — 1 hub + 2 spokes — for experimenting with
Open Cluster Manager using the clusteradm CLI.
Topology
graph TD
subgraph Docker_Host["Docker Host"]
subgraph KinD["KinD Clusters — kindest/node:v1.31.0"]
hub["🟢 hub (Control Plane)<br/>cluster-manager<br/>API :6443"]
spoke1["🔵 spoke1 (Worker)<br/>klusterlet<br/>API :6443"]
spoke2["🔵 spoke2 (Worker)<br/>klusterlet<br/>API :6443"]
end
hub---|"Docker bridge<br/>172.18.0.0/16"| spoke1
hub---|"Docker bridge<br/>172.18.0.0/16"| spoke2
end
classDef hub fill:#1b5e20,color:#fff,stroke:#2e7d32
classDef spoke fill:#0d47a1,color:#fff,stroke:#1565c0
class hub hub
class spoke1,spoke2 spoke
Containerlab generates a live SVG graph from this topology at clab-ocm-demo/graph/.
Prerequisites
| Tool | Minimum Version | Purpose |
|---|---|---|
| containerlab | 0.50+ | Deploys KinD nodes as Docker containers |
| Docker | 24+ | Container runtime for KinD |
| kubectl | 1.28+ | Kubernetes CLI |
| clusteradm | 1.3+ | OCM bootstrapping |
Quick Start
# From the ocm/ directory:
# Full automated pipeline:
make demo
# Or step by step:
make deploy # Spin up 3 KinD clusters + export kubeconfigs
make install-ocm # Initialize OCM hub via clusteradm init
make register-spokes # Register spokes via clusteradm join
make accept # Accept managed clusters via clusteradm accept
Make Targets
| Target | Description |
|---|---|
deploy |
Deploy the 3-cluster KinD topology + export kubeconfigs |
destroy |
Tear down the lab |
status |
Show containerlab node status |
kubeconfigs |
(Re-)export kubeconfigs to ./kubeconfigs/ |
install-ocm |
Initialize OCM hub via clusteradm init |
register-spokes |
Register spoke clusters via clusteradm join |
accept |
Approve pending spoke CSRs via clusteradm accept |
demo |
Full pipeline: deploy → OCM hub → register → accept |
clean |
Destroy + clean kubeconfigs |
Manual Inspection
# Point to the hub cluster
export KUBECONFIG=./kubeconfigs/hub
# List managed clusters
kubectl get managedclusters
# Deploy a workload to a spoke via ManifestWork
cat <<EOF | kubectl apply -f -
apiVersion: work.open-cluster-management.io/v1
kind: ManifestWork
metadata:
name: hello-ocm
namespace: spoke1
spec:
workload:
manifests:
- apiVersion: v1
kind: Namespace
metadata:
name: ocm-demo
- apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
namespace: ocm-demo
spec:
replicas: 1
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:alpine
EOF
# Verify on spoke
export KUBECONFIG=./kubeconfigs/spoke1
kubectl get pods -n ocm-demo
Lab Details
- Topology file:
topology.clab.yml - Kubeconfigs: Exported to
./kubeconfigs/{hub,spoke1,spoke2} - Node images:
kindest/node:v1.31.0 - Management network:
172.18.0.0/16(Docker bridge)