Skip to content

Commit 387002b

Browse files
author
naman-msft
committed
added aks doc on windows node
1 parent 9cedeea commit 387002b

File tree

3 files changed

+449
-0
lines changed

3 files changed

+449
-0
lines changed
Lines changed: 386 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,386 @@
1+
---
2+
title: Deploy a Windows Server container on an Azure Kubernetes Service (AKS) cluster using Azure CLI
3+
description: Learn how to quickly deploy a Kubernetes cluster and deploy an application in a Windows Server container in Azure Kubernetes Service (AKS) using Azure CLI.
4+
ms.topic: quickstart
5+
ms.custom: devx-track-azurecli, innovation-engine
6+
ms.date: 01/11/2024
7+
author: schaffererin
8+
ms.author: schaffererin
9+
---
10+
11+
# Deploy a Windows Server container on an Azure Kubernetes Service (AKS) cluster using Azure CLI
12+
13+
Azure Kubernetes Service (AKS) is a managed Kubernetes service that lets you quickly deploy and manage clusters. In this article, you use Azure CLI to deploy an AKS cluster that runs Windows Server containers. You also deploy an ASP.NET sample application in a Windows Server container to the cluster.
14+
15+
> [!NOTE]
16+
> To get started with quickly provisioning an AKS cluster, this article includes steps to deploy a cluster with default settings for evaluation purposes only. Before deploying a production-ready cluster, we recommend that you familiarize yourself with our [baseline reference architecture][baseline-reference-architecture] to consider how it aligns with your business requirements.
17+
18+
## Before you begin
19+
20+
This quickstart assumes a basic understanding of Kubernetes concepts. For more information, see [Kubernetes core concepts for Azure Kubernetes Service (AKS)](../concepts-clusters-workloads.md).
21+
22+
- [!INCLUDE [quickstarts-free-trial-note](~/reusable-content/ce-skilling/azure/includes/quickstarts-free-trial-note.md)]
23+
24+
[!INCLUDE [azure-cli-prepare-your-environment-no-header.md](~/reusable-content/azure-cli/azure-cli-prepare-your-environment-no-header.md)]
25+
26+
- This article requires version 2.0.64 or later of the Azure CLI. If you're using Azure Cloud Shell, the latest version is already installed there.
27+
- Make sure that the identity you're using to create your cluster has the appropriate minimum permissions. For more details on access and identity for AKS, see [Access and identity options for Azure Kubernetes Service (AKS)](../concepts-identity.md).
28+
- If you have multiple Azure subscriptions, select the appropriate subscription ID in which the resources should be billed using the [az account set](/cli/azure/account#az-account-set) command. For more information, see [How to manage Azure subscriptions – Azure CLI](/cli/azure/manage-azure-subscriptions-azure-cli?tabs=bash#change-the-active-subscription).
29+
30+
## Create a resource group
31+
32+
An [Azure resource group](/azure/azure-resource-manager/management/overview) is a logical group in which Azure resources are deployed and managed. When you create a resource group, you're asked to specify a location. This location is where resource group metadata is stored and where your resources run in Azure if you don't specify another region during resource creation.
33+
34+
- Create a resource group using the [az group create][az-group-create] command. The following example creates a resource group named *myResourceGroup* in the *WestUS2* location. Enter this command and other commands in this article into a BASH shell:
35+
36+
```bash
37+
export RANDOM_SUFFIX=$(openssl rand -hex 3)
38+
export REGION="eastus2"
39+
export MY_RESOURCE_GROUP_NAME="myAKSResourceGroup$RANDOM_SUFFIX"
40+
az group create --name $MY_RESOURCE_GROUP_NAME --location $REGION
41+
```
42+
43+
Results:
44+
45+
<!-- expected_similarity=0.3 -->
46+
47+
```JSON
48+
{
49+
"id": "/subscriptions/xxxxx-xxxxx-xxxxx-xxxxx/resourceGroups/myResourceGroupxxxxx",
50+
"location": "WestUS2",
51+
"managedBy": null,
52+
"name": "myResourceGroupxxxxx",
53+
"properties": {
54+
"provisioningState": "Succeeded"
55+
},
56+
"tags": null,
57+
"type": "Microsoft.Resources/resourceGroups"
58+
}
59+
```
60+
61+
## Create an AKS cluster
62+
63+
In this section, we create an AKS cluster with the following configuration:
64+
65+
- The cluster is configured with two nodes to ensure it operates reliably. A [node](../concepts-clusters-workloads.md#nodes) is an Azure virtual machine (VM) that runs the Kubernetes node components and container runtime.
66+
- The `--windows-admin-password` and `--windows-admin-username` parameters set the administrator credentials for any Windows Server nodes on the cluster and must meet [Windows Server password requirements][windows-server-password].
67+
- The node pool uses `VirtualMachineScaleSets`.
68+
69+
To create the AKS cluster with Azure CLI, follow these steps:
70+
71+
1. Create a username to use as administrator credentials for the Windows Server nodes on your cluster. (The original example prompted for input; in this Exec Doc, the environment variable is set non-interactively.)
72+
73+
```bash
74+
export WINDOWS_USERNAME="winadmin"
75+
```
76+
77+
2. Create a password for the administrator username you created in the previous step. The password must be a minimum of 14 characters and meet the [Windows Server password complexity requirements][windows-server-password].
78+
79+
```bash
80+
export WINDOWS_PASSWORD="$(openssl rand -base64 32 | tr -d '=+/' | cut -c1-14)"
81+
```
82+
83+
3. Create your cluster using the [az aks create][az-aks-create] command and specify the `--windows-admin-username` and `--windows-admin-password` parameters. The following example command creates a cluster using the values from *WINDOWS_USERNAME* and *WINDOWS_PASSWORD* you set in the previous commands. A random suffix is appended to the cluster name for uniqueness.
84+
85+
```bash
86+
export MY_AKS_CLUSTER="myAKSCluster$RANDOM_SUFFIX"
87+
```
88+
89+
```bash
90+
export MY_AKS_CLUSTER="myAKSCluster$RANDOM_SUFFIX"
91+
az aks create \
92+
--resource-group $MY_RESOURCE_GROUP_NAME \
93+
--name $MY_AKS_CLUSTER \
94+
--node-count 2 \
95+
--enable-addons monitoring \
96+
--generate-ssh-keys \
97+
--windows-admin-username $WINDOWS_USERNAME \
98+
--windows-admin-password $WINDOWS_PASSWORD \
99+
--vm-set-type VirtualMachineScaleSets \
100+
--network-plugin azure
101+
```
102+
103+
After a few minutes, the command completes and returns JSON-formatted information about the cluster. Occasionally, the cluster can take longer than a few minutes to provision. Allow up to 10 minutes for provisioning.
104+
105+
If you get a password validation error, and the password that you set meets the length and complexity requirements, try creating your resource group in another region. Then try creating the cluster with the new resource group.
106+
107+
If you don't specify an administrator username and password when creating the node pool, the username is set to *azureuser* and the password is set to a random value. For more information, see the [Windows Server FAQ](../windows-faq.yml)
108+
109+
The administrator username can't be changed, but you can change the administrator password that your AKS cluster uses for Windows Server nodes using `az aks update`. For more information, see [Windows Server FAQ](../windows-faq.yml).
110+
111+
To run an AKS cluster that supports node pools for Windows Server containers, your cluster needs to use a network policy that uses [Azure CNI (advanced)][azure-cni] network plugin. The `--network-plugin azure` parameter specifies Azure CNI.
112+
113+
## Add a node pool
114+
115+
By default, an AKS cluster is created with a node pool that can run Linux containers. You must add another node pool that can run Windows Server containers alongside the Linux node pool.
116+
117+
Windows Server 2022 is the default operating system for Kubernetes versions 1.25.0 and higher. Windows Server 2019 is the default OS for earlier versions. If you don't specify a particular OS SKU, Azure creates the new node pool with the default SKU for the version of Kubernetes used by the cluster.
118+
119+
### [Windows node pool (default SKU)](#tab/add-windows-node-pool)
120+
121+
To use the default OS SKU, create the node pool without specifying an OS SKU. The node pool is configured for the default operating system based on the Kubernetes version of the cluster.
122+
123+
Add a Windows node pool using the `az aks nodepool add` command. The following command creates a new node pool named *npwin* and adds it to *myAKSCluster*. The command also uses the default subnet in the default virtual network created when running `az aks create`. An OS SKU isn't specified, so the node pool is set to the default operating system based on the Kubernetes version of the cluster:
124+
125+
```text
126+
az aks nodepool add \
127+
--resource-group $MY_RESOURCE_GROUP_NAME \
128+
--cluster-name $MY_AKS_CLUSTER \
129+
--os-type Windows \
130+
--name npwin \
131+
--node-count 1
132+
```
133+
134+
### [Windows Server 2022 node pool](#tab/add-windows-server-2022-node-pool)
135+
136+
To use Windows Server 2022, specify the following parameters:
137+
138+
- `os-type` set to `Windows`
139+
- `os-sku` set to `Windows2022`
140+
141+
> [!NOTE]
142+
> Windows Server 2022 requires Kubernetes version 1.23.0 or higher. Windows Server 2022 is being retired after Kubernetes version 1.34 reaches its end of support. Windows Server 2022 will not be supported in Kubernetes version 1.35 and above. For more information about this retirement, see the [AKS release notes][aks-release-notes].
143+
144+
Add a Windows Server 2022 node pool using the `az aks nodepool add` command:
145+
146+
```text
147+
az aks nodepool add \
148+
--resource-group $MY_RESOURCE_GROUP_NAME \
149+
--cluster-name $MY_AKS_CLUSTER \
150+
--os-type Windows \
151+
--os-sku Windows2022 \
152+
--name npwin \
153+
--node-count 1
154+
```
155+
156+
### [Windows Server 2019 node pool](#tab/add-windows-server-2019-node-pool)
157+
158+
To use Windows Server 2019, specify the following parameters:
159+
160+
- `os-type` set to `Windows`
161+
- `os-sku` set to `Windows2019`
162+
163+
> [!NOTE]
164+
> Windows Server 2019 is being retired after Kubernetes version 1.32 reaches end of support. Windows Server 2019 will not be supported in Kubernetes version 1.33 and above. For more information about this retirement, see the [AKS release notes][aks-release-notes].
165+
166+
Add a Windows Server 2019 node pool using the `az aks nodepool add` command:
167+
168+
```text
169+
az aks nodepool add \
170+
--resource-group $MY_RESOURCE_GROUP_NAME \
171+
--cluster-name $MY_AKS_CLUSTER \
172+
--os-type Windows \
173+
--os-sku Windows2019 \
174+
--name npwin \
175+
--node-count 1
176+
```
177+
178+
## Connect to the cluster
179+
180+
You use [kubectl][kubectl], the Kubernetes command-line client, to manage your Kubernetes clusters. If you use Azure Cloud Shell, `kubectl` is already installed. If you want to install and run `kubectl` locally, call the [az aks install-cli][az-aks-install-cli] command.
181+
182+
1. Configure `kubectl` to connect to your Kubernetes cluster using the [az aks get-credentials][az-aks-get-credentials] command. This command downloads credentials and configures the Kubernetes CLI to use them.
183+
184+
```bash
185+
az aks get-credentials --resource-group $MY_RESOURCE_GROUP_NAME --name $MY_AKS_CLUSTER
186+
```
187+
188+
2. Verify the connection to your cluster using the [kubectl get][kubectl-get] command, which returns a list of the cluster nodes.
189+
190+
```bash
191+
kubectl get nodes -o wide
192+
```
193+
194+
The following sample output shows all nodes in the cluster. Make sure the status of all nodes is *Ready*:
195+
196+
<!-- expected_similarity=0.3 -->
197+
198+
```text
199+
NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
200+
aks-nodepool1-20786768-vmss000000 Ready agent 22h v1.27.7 10.224.0.4 <none> Ubuntu 22.04.3 LTS 5.15.0-1052-azure containerd://1.7.5-1
201+
aks-nodepool1-20786768-vmss000001 Ready agent 22h v1.27.7 10.224.0.33 <none> Ubuntu 22.04.3 LTS 5.15.0-1052-azure containerd://1.7.5-1
202+
aksnpwin000000 Ready agent 20h v1.27.7 10.224.0.62 <none> Windows Server 2022 Datacenter 10.0.20348.2159 containerd://1.6.21+azure
203+
```
204+
205+
> [!NOTE]
206+
> The container runtime for each node pool is shown under *CONTAINER-RUNTIME*. The container runtime values begin with `containerd://`, which means that they each use `containerd` for the container runtime.
207+
208+
## Deploy the application
209+
210+
A Kubernetes manifest file defines a desired state for the cluster, such as what container images to run. In this article, you use a manifest to create all objects needed to run the ASP.NET sample application in a Windows Server container. This manifest includes a [Kubernetes deployment][kubernetes-deployment] for the ASP.NET sample application and an external [Kubernetes service][kubernetes-service] to access the application from the internet.
211+
212+
The ASP.NET sample application is provided as part of the [.NET Framework Samples][dotnet-samples] and runs in a Windows Server container. AKS requires Windows Server containers to be based on images of *Windows Server 2019* or greater. The Kubernetes manifest file must also define a [node selector][node-selector] to tell your AKS cluster to run your ASP.NET sample application's pod on a node that can run Windows Server containers.
213+
214+
1. Create a file named `sample.yaml` and copy in the following YAML definition.
215+
216+
```yaml
217+
apiVersion: apps/v1
218+
kind: Deployment
219+
metadata:
220+
name: sample
221+
labels:
222+
app: sample
223+
spec:
224+
replicas: 1
225+
template:
226+
metadata:
227+
name: sample
228+
labels:
229+
app: sample
230+
spec:
231+
nodeSelector:
232+
"kubernetes.io/os": windows
233+
containers:
234+
- name: sample
235+
image: mcr.microsoft.com/dotnet/framework/samples:aspnetapp
236+
resources:
237+
limits:
238+
cpu: 1
239+
memory: 800M
240+
ports:
241+
- containerPort: 80
242+
selector:
243+
matchLabels:
244+
app: sample
245+
---
246+
apiVersion: v1
247+
kind: Service
248+
metadata:
249+
name: sample
250+
spec:
251+
type: LoadBalancer
252+
ports:
253+
- protocol: TCP
254+
port: 80
255+
selector:
256+
app: sample
257+
```
258+
259+
For a breakdown of YAML manifest files, see [Deployments and YAML manifests](../concepts-clusters-workloads.md#deployments-and-yaml-manifests).
260+
261+
If you create and save the YAML file locally, then you can upload the manifest file to your default directory in CloudShell by selecting the **Upload/Download files** button and selecting the file from your local file system.
262+
263+
2. Deploy the application using the [kubectl apply][kubectl-apply] command and specify the name of your YAML manifest.
264+
265+
```bash
266+
kubectl apply -f sample.yaml
267+
```
268+
269+
The following sample output shows the deployment and service created successfully:
270+
271+
<!-- expected_similarity=0.3 -->
272+
273+
```text
274+
{
275+
"deployment.apps/sample": "created",
276+
"service/sample": "created"
277+
}
278+
```
279+
280+
## Test the application
281+
282+
When the application runs, a Kubernetes service exposes the application front end to the internet. This process can take a few minutes to complete. Occasionally, the service can take longer than a few minutes to provision. Allow up to 10 minutes for provisioning.
283+
284+
1. Check the status of the deployed pods using the [kubectl get pods][kubectl-get] command. Make sure all pods are `Running` before proceeding.
285+
286+
```bash
287+
kubectl get pods
288+
```
289+
290+
2. Monitor progress using the [kubectl get service][kubectl-get] command with the `--watch` argument.
291+
292+
```bash
293+
while true; do
294+
export EXTERNAL_IP=$(kubectl get service sample -o jsonpath="{.status.loadBalancer.ingress[0].ip}" 2>/dev/null)
295+
if [[ -n "$EXTERNAL_IP" && "$EXTERNAL_IP" != "<pending>" ]]; then
296+
kubectl get service sample
297+
break
298+
fi
299+
echo "Still waiting for external IP assignment..."
300+
sleep 5
301+
done
302+
```
303+
304+
Initially, the output shows the *EXTERNAL-IP* for the sample service as *pending*:
305+
306+
<!-- expected_similarity=0.3 -->
307+
308+
```text
309+
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
310+
sample LoadBalancer xx.xx.xx.xx pending xx:xxxx/TCP 2m
311+
```
312+
313+
When the *EXTERNAL-IP* address changes from *pending* to an actual public IP address, use `CTRL-C` to stop the `kubectl` watch process. The following sample output shows a valid public IP address assigned to the service:
314+
315+
```JSON
316+
{
317+
"NAME": "sample",
318+
"TYPE": "LoadBalancer",
319+
"CLUSTER-IP": "10.0.37.27",
320+
"EXTERNAL-IP": "52.179.23.131",
321+
"PORT(S)": "80:30572/TCP",
322+
"AGE": "2m"
323+
}
324+
```
325+
326+
3. See the sample app in action by opening a web browser to the external IP address of your service.
327+
328+
```bash
329+
curl -s $EXTERNAL_IP | head -n 20
330+
```
331+
332+
The following sample output shows the HTML content returned by the ASP.NET sample application:
333+
334+
<!-- expected_similarity=0.3 -->
335+
336+
```text
337+
<!DOCTYPE html>
338+
<html lang="en">
339+
<head>
340+
<meta charset="utf-8" />
341+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
342+
<title>Home Page - ASP.NET Application</title>
343+
<script src="/Scripts/modernizr.js"></script>
344+
<link href="/Content/bootstrap.css" rel="stylesheet"/>
345+
<link href="/Content/Site.css" rel="stylesheet"/>
346+
<link href="favicon.ico" rel="shortcut icon" type="image/x-icon" />
347+
</head>
348+
<body>
349+
<form method="post" action="./" id="form1">
350+
<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="[VIEWSTATE_REMOVED]" />
351+
<script src="/bundles/MsAjaxJs" type="text/javascript"></script>
352+
<script type="text/javascript">
353+
// Script content here
354+
```
355+
356+
:::image type="content" source="media/quick-windows-container-deploy-cli/asp-net-sample-app.png" alt-text="Screenshot of browsing to ASP.NET sample application." lightbox="media/quick-windows-container-deploy-cli/asp-net-sample-app.png":::
357+
358+
## Next steps
359+
360+
In this quickstart, you deployed a Kubernetes cluster and then deployed an ASP.NET sample application in a Windows Server container to it. This sample application is for demo purposes only and doesn't represent all the best practices for Kubernetes applications. For guidance on creating full solutions with AKS for production, see [AKS solution guidance][aks-solution-guidance].
361+
362+
To learn more about AKS, and to walk through a complete code-to-deployment example, continue to the Kubernetes cluster tutorial.
363+
364+
> [!div class="nextstepaction"]
365+
> [AKS tutorial][aks-tutorial]
366+
367+
<!-- LINKS - external -->
368+
[kubectl]: https://kubernetes.io/docs/reference/kubectl/
369+
[kubectl-apply]: https://kubernetes.io/docs/reference/generated/kubectl/kubectl-commands#apply
370+
[kubectl-get]: https://kubernetes.io/docs/reference/generated/kubectl/kubectl-commands#get
371+
[node-selector]: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/
372+
[dotnet-samples]: https://hub.docker.com/_/microsoft-dotnet-framework-samples/
373+
[azure-cni]: https://github.com/Azure/azure-container-networking/blob/master/docs/cni.md
374+
[aks-release-notes]: https://github.com/Azure/AKS/releases
375+
376+
<!-- LINKS - internal -->
377+
[aks-tutorial]: ../tutorial-kubernetes-prepare-app.md
378+
[az-aks-create]: /cli/azure/aks#az_aks_create
379+
[az-aks-get-credentials]: /cli/azure/aks#az_aks_get_credentials
380+
[az-aks-install-cli]: /cli/azure/aks#az_aks_install_cli
381+
[az-group-create]: /cli/azure/group#az_group_create
382+
[aks-solution-guidance]: /azure/architecture/reference-architectures/containers/aks-start-here?toc=/azure/aks/toc.json&bc=/azure/aks/breadcrumb/toc.json
383+
[kubernetes-deployment]: ../concepts-clusters-workloads.md#deployments-and-yaml-manifests
384+
[kubernetes-service]: ../concepts-network-services.md
385+
[windows-server-password]: /windows/security/threat-protection/security-policy-settings/password-must-meet-complexity-requirements#reference
386+
[baseline-reference-architecture]: /azure/architecture/reference-architectures/containers/aks/baseline-aks?toc=/azure/aks/toc.json&bc=/azure/aks/breadcrumb/toc.json

0 commit comments

Comments
 (0)