- Home
- Operations Guide
- Deploy applications with Kubernetes
- Use Kubernetes on Windows Server nodes
Use Kubernetes on Windows Server nodes#
Observe the following prerequisites prior to using Kubernetes on Windows Server nodes.
-
Install MKE.
Note
Running Kubernetes on Windows Server nodes is only supported on MKE 3.3.0 and later. If you want to run Kubernetes on Windows Server nodes on a cluster that is currently running an earlier version of MKE than 3.3.0, you must perform a fresh install of MKE 3.3.0 or later.
Add Windows Server nodes#
-
Log in to the MKE web UI.
-
In the left-side navigation panel, navigate to Shared Resources > Nodes and click Add Node.
-
Under NODE TYPE, select Windows. Windows Server nodes can only be workers.
-
Optional. Specify custom listen and advertise addresses by using the relevant slider.
-
Copy the command generated at the bottom of the Add Node page, which includes the
join-token.Example command:
docker swarm join \ --token SWMTKN-1-2is7c14ff43tq1g61ubc5egvisgilh6m8qxm6dndjzgov9qjme-4388n8bpyqivzudz4fidqm7ey \ 172.31.2.154:2377 -
Add your Windows Server node to the MKE cluster by running the
docker swarm joincommand copied in the previous step.
Validate your cluster#
To validate your cluster using the MKE web UI:
-
Log in to the MKE web UI.
-
In the left-side navigation panel, navigate to Nodes. A green circle indicates a healthy node state. All nodes should be green.
-
Change each node orchestrator to Kubernetes:
-
Click on the node.
-
In the upper-right corner, click the slider icon.
-
In the Role section of the Details tab, select Kubernetes under ORCHESTRATOR TYPE.
-
Click Save.
-
Repeat the above steps for each node.
-
To validate your cluster using the command line:
-
View the status of all the nodes in your cluster:
kubectl get nodesYour nodes should all have a status value of
Ready, as in the following example:NAME STATUS ROLES AGE VERSION user-135716-win-0 Ready <none> 2m16s v1.17.2 user-7d985f-ubuntu-0 Ready master 4m55s v1.17.2-docker-d-2 user-135716-win-1 Ready <none> 1m12s v1.17.2 -
Change each node orchestrator to Kubernetes:
docker node update <node name> --label-add com.docker.ucp.orchestrator.kubernetes=true -
Repeat the last step for each node.
-
Deploy a workload on your cluster to verify that everything works as expected.
Troubleshoot#
If you cannot join your Windows Server node to the cluster, confirm that the correct processes are running on the node.
-
Verify that the
calico-nodeprocess is operational:PS C:\> Get-Process calico-nodeExample output:
Handles NPM(K) PM(K) WS(K) CPU(s) Id SI ProcessName ------- ------ ----- ----- ------ -- -- ----------- 276 17 33284 40948 39.89 8132 0 calico-node -
Verify that the
kubeletprocess is operational:PS C:\> Get-Process kubeletExample output:
Handles NPM(K) PM(K) WS(K) CPU(s) Id SI ProcessName ------- ------ ----- ----- ------ -- -- ----------- 524 23 47332 73380 828.50 6520 0 kubelet -
Verify that the
kube-proxyprocess is operational:PS C:\> Get-Process kube-proxyExample output:
Handles NPM(K) PM(K) WS(K) CPU(s) Id SI ProcessName ------- ------ ----- ----- ------ -- -- ----------- 322 19 25464 33488 21.00 7852 0 kube-proxy -
If any of the process verifications indicate a problem, review the container logs that bootstrap the Kubernetes components on the Windows node:
docker container logs (docker container ls --filter name=ucp-kubelet-win -q) docker container logs (docker container ls --filter name=ucp-kube-proxy -q) docker container logs (docker container ls --filter name=ucp-tigera-node-win -q) docker container logs (docker container ls --filter name=ucp-tigera-felix-win -q)
Deploy a workload on Windows Server#
The following procedure deploys a complete web application on IIS servers as Kubernetes Services. The example workload includes an MSSQL database and a load balancer. The procedure includes the following tasks:
- Namespace creation
- Pod and deployment scheduling
- Kubernetes Service provisioning
- Application workload deployment
-
Pod, Node, and Service configuration
-
Create the following namespace file:
demo-namespace.yamlapiVersion: v1 kind: Namespace metadata: name: demo -
Create a namespace:
kubectl create -f demo-namespace.yaml -
Create the following Windows web server file:
win-webserver.yamlapiVersion: v1 kind: Service metadata: name: win-webserver labels: app: win-webserver namespace: demo spec: ports: - port: 80 targetPort: 80 selector: app: win-webserver type: NodePort --- apiVersion: apps/v1 kind: Deployment metadata: name: win-webserver labels: app: win-webserver namespace: demo spec: replicas: 2 selector: matchLabels: app: win-webserver template: metadata: labels: app: win-webserver spec: affinity: podAntiAffinity: requiredDuringSchedulingIgnoredDuringExecution: - labelSelector: matchExpressions: - key: app operator: In values: - win-webserver topologyKey: "kubernetes.io/hostname" containers: - name: windowswebserver image: mcr.microsoft.com/windows/servercore:ltsc2019 command: - powershell.exe - -command - "<#code used from https://gist.github.com/wagnerandrade/5424431#> ; $$listener = New-Object System.Net.HttpListener ; $$listener.Prefixes.Add('http://*:80/') ; $$listener.Start() ; $$callerCounts = @{} ; Write-Host('Listening at http://*:80/') ; while ($$listener.IsListening) { ;$$context = $$listener.GetContext() ;$$requestUrl = $$context.Request.Url ;$$clientIP = $$context.Request.RemoteEndPoint.Address ;$$response = $$context.Response ;Write-Host '' ;Write-Host('> {0}' -f $$requestUrl) ; ;$$count = 1 ;$$k=$$callerCounts.Get_Item($$clientIP) ;if ($$k -ne $$null) { $$count += $$k } ;$$callerCounts.Set_Item($$clientIP, $$count) ;$$ip=(Get-NetAdapter | Get-NetIpAddress); $$header='<html><body><H1>Windows Container Web Server</H1>' ;$$callerCountsString='' ;$$callerCounts.Keys | % { $$callerCountsString+='<p>IP {0} callerCount {1} ' -f $$ip[1].IPAddress,$$callerCounts.Item($$_) } ;$$footer='</body></html>' ;$$content='{0}{1}{2}' -f $$header,$$callerCountsString,$$footer ;Write-Output $$content ;$$buffer = [System.Text.Encoding]::UTF8.GetBytes($$content) ;$$response.ContentLength64 = $$buffer.Length ;$$response.OutputStream.Write($$buffer, 0, $$buffer.Length) ;$$response.Close() ;$$responseStatus = $$response.StatusCode ;Write-Host('< {0}' -f $$responseStatus) } ; " nodeSelector: kubernetes.io/os: windowsNote
If the Windows nodes in your MKE cluster are Windows Server 2022, edit the image tag in the win-webserver.yaml file from
ltsc2019toltsc2022. -
Create the web service:
kubectl create -f win-webserver.yamlExpected output:
service/win-webserver created deployment.apps/win-webserver created -
Verify creation of the Kubernetes Service:
kubectl get service --namespace demoExpected output:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE win-webserver NodePort 10.96.29.12 <none> 80:35048/TCP 12m -
Review the pods deployed on your Windows Server worker nodes with inter-pod affinity and anti-affinity.
Note
After creating the web service, it may take several minutes for the pods to enter a ready state.
kubectl get pod --namespace demoExpected output:
NAME READY STATUS RESTARTS AGE win-webserver-8c5678c68-qggzh 1/1 Running 0 6m21s win-webserver-8c5678c68-v8p84 1/1 Running 0 6m21s -
Review the detailed status of pods deployed:
kubectl describe pod win-webserver-8c5678c68-qggzh --namespace demo -
From a kubectl client, access the web service using node-to-pod communication across the network:
kubectl get pods --namespace demo -o wideExample output:
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES win-webserver-8c5678c68-qggzh 1/1 Running 0 16m 192.168.77.68 user-135716-win-1 <none> <none> win-webserver-8c5678c68-v8p84 1/1 Running 0 16m 192.168.4.206 user-135716-win-0 <none> <none> -
SSH into the master node:
ssh -o ServerAliveInterval=15 root@<master-node> -
Use
curlto access the web service by way of theCLUSTER-IPlisted for thewin-webserverservice.curl 10.96.29.12Example output:
<html><body><H1>Windows Container Web Server</H1><p>IP 192.168.77.68 callerCount 1 </body></html> -
Run the
curlcommand a second time. You can see the second request load-balanced to a different pod:curl 10.96.29.12Example output:
<html><body><H1>Windows Container Web Server</H1><p>IP 192.168.4.206 callerCount 1 </body></html> -
From a kubectl client, access the web service using pod-to-pod communication across the network:
kubectl get service --namespace demoExpample output:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE win-webserver NodePort 10.96.29.12 <none> 80:35048/TCP 12m -
Review the pod status:
kubectl get pods --namespace demo -o wideExample output:
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES win-webserver-8c5678c68-qggzh 1/1 Running 0 16m 192.168.77.68 user-135716-win-1 <none> <none> win-webserver-8c5678c68-v8p84 1/1 Running 0 16m 192.168.4.206 user-135716-win-0 <none> <none> -
Exec into the web service:
kubectl exec -it win-webserver-8c5678c68-qggzh --namespace demo cmdExample output:
Microsoft Windows [Version 10.0.17763.1098] (c) 2018 Microsoft Corporation. All rights reserved. -
Use
curlto access the web service:C:\>curl 10.96.29.12Example output:
<html><body><H1>Windows Container Web Server</H1><p>IP 192.168.77.68 callerCount 1 <p>IP 192.168.77.68 callerCount 1 </body></html>