Running Kubernetes On Windows With Docker Desktop
· 17 min read · Views --
Last updated on

Running Kubernetes On Windows With Docker Desktop

Author: Alex Xiang


Running Kubernetes On Windows With Docker Desktop

This note records a Windows Kubernetes setup that took quite a bit of trial and error.

The software environment:

  • Windows 11
  • Docker Desktop for Windows
  • WSL2

WSL2 is extremely useful for developers on Windows because it gives a Linux-like environment while still integrating well with Windows. Docker Desktop has also improved its Windows support, especially after adding WSL integration. Docker Desktop can run containers through WSL, Windows, or Hyper-V modes. This note uses the WSL mode.

For beginners, enabling WSL2 can still be a little tedious, but there are many guides now. Docker Desktop installation itself is straightforward. The more interesting part is Kubernetes.

Kind Versus Docker Desktop Kubernetes

One simple way to run Kubernetes on Docker Desktop is Kind. It runs the Kubernetes dependencies inside a single container, and that container acts like a node. It is easy to install and good for learning commands.

But for practical use, it feels more like an experimental Kubernetes environment. Many resources, especially containers, are not visible in the same way in Docker Desktop. I suspect another Docker-like runtime is running inside the Kind container. That makes it useful for learning but not necessarily for everyday local work.

Docker Desktop itself can enable Kubernetes in its settings. In a perfect network environment, checking the option may be enough. In my case, the main difficulty was downloading the required Kubernetes images.

Image Preparation

After Kubernetes support is enabled, Docker Desktop downloads a set of images. If this fails, Kubernetes may stay in Starting state.

For Docker Desktop’s built-in Kubernetes, image versions must match the Kubernetes version bundled with your Docker Desktop version. A small mismatch can prevent startup.

For my setup, Kubernetes was v1.22.5. A useful reference at the time was:

https://github.com/AliyunContainerService/k8s-for-docker-desktop

The corresponding branch contains an images.properties file showing the required images and replacement image locations, for example:

k8s.gcr.io/pause:3.5=registry.cn-hangzhou.aliyuncs.com/google_containers/pause:3.5
k8s.gcr.io/kube-controller-manager:v1.22.5=registry.cn-hangzhou.aliyuncs.com/google_containers/kube-controller-manager:v1.22.5
k8s.gcr.io/kube-scheduler:v1.22.5=registry.cn-hangzhou.aliyuncs.com/google_containers/kube-scheduler:v1.22.5
k8s.gcr.io/kube-proxy:v1.22.5=registry.cn-hangzhou.aliyuncs.com/google_containers/kube-proxy:v1.22.5
k8s.gcr.io/kube-apiserver:v1.22.5=registry.cn-hangzhou.aliyuncs.com/google_containers/kube-apiserver:v1.22.5
k8s.gcr.io/etcd:3.5.0-0=registry.cn-hangzhou.aliyuncs.com/google_containers/etcd:3.5.0-0
k8s.gcr.io/coredns/coredns:v1.8.4=registry.cn-hangzhou.aliyuncs.com/google_containers/coredns:1.8.4

The load_images.ps1 script explains the idea:

foreach($line in Get-Content .\images.properties) {
    $data = $line.Split('=')
    $key = $data[0];
    $value = $data[1];
    Write-Output "$key=$value"
    docker pull ${value}
    docker tag ${value} ${key}
    docker rmi ${value}
}

Each line maps the final image tag to a replacement image. The script pulls the replacement, tags it with the original Kubernetes image name, and removes the replacement tag. If the script fails because of permissions, the same docker pull, docker tag, and docker rmi commands can be run manually.

After all images are ready, Kubernetes should start and the related containers should be visible in Docker Desktop. If it still fails, check the exact image versions again. If necessary, clear Docker Desktop data from Troubleshoot and restart.

Kubernetes Dashboard

After Kubernetes starts, install the dashboard. The upstream repository is:

https://github.com/kubernetes/dashboard

The recommended command at that time was:

kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/v2.5.0/aio/deploy/recommended.yaml

If fetching the URL fails, open the repository page, choose the correct version, copy the YAML content, and apply it locally.

Before login, create a service account:

apiVersion: v1
kind: ServiceAccount
metadata:
  name: admin-user
  namespace: kubernetes-dashboard

Apply it:

kubectl apply -f dashboard-adminuser.yaml

Create a cluster role binding:

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: admin-user
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: cluster-admin
subjects:
- kind: ServiceAccount
  name: admin-user
  namespace: kubernetes-dashboard

Apply it:

kubectl apply -f dashboard-role-binding.yaml

Start the Kubernetes proxy:

kubectl proxy

It listens on 127.0.0.1:8001 by default. Open the dashboard:

http://localhost:8001/api/v1/namespaces/kubernetes-dashboard/services/https:kubernetes-dashboard:/proxy

The dashboard asks for a token. With the service account above, the token can be obtained by:

kubectl -n kubernetes-dashboard get secret \
  $(kubectl -n kubernetes-dashboard get sa/admin-user -o jsonpath="{.secrets[0].name}") \
  -o go-template="{{.data.token | base64decode}}"

Paste the token into the dashboard login page and the local Kubernetes environment is ready for basic use.

Closing

The key lesson is version matching. Docker Desktop’s built-in Kubernetes is convenient, but the image list must match the bundled Kubernetes version exactly. Once the images are correct, the rest of the process is mostly standard Kubernetes setup.