Install kubernetes on windows + WSL

While Windows Subsystem for Linux (WSL) does a decent job providing a unix system, it cannot run natively anything that requires access to virtualisation — for now.

If you already have docker installed, there’s a workaround: install minikube on windows, and then connect to that from within WSL.

To do that, start by opening powershell as an administrator:

Windows key, search “powershell”, right click, “Run as Administrator”

In the powershell window, paste the following commands to install minikube and kubectl:

cd $env:userprofile\AppData\Local\Microsoft\WindowsApps
# replace 1.9.0 with the most recent version
wget https://storage.googleapis.com/kubernetes-release/release/v1
.9.0/bin/windows/amd64/kubectl.exe -OutFile kubectl.exe
# replace 0.24.1 with the most recent version
wget https://storage.googleapis.com/minikube/releases/v0.24.1/minikube-windows-amd64.exe -OutFile minikube.exe

Now we need to create a virtual machine using hyper-v.
There’s currently a bug that keeps minikube hanging on start — as a workaround, create a new external virtual switch.
Name it “Primary Virtual Switch” (“The neighbours stole my dog” works just as well tbh) and use it to start the kubernetes cluster:

minikube.exe start --vm-driver=hyperv --hyperv-virtual-switch="Primary Virtual Switch"
# at this point you can already use kubectl inside powershell, but we're going to set it up inside WSL instead:
kubectl.exe config view > $env:TEMP/kubectl-config
minikube.exe docker-env --shell=bash > $env:TEMP/minikube-config
# convert line endings to unix format
Get-ChildItem -File -Filter *-config | % { $x = get-content -raw -path $_.fullname
; $x -replace "`r`n","`n" | set-content -path $_.fullname }

That’s everything we need to do in powershell, now open the WSL bash:

# install kubectl
curl -LO https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/amd64/kubectl && \
chmod +x kubectl && \
sudo mv kubectl /usr/local/bin/
# cd into windows' TEMP folder.
# Since paths are different from unix, we need to normalise them first
cd /mnt/$(cmd.exe /c echo\|set /p=%TEMP% | sed --expression='s|\\|/|g' | sed --expression='s|^\([A-Za-z]\):|\L\1|')
mkdir ~/.{kube,minikube}
mv kubectl-config ~/.kube/config
mv minikube-config ~/.minikube/docker-env
# convert windows paths to unix format
sed -i 's|\\|/|g' ~/.{kube,minikube}/{config,docker-env}
sed -i 's|\([ "]\)\([A-Za-z]\):|\1/mnt/\L\2|' ~/.{kube,minikube}/{config,docker-env}
kubectl config use-context minikube
# optional, if you want to use a local docker image
# e.g. docker build -t <your-image-name> .
eval $(cat ~/.minikube/docker-env)
# we can now launch a sample app
kubectl run hello-minikube --image=k8s.gcr.io/echoserver:1.4 --port=8080
# alternatively you can deploy your local docker image with
# kubectl run hello-minikube --image=<your-image-name> --port=<someport> --image-pull-policy=Never

That’s almost everything needed to see your service running — at this stage, it will only be accessible to kubernetes’ internal network.
Let’s make sure the deployment is working first:

$ kubectl get deployment
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
hello-minikube 1 1 1 1 21s
$ kubectl get pod
NAME READY STATUS RESTARTS AGE
hello-minikube-7844bdb9c6-wkqtb 1/1 Running 0 34s

Now we can expose the service to the outside world:

$ kubectl expose deployment hello-minikube --type=NodePort
service "hello-minikube" exposed
$ kubectl get service hello-minikube
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
hello-minikube NodePort 10.110.6.111 <none> 8080:30668/TCP 19s
# ☝ ️30668 externally reachable port

We need to go back to powershell to see the service in action:

## should open a browser tab showing the service just deployed
minikube.exe service hello-minikube

That’s it! Now might be a good time to enable autocompletion for kubectl.
Go deploy all the things!