The following is a bash script with a set of Azure CLI commands to build an cost efficient Azure Kubernetes Environment to host a public facing web application.
This is suitable for beginners or a simple development environment for your project. And demonstrates my recommended setup with both Azure cloud resources and the Open Source Software deployed into the Kubernetes cluster for a public facing web application.
This script consists of Azure resources and OSS software.
- Azure Container Registry
- Azure Virtual Network and subnet
- Azure Kubernetes Service
- Kubernetes Dashboard UI for cluster resource administration
- NGINX Ingress Controller to expose public traffic into the cluster and application
- Cert-Manager for Https
- AKS Hello World Demo application
The latest script can be found in my Github Repo:
https://github.com/RoyKimYYZ/linux-scripts/blob/master/setup-aks-vnet-acr.sh
To get a glance of a version at the time of this post, you can see:
#!/bin/bash # setup-aks-vnet-acr.sh az account show -o table az account list -o table az account set -s 'Visual Studio Enterprise' az subscription -n 'Visual Studio Enterprise' # AKS rgName='linux-demos' #'aks-solution' aksName='rkaks-vsent' location='canadacentral' # create AKS cluster #################### az group create -l $location -n $rgName #--subscription $appSubId # Azure Container Registry # set this to the name of your Azure Container Registry. It must be globally unique acrName=rkimacrVSEnt #name is global # Note: acr in enterprise rg in Enterprise subscription az acr create --name $acrName --resource-group $rgName -l $location --sku Basic acrResourceId=$(az acr show --name $acrName --resource-group $rgName --query "id" --output tsv) az acr update -n $acrName --admin-enabled true acr_userName=$(az acr credential show -n $acrName --query="username" -o tsv) acr_pwd=$(az acr credential show -n $acrName --query="passwords[0].value" -o tsv) echo $acr_userName $acr_pwd # create vnet and subnet az network vnet create -g $rgName -n aksVnet -l $location --address-prefix 10.1.0.0/24 \ --subnet-name akssubnet --subnet-prefix 10.1.0.0/25 subnetId=$(az network vnet subnet show --resource-group $rgName --vnet-name aksVnet --name akssubnet --query id -o tsv) echo $subnetId # existing subnets az network vnet subnet list --resource-group $rgName --vnet-name aksVnet -o tsv subnetId=$(az network vnet subnet show --resource-group $rgName --vnet-name aksVnet --name akssubnet --query id -o tsv) # VM SKUS az vm list-skus --location $location -o table # versions az aks get-versions --location $location --output table az aks create --resource-group $rgName --name $aksName \ --kubernetes-version 1.19.1 \ --location $location \ --node-vm-size Standard_D2_v3 \ --vm-set-type VirtualMachineScaleSets \ --node-osdisk-size 30 \ --node-count 1 --max-pods 30 \ --network-plugin azure \ --vnet-subnet-id $subnetId \ --load-balancer-sku Basic \ --generate-ssh-keys \ --enable-cluster-autoscaler --min-count 1 --max-count 5 \ --enable-aad \ --enable-managed-identity \ --attach-acr $acrResourceId #--enable-addons monitoring --workspace-resource-id $logWorkspaceResourceId # Side Notes # Standard_D2_v3 2vCpu 8GB Ram, not premium storage # Networking config options: --service-cidr 10.2.0.0/24 --dns-service-ip 10.2.0.10 --docker-bridge-address 172.17.0.1/16 \ az aks get-credentials -n $aksName -g $rgName az aks show -n $aksName -g $rgName # Kubernetes Dashboard kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/v2.0.0/aio/deploy/recommended.yaml kubectl delete clusterrolebinding kubernetes-dashboard kubectl create clusterrolebinding kubernetes-dashboard --clusterrole=cluster-admin --serviceaccount=kube-system:kubernetes-dashboard --insecure-skip-tls-verify kubectl create clusterrolebinding serviceaccounts-cluster-admin \ --clusterrole=cluster-admin --group=system:serviceaccounts kubectl get secrets -n kube-system | grep dashboard-token kubectl get secrets -n kube-system -o json TOKEN=$(kubectl get secrets -o jsonpath="{.items[?(@.metadata.annotations['kubernetes\.io/service-account\.name']=='default')].data.token}"|base64 --decode) echo $TOKEN # | xclip --selection clipboard -o curl http://localhost:8001/api/v1/namespaces/kube-system/services/https:kubernetes-dashboard:/proxy/#/login kubectl get pods -n kubernetes-dashboard -o jsonpath | grep kubernetes-dashboard.* kubectl port-forward $(kubectl get pods -n kubernetes-dashboard -o name | grep kubernetes) 8443:8443 # Create a namespace for your ingress resources kubectl create namespace ingress-basic # Add the official stable repo helm repo update helm repo add stable https://kubernetes-charts.storage.googleapis.com/ # Use Helm to deploy an NGINX ingress controller helm install nginx stable/nginx-ingress \ --namespace ingress-basic \ --set controller.replicaCount=2 \ --set controller.nodeSelector."beta\.kubernetes\.io/os"=linux \ --set defaultBackend.nodeSelector."beta\.kubernetes\.io/os"=linux kubectl get service -l app=nginx-ingress --namespace ingress-basic kubectl get service nginx-nginx-ingress-controller --namespace ingress-basic # Public IP address of your ingress controller # Look up in resource group in Azure Portal publicIP='<PUBLIC IP>' ## Add an A record to your DNS zone ## # Set A record to GoDaddy DNS # OR # Name to associate with public IP address DNSNAME="demo-aks-ingress" # Get the resource-id of the public ip PUBLICIPID=$(az network public-ip list --query "[?ipAddress!=null]|[?contains(ipAddress, '$IP')].[id]" --output tsv) # Update public ip address with DNS name az network public-ip update --ids $PUBLICIPID --dns-name $DNSNAME # Display the FQDN az network public-ip show --ids $PUBLICIPID --query "[dnsSettings.fqdn]" --output tsv ## Install cert-manager # Install the CustomResourceDefinition resources separately kubectl apply --validate=false -f https://raw.githubusercontent.com/jetstack/cert-manager/release-0.13/deploy/manifests/00-crds.yaml # Label the ingress-basic namespace to disable resource validation kubectl label namespace ingress-basic cert-manager.io/disable-validation=true # Add the Jetstack Helm repository helm repo add jetstack https://charts.jetstack.io # Update your local Helm chart repository cache helm repo update # Install the cert-manager Helm chart helm install \ cert-manager \ --namespace ingress-basic \ --version v0.13.0 \ jetstack/cert-manager echo "apiVersion: cert-manager.io/v1alpha2 kind: ClusterIssuer metadata: name: letsencrypt spec: acme: server: https://acme-v02.api.letsencrypt.org/directory email: abc@outlook.com privateKeySecretRef: name: letsencrypt solvers: - http01: ingress: class: nginx" | kubectl apply -f - # Demo application helm repo add azure-samples https://azure-samples.github.io/helm-charts/ akshelloworldnamespace=aks-helloworld kubectl create namespace $akshelloworldnamespace helm install aks-helloworld azure-samples/aks-helloworld --namespace $akshelloworldnamespace helm install aks-helloworld-two azure-samples/aks-helloworld \ --namespace $akshelloworldnamespace \ --set title="AKS Ingress Demo" \ --set serviceName="aks-helloworld-two" AppDnsName=akshelloworld.rkim.ca #Your DNS url for your app. echo "apiVersion: extensions/v1beta1 kind: Ingress metadata: name: hello-world-ingress annotations: kubernetes.io/ingress.class: nginx nginx.ingress.kubernetes.io/rewrite-target: / cert-manager.io/cluster-issuer: letsencrypt spec: tls: - hosts: - $AppDnsName secretName: tls-secret rules: - host: $AppDnsName http: paths: - backend: serviceName: aks-helloworld servicePort: 80 path: / - backend: serviceName: aks-helloworld-two servicePort: 80 path: /hello-world-two(/|$)(.*) --- # apiVersion: extensions/v1beta1 # kind: Ingress # metadata: # name: hello-world-ingress-static # annotations: # kubernetes.io/ingress.class: nginx # nginx.ingress.kubernetes.io/rewrite-target: /static/$2 # cert-manager.io/cluster-issuer: letsencrypt # spec: # tls: # - hosts: # - $AppDnsName # secretName: tls-secret # rules: # - host: $AppDnsName # http: # paths: # - backend: # serviceName: aks-helloworld # servicePort: 80 # path: /static(/|$)(.*) " | kubectl apply --namespace $akshelloworldnamespace -f - --- kubectl apply -f akshelloworld-hpa.yaml -n $akshelloworldnamespace #need hpa in same namespace as deployment or else <unknown> target # Verify certificate kubectl get certificate --namespace ingress-basic kubectl get certificate --namespace $akshelloworldnamespace kubectl describe certificate tls-secret --namespace $akshelloworldnamespace kubectl get ingress -n ingress-basic kubectl get ingress -n $akshelloworldnamespace kubectl get ingress -n $akshelloworldnamespace kubectl describe ingress -n $akshelloworldnamespace kubectl describe ingress hello-world-ingress -n $akshelloworldnamespace kubectl describe ingress hello-world-ingress-static -n $akshelloworldnamespace kubectl get pods -n ingress-basic # kubectl logs -n ingress-basic nginx-nginx-ingress-controller-74bf9bd9f5-tzs7k # kubectl logs -n ingress-basic nginx-nginx-ingress-controller-74bf9bd9f5-4vcc9
Hope this script helps on your journey of learning and applying Azure and Kubernetes for your projects.