Skip to content

Aks updated doc #60

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 8 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
316 changes: 42 additions & 274 deletions scenarios/CreateAKSDeployment/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ description: This tutorial where we will take you step by step in creating an Az
author: mbifeld
ms.author: mbifeld
ms.topic: article
ms.date: 11/28/2023
ms.custom: innovation-engine
ms.date: 04/04/2024
ms.custom: innovation-engine, linux-related content
---

# Quickstart: Deploy a Scalable & Secure Azure Kubernetes Service cluster using the Azure CLI
Expand All @@ -20,18 +20,11 @@ The first step in this tutorial is to define environment variables.

```bash
export RANDOM_ID="$(openssl rand -hex 3)"
export NETWORK_PREFIX="$(($RANDOM % 254 + 1))"
export SSL_EMAIL_ADDRESS="$(az account show --query user.name --output tsv)"
export MY_RESOURCE_GROUP_NAME="myAKSResourceGroup$RANDOM_ID"
export REGION="westeurope"
export MY_AKS_CLUSTER_NAME="myAKSCluster$RANDOM_ID"
export MY_PUBLIC_IP_NAME="myPublicIP$RANDOM_ID"
export MY_DNS_LABEL="mydnslabel$RANDOM_ID"
export MY_VNET_NAME="myVNet$RANDOM_ID"
export MY_VNET_PREFIX="10.$NETWORK_PREFIX.0.0/16"
export MY_SN_NAME="mySN$RANDOM_ID"
export MY_SN_PREFIX="10.$NETWORK_PREFIX.0.0/22"
export FQDN="${MY_DNS_LABEL}.${REGION}.cloudapp.azure.com"
```

## Create a resource group
Expand Down Expand Up @@ -60,96 +53,17 @@ Results:
}
```

## Create a virtual network and subnet

A virtual network is the fundamental building block for private networks in Azure. Azure Virtual Network enables Azure resources like VMs to securely communicate with each other and the internet.

```bash
az network vnet create \
--resource-group $MY_RESOURCE_GROUP_NAME \
--location $REGION \
--name $MY_VNET_NAME \
--address-prefix $MY_VNET_PREFIX \
--subnet-name $MY_SN_NAME \
--subnet-prefixes $MY_SN_PREFIX
```

Results:

<!-- expected_similarity=0.3 -->

```JSON
{
"newVNet": {
"addressSpace": {
"addressPrefixes": [
"10.xxx.0.0/16"
]
},
"enableDdosProtection": false,
"id": "/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/myAKSResourceGroupxxxxxx/providers/Microsoft.Network/virtualNetworks/myVNetxxx",
"location": "eastus",
"name": "myVNetxxx",
"provisioningState": "Succeeded",
"resourceGroup": "myAKSResourceGroupxxxxxx",
"subnets": [
{
"addressPrefix": "10.xxx.0.0/22",
"delegations": [],
"id": "/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/myAKSResourceGroupxxxxxx/providers/Microsoft.Network/virtualNetworks/myVNetxxx/subnets/mySNxxx",
"name": "mySNxxx",
"privateEndpointNetworkPolicies": "Disabled",
"privateLinkServiceNetworkPolicies": "Enabled",
"provisioningState": "Succeeded",
"resourceGroup": "myAKSResourceGroupxxxxxx",
"type": "Microsoft.Network/virtualNetworks/subnets"
}
],
"type": "Microsoft.Network/virtualNetworks",
"virtualNetworkPeerings": []
}
}
```

## Register to AKS Azure Resource Providers

Verify Microsoft.OperationsManagement and Microsoft.OperationalInsights providers are registered on your subscription. These are Azure resource providers required to support [Container insights](https://docs.microsoft.com/azure/azure-monitor/containers/container-insights-overview). To check the registration status, run the following commands

```bash
az provider register --namespace Microsoft.Insights
az provider register --namespace Microsoft.OperationsManagement
az provider register --namespace Microsoft.OperationalInsights
```

## Create AKS Cluster

Create an AKS cluster using the az aks create command with the --enable-addons monitoring parameter to enable Container insights. The following example creates an autoscaling, availability zone enabled cluster.

This will take a few minutes.
Create an AKS cluster use the az aks create command. The following example creates a cluster named myAKSCluster with one node and enables a system-assigned managed identity. This will take a few minutes.

```bash
export MY_SN_ID=$(az network vnet subnet list --resource-group $MY_RESOURCE_GROUP_NAME --vnet-name $MY_VNET_NAME --query "[0].id" --output tsv)
az aks create \
--resource-group $MY_RESOURCE_GROUP_NAME \
--name $MY_AKS_CLUSTER_NAME \
--auto-upgrade-channel stable \
--enable-cluster-autoscaler \
--enable-addons monitoring \
--location $REGION \
--node-count 1 \
--min-count 1 \
--max-count 3 \
--network-plugin azure \
--network-policy azure \
--vnet-subnet-id $MY_SN_ID \
--no-ssh-key \
--node-vm-size Standard_DS2_v2 \
--zones 1 2 3
az aks create --resource-group $MY_RESOURCE_GROUP_NAME --name $MY_AKS_CLUSTER_NAME --enable-managed-identity --node-count 1 --generate-ssh-keys
```

## Connect to the cluster

To manage a Kubernetes cluster, use the Kubernetes command-line client, kubectl. kubectl is already installed if you use Azure Cloud Shell.
To manage a Kubernetes cluster, use the Kubernetes command-line client, kubectl. kubectl is already installed if you use Azure Cloud Shell. To install kubectl locally, call the az aks install-cli command.

1. Install az aks CLI locally using the az aks install-cli command

Expand All @@ -175,41 +89,21 @@ To manage a Kubernetes cluster, use the Kubernetes command-line client, kubectl.
kubectl get nodes
```

## Install NGINX Ingress Controller

```bash
export MY_STATIC_IP=$(az network public-ip create --resource-group MC_${MY_RESOURCE_GROUP_NAME}_${MY_AKS_CLUSTER_NAME}_${REGION} --location ${REGION} --name ${MY_PUBLIC_IP_NAME} --dns-name ${MY_DNS_LABEL} --sku Standard --allocation-method static --version IPv4 --zone 1 2 3 --query publicIp.ipAddress -o tsv)
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm repo update
helm upgrade --install ingress-nginx ingress-nginx/ingress-nginx \
--namespace ingress-nginx \
--create-namespace \
--set controller.service.annotations."service\.beta\.kubernetes\.io/azure-dns-label-name"=$MY_DNS_LABEL \
--set controller.service.loadBalancerIP=$MY_STATIC_IP \
--set controller.service.annotations."service\.beta\.kubernetes\.io/azure-load-balancer-health-probe-request-path"=/healthz \
--wait
```

## Deploy the Application

A Kubernetes manifest file defines a cluster's desired state, such as which container images to run.

In this quickstart, you will use a manifest to create all objects needed to run the Azure Vote application. This manifest includes two Kubernetes deployments:

- The sample Azure Vote Python applications.
- A Redis instance.

Two Kubernetes Services are also created:
In this quickstart, you will use a manifest to create all objects needed to run the AKS Store application. The manifest includes the following Kubernetes deployments and services:

- An internal service for the Redis instance.
- An external service to access the Azure Vote application from the internet.
- **Store front**: Web application for customers to view products and place orders.
- **Product service**: Shows product information.
- **Order service**: Places orders.
- **Rabbit MQ**: Message queue for an order queue.

Finally, an Ingress resource is created to route traffic to the Azure Vote application.

A test voting app YML file is already prepared. To deploy this app run the following command
A test store front application YML file is already prepared. To deploy this app run the following command

```bash
kubectl apply -f azure-vote-start.yml
kubectl apply -f aks-store-quickstart.yml
```

## Test The Application
Expand All @@ -220,178 +114,52 @@ Validate that the application is running by either visiting the public ip or the
> It often takes 2-3 minutes for the PODs to be created and the site to be reachable via HTTP

```bash
runtime="5 minute";
endtime=$(date -ud "$runtime" +%s);
while [[ $(date -u +%s) -le $endtime ]]; do
STATUS=$(kubectl get pods -l app=azure-vote-front -o 'jsonpath={..status.conditions[?(@.type=="Ready")].status}'); echo $STATUS;
if [ "$STATUS" == 'True' ]; then
break;
runtime="5 minute"
endtime=$(date -ud "$runtime" +%s)
while [[ $(date -u +%s) -le $endtime ]]
do
STATUS=$(kubectl get pods -l app=store-front -o 'jsonpath={..status.conditions[?(@.type=="Ready")].status}')
echo $STATUS
if [ "$STATUS" == 'True' ]
then
export IP_ADDRESS=$(kubectl get service store-front --output 'jsonpath={..status.loadBalancer.ingress[0].ip}')
echo "Service IP Address: $IP_ADDRESS"
break
else
sleep 10;
fi;
sleep 10
fi
done
```

```bash
curl "http://$FQDN"
curl $IP_ADDRESS
```

Results:

<!-- expected_similarity=0.3 -->

```HTML
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<link rel="stylesheet" type="text/css" href="/static/default.css">
<title>Azure Voting App</title>

<script language="JavaScript">
function send(form){
}
</script>

</head>
<body>
<div id="container">
<form id="form" name="form" action="/"" method="post"><center>
<div id="logo">Azure Voting App</div>
<div id="space"></div>
<div id="form">
<button name="vote" value="Cats" onclick="send()" class="button button1">Cats</button>
<button name="vote" value="Dogs" onclick="send()" class="button button2">Dogs</button>
<button name="vote" value="reset" onclick="send()" class="button button3">Reset</button>
<div id="space"></div>
<div id="space"></div>
<div id="results"> Cats - 0 | Dogs - 0 </div>
</form>
</div>
</div>
</body>
<!doctype html>
<html lang="">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1">
<link rel="icon" href="/favicon.ico">
<title>store-front</title>
<script defer="defer" src="/js/chunk-vendors.df69ae47.js"></script>
<script defer="defer" src="/js/app.7e8cfbb2.js"></script>
<link href="/css/app.a5dc49f6.css" rel="stylesheet">
</head>
<body>
<div id="app"></div>
</body>
</html>
```

## Add HTTPS termination to custom domain

At this point in the tutorial you have an AKS web app with NGINX as the Ingress controller and a custom domain you can use to access your application. The next step is to add an SSL certificate to the domain so that users can reach your application securely via HTTPS.

## Set Up Cert Manager

In order to add HTTPS we are going to use Cert Manager. Cert Manager is an open source tool used to obtain and manage SSL certificate for Kubernetes deployments. Cert Manager will obtain certificates from a variety of Issuers, both popular public Issuers as well as private Issuers, and ensure the certificates are valid and up-to-date, and will attempt to renew certificates at a configured time before expiry.

1. In order to install cert-manager, we must first create a namespace to run it in. This tutorial will install cert-manager into the cert-manager namespace. It is possible to run cert-manager in a different namespace, although you will need to make modifications to the deployment manifests.

```bash
kubectl create namespace cert-manager
```

2. We can now install cert-manager. All resources are included in a single YAML manifest file. This can be installed by running the following:

```bash
kubectl apply -f https://github.com/jetstack/cert-manager/releases/download/v1.7.0/cert-manager.crds.yaml
```

3. Add the certmanager.k8s.io/disable-validation: "true" label to the cert-manager namespace by running the following. This will allow the system resources that cert-manager requires to bootstrap TLS to be created in its own namespace.

```bash
kubectl label namespace cert-manager certmanager.k8s.io/disable-validation=true
```

## Obtain certificate via Helm Charts

Helm is a Kubernetes deployment tool for automating creation, packaging, configuration, and deployment of applications and services to Kubernetes clusters.

Cert-manager provides Helm charts as a first-class method of installation on Kubernetes.

1. Add the Jetstack Helm repository

This repository is the only supported source of cert-manager charts. There are some other mirrors and copies across the internet, but those are entirely unofficial and could present a security risk.

```bash
helm repo add jetstack https://charts.jetstack.io
```

2. Update local Helm Chart repository cache

```bash
helm repo update
```

3. Install Cert-Manager addon via helm by running the following:

```bash
helm install cert-manager jetstack/cert-manager --namespace cert-manager --version v1.7.0
```

4. Apply Certificate Issuer YAML File

ClusterIssuers are Kubernetes resources that represent certificate authorities (CAs) that are able to generate signed certificates by honoring certificate signing requests. All cert-manager certificates require a referenced issuer that is in a ready condition to attempt to honor the request.
The issuer we are using can be found in the `cluster-issuer-prod.yml file`

```bash
cluster_issuer_variables=$(<cluster-issuer-prod.yml)
echo "${cluster_issuer_variables//\$SSL_EMAIL_ADDRESS/$SSL_EMAIL_ADDRESS}" | kubectl apply -f -
```

5. Upate Voting App Application to use Cert-Manager to obtain an SSL Certificate.

The full YAML file can be found in `azure-vote-nginx-ssl.yml`

```bash
azure_vote_nginx_ssl_variables=$(<azure-vote-nginx-ssl.yml)
echo "${azure_vote_nginx_ssl_variables//\$FQDN/$FQDN}" | kubectl apply -f -
```

<!--## Validate application is working

Wait for the SSL certificate to issue. The following command will query the
status of the SSL certificate for 3 minutes. In rare occasions it may take up to
15 minutes for Lets Encrypt to issue a successful challenge and
the ready state to be 'True'

```bash
runtime="10 minute"; endtime=$(date -ud "$runtime" +%s); while [[ $(date -u +%s) -le $endtime ]]; do STATUS=$(kubectl get certificate --output jsonpath={..status.conditions[0].status}); echo $STATUS; if [ "$STATUS" = 'True' ]; then break; else sleep 10; fi; done
```

Validate SSL certificate is True by running the follow command:

```bash
kubectl get certificate --output jsonpath={..status.conditions[0].status}
```

Results:

<!-- expected_similarity=0.3 -->
<!--
```ASCII
True
```
-->

## Browse your AKS Deployment Secured via HTTPS

Run the following command to get the HTTPS endpoint for your application:

> [!Note]
> It often takes 2-3 minutes for the SSL certificate to propogate and the site to be reachable via HTTPS.

```bash
runtime="5 minute";
endtime=$(date -ud "$runtime" +%s);
while [[ $(date -u +%s) -le $endtime ]]; do
STATUS=$(kubectl get svc --namespace=ingress-nginx ingress-nginx-controller -o jsonpath='{.status.loadBalancer.ingress[0].ip}');
echo $STATUS;
if [ "$STATUS" == "$MY_STATIC_IP" ]; then
break;
else
sleep 10;
fi;
done
```

```bash
echo "You can now visit your web server at https://$FQDN"
echo "You can now visit your web server at $IP_ADDRESS"
```

## Next Steps
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should tell the user to visit the site at the end once it's ready. Like:
 

echo "You can now visit your web server at $IP_ADDRESS"

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

Expand Down
Loading