Fixing Kind Cluster Creation Failure Due to cgroup v1 on Windows with Docker Desktop and WSL2
While setting up my Kubernetes learning environment using Kind, I encountered an issue where the cluster creation failed during the control plane initialization. This post documents the problem, the investigation process, and the final solution.
Environment
- Host OS: Windows 11
- WSL Version: 2.3.24.0
- Kernel Version: 5.15.153.1-2
- Docker Desktop: 4.80.0
- Docker Engine: 29.6.1
- Kind: v0.31.0
- Kind Node Image:
kindest/node:v1.35.0
Kind configuration:
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
- role: worker
- role: worker
The Problem
Running the following command:
kind create cluster --config kind-config.yaml
failed with the error:
[kubelet-check] Waiting for a healthy kubelet at http://127.0.0.1:10248/healthz. This can take up to 4m0s
[kubelet-check] The kubelet is not healthy after 4m0s
Unfortunately, an error has occurred, likely caused by:
- The kubelet is not running
- The kubelet is unhealthy due to a misconfiguration of the node in some way (required cgroups disabled)
error execution phase wait-control-plane: failed while waiting for the kubelet to start
At first glance, this error doesn't reveal the actual root cause.
Step 1: Keep the Failed Containers
By default, Kind removes failed containers, making debugging difficult.
I recreated the cluster using:
kind create cluster --retain --config kind-config.yaml
This preserved the containers after the failure.
Step 2: Inspect the Control Plane Container
I connected to the control plane node:
docker exec -it <control-plane-container> bash
Then checked the kubelet logs:
journalctl -u kubelet
This immediately showed the real error:
failed to validate kubelet configuration, kubelet is configured to not run on a host using cgroup v1. cgroup v1 support is unsupported and will be removed in a future release.
This was much more useful than the generic kubelet-check error.
Step 3: Verify Docker's cgroup Version
On the Windows host:
docker info
The relevant output was:
Cgroup Driver: cgroupfs Cgroup Version: 1
That was unexpected.
Modern Kubernetes versions no longer support cgroup v1.
Step 4: Verify the Container Runtime
To confirm the container itself was also using cgroup v1:
docker run --rm alpine sh -c "mount | grep cgroup"
Output:
cgroup on /sys/fs/cgroup/cpu type cgroup cgroup on /sys/fs/cgroup/memory type cgroup ...
Inside the Kind control plane:
stat -fc %T /sys/fs/cgroup
Output:
tmpfs
This confirmed that the environment was not using a unified cgroup v2 hierarchy.
Root Cause
The Docker engine was exposing cgroup v1.
Since the Kind node image (kindest/node:v1.35.0) contains a Kubernetes version that no longer supports cgroup v1, the kubelet exited immediately during startup.
As a result:
- kubelet never started
- the health endpoint on
127.0.0.1:10248never became available kubeadm initfailed- Kind reported only the generic "kubelet is not healthy" error
The Fix
I added the following configuration to my Windows .wslconfig file:
[wsl2]
kernelCommandLine="cgroup_no_v1=all systemd.unified_cgroup_hierarchy=1"
The file is located at:
C:\Users\<username>\.wslconfig
What those kernel parameters do
cgroup_no_v1=all- Disables all cgroup v1 controllers.
- Forces the system to use cgroup v2.
systemd.unified_cgroup_hierarchy=1- Enables the unified cgroup v2 hierarchy.
- This is what modern Kubernetes expects.
After saving the file:
- Restart WSL
wsl --shutdown
- Restart Docker Desktop.
Verify the Fix
Check the Docker cgroup version:
docker info --format '{{json .CgroupVersion}}'
Output:
"2"
Now create the cluster again:
kind create cluster --config kind-config.yaml
The cluster was created successfully.
Verify the nodes:
kubectl get nodes
Example output:
NAME STATUS ROLES AGE VERSION cka-lab-control-plane Ready control-plane 15m v1.35.0 cka-lab-worker Ready <none> 15m v1.35.0 cka-lab-worker2 Ready <none> 15m v1.35.0
Lessons Learned
The initial Kind error message pointed only to an unhealthy kubelet, but the actual issue was much deeper.
The investigation process that led to the solution was:
- Preserve the failed Kind containers using
--retain. - Connect to the control plane container.
- Inspect the kubelet logs using
journalctl. - Identify the cgroup v1 error.
- Verify Docker's cgroup version.
- Configure WSL to use a unified cgroup v2 hierarchy.
- Restart WSL and Docker Desktop.
- Recreate the cluster successfully.
The key takeaway is that journalctl -u kubelet inside the Kind control plane container provides the real reason behind kubelet startup failures, whereas the error displayed by Kind is often only a symptom.
