In the previous post we deployed Miniblog.Core to Azure Container Instances using a storage account as volume. In this post we will deploy to Azure Managed Kubernetes.

What is Azure Managed Kubernetes?

AKS for short is the second version of Kubernetes Cluster in Azure. The first version Azure Container Services (ACS) allows you to create a cluster in Azure. However, all cluster management is in your hands. Moreover, you pay for the cluster master node.

With AKS Azure you get a managed cluster. Using the cli you can scale applications, add more nodes, upgrade to newer version of Kubernetes.

How to start? First step is to enabled managed Kubernetes on your Azure subscription

az provider register -n Microsoft.ContainerService

It can take a few seconds until the registration is complete. Check for completion with the following command:

$ az provider show -n Microsoft.ContainerService -o table
Namespace RegistrationState
— — — — — — — — — — — — — — — — — — — — — — -Microsoft.ContainerService Registered

In order to keep the cluster logically isolated from my previous deployments I create a new resource group. You don’t have to. Azure will create a separated resource group automatically for the managed cluster specific resources (nodes, load balancer, vnet, public IPs, etc).

az group create -n miniblogcore -l westeurope

Next we create our cluster. For the purpose of simplicity I will create a single node cluster. If you already have an managed cluster and wish to reuse it you can skip this step (we will be isolating the deployment in a own namespace). For all options on creating a cluster with the cli refer to the documentation https://docs.microsoft.com/en-us/cli/azure/aks?view=azure-cli-latest#az_aks_create

az aks create -g miniblogcore -n miniblogcore-aks \
--node-count 1 \
--node-vm-size Standard_B1s \
--kubernetes-version 1.8.2 \
--generate-ssh-keys

The command above tells Azure to create a cluster named “miniblogcore-aks” in resource group “miniblogcore”. It should have 1 node (not recommended for anything serious) with size “Standard_B1s (cheapeast one, also not recommended for anything intensive, see all options here) with Kubernetes version 1.8.2 (latest possible at the time of writing). The parameter “ — generate-ssh-keys” tells Azure to create the SSH private and public key files.

It takes around 10 minutes to create the cluster, and it does not always work. If it does not work, try again. In case it continues to fail you can look at the activity log of the resource group in Azure Portal to get more information about the problem.

az aks install-cli

Next add the managed cluster configuration to your kubectl configuration. The command below will add the context and switch to it.

az aks get-credentials -g miniblogcore -n miniblogcore-aks

To test the connection try to get the Kubernetes nodes with the command below.

kubectl get nodes

There a few ways a volume can be mounted to a Kubernetes deployment. The one I am going to use requires us to create an storage account with a share then give the connection information to Kubernetes.

Creating the Storage account

Setup Azure disk for Persistent Volume. For a complete example check the documentation https://docs.microsoft.com/en-us/azure/aks/azure-files

We basically need to do the same we did for container instances. Create a storage account and a share. The difference is that we will be more secure in how we tell Kubernetes which account and key to use through secrets (https://kubernetes.io/docs/concepts/configuration/secret/).

az storage account create -n miniblogstorage -g miniblogcore -l westeurope --sku Standard_LRS

Find the connection string:

az storage account show-connection-string -n miniblogstorage -g miniblogcore -o tsv

Which returns something like this:

DefaultEndpointsProtocol=https;EndpointSuffix=core.windows.net;AccountName=miniblogstorage;AccountKey=xxxxxxx

Create the storage share:

az storage share create -n miniblogstorageshare \
--connection-string "{connection string}”

Retrieve the storage key:

az storage account keys list -g miniblogcore -n miniblogstorage --query "[0].value" -o tsv

Secrets in Kubernetes are ways to store sensitive information (connection strings, passwords, keys). Secrets can be referenced during the deployment by associating their values to environment variables or other deployment parameters.

As any other object type, secrets can be created with yaml files, however the values must be encoded in base64 format. If you are running a Mac or Linux you can use “echo” to encode to base64. If you are running on Windows you can use this online tool https://www.base64encode.org/

$ echo -n miniblogstorage | base64$ echo -n {enter the storage key} | base64

All set, now we can deploy the application. This is the complete deployment yaml:

In the container section we define that a volume with name miniblob01-pv should be mapped to /app/data.

In the volume definition we tell Kubernetes how to resolve the volume. Volumes are an abstraction to the file system and there are many possible implementations. In our case we are using the Azure File plug-in and the connection information can be found in the secret with name ‘storage-secret’ (defined in a section previously). We then tell Azure File that the storage share name is ‘miniblogstorageshare’ and that the volume is read/write.

Copy the contents from the file above, replace the missing values and save as “deployment-aks.yaml”. Apply the deployment with kubectl:

kubectl apply -f deployment-aks.yaml

The deployment should work, but since we asked for a public IP address for our service (type: LoadBalancer) it can take a few minutes until Azure provides one. See the status of the services with the command below:

$ kubectl get services --namespace miniblog01
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
web LoadBalancer 10.0.76.71 <pending> 80:30421/TCP 26s

To be able to test before the public IP is available we can forward the calls to the pod we want. First find out the pod and then forward the calls. However we need to wait until the container has been created. The -w flag will tell kubectl that we want to keep watching for changes. CTRL+C will stop it.

$ kubectl get pod --namespace miniblog01 -w
NAME READY STATUS RESTARTS AGE
web-776d9d74cc-cqh5t 0/1 ContainerCreating 0 1m

Once the pod is available copy the pod name and “port-forward” (local 8002 to container 80) it:

kubectl port-forward web-776d9d74cc-27n8x 8002:80 --namespace miniblog01

Opening your browser on http://localhost:8002 should show the following:

Port forwarded Miniblog.Core running on AKS

Let’s do the same exercise we did previously to ensure files are stored safely in our storage account. Sign-in (aksadmin/demo) and create a test post. After, ensure that the file was created in the storage account we provided.

$ az storage file list --share-name miniblogstorageshare/Posts \
--connection-string "storage connection string" -o table
Name Content Length Type Last Modified
---------------------- ---------------- ------ ---------------
636490172890722780.xml 365 file

Clearing up after testing

If you created the resources only for testing purposes you can delete the storage and the managed cluster by deleting the original resource group. Do that only if the resource group contains only your test resources!

az group delete -n miniblogcore

Next remove from your kubectl the cluster information

kubectl config delete-context miniblogcore-aks

Hope that at the end of this series you got a bit familiar in adding volumes to a docker image locally, using Azure Container Instances and Azure Managed Kubernetes. The same concept can be used in any Kubernetes provider with a few changes.

Francisco Beltrao

Written by

Software Engineer @Microsoft. Opinions are my own.

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade