This is a “walkthrough cheatsheet” from my initial experimenting with AKS (Azure Kubernetes Service). Everything here can be run using Azure’s Free Account trial.
This article is written from the point of view of someone completely new to both Azure Cloud and Kubernetes. I do recommend at least basic Docker knowledge and some experience with other cloud service provider(s).
I haven’t been an avid Kubernetes enthusiast mostly because I never had the need to learn it’s ways, until now. If interested in a Docker Swarm proof of concept article feel free to check my previous post. However, I have to admit Kubernetes and most notably AKS have been lovely to work with so far.
If you’re interested in learning Kubernetes “the right way” I recommend the Kubernetes: Up and Running book. This is just a “walkthrough guide” on how to deploy a Ruby on Rails project on AKS. Swapping the Rails specific steps for a different platform should be straightforward too.
AKS setup
Basic commands to deploy & manage a cluster with the Azure CLI
# Authenticate the CLI
$ az login
# Create resource group:
$ az group create -n <resource-group> -l eastus
# List available Kubernetes versions
$ az aks get-versions -l eastus -o table
# Create the cluster
$ az aks create -n k8s-dev -g <resource-group> -c 1 -k 1.11.2
# Get credentials for `kubectl`
$ az aks get-credentials -n k8s-dev -g <resource-group>
# Run `kubectl` commands on the cluster
$ kubectl get nodes
$ kubectl get pods --all-namespaces
# Proxy kubernetes dashboard
$ az aks browse -n k8s-dev -g <resource-group>
# Cleanup
$ az aks delete -n k8s-dev -g <resource-group>
$ az group delete -n <resource-group>
Rails 5.2+ Secrets
More info about the new secrets management in this Engine Yard article
# Edit rails secrets & make sure `config/master.key` is not in version control
# i.e. add to `.gitignore`
$ rails credentials:edit
# Add the master key as a secret to k8s
$ kubectl create secret generic rails-master-key --from-literal=rails-master-key=<secret>
# Add the ConfigMap that contains non sensitive variables
# (see the following sample ConfigMap YAML file)
$ kubectl create -f <configmap.yml>
Sample ConfigMap YAML definition
apiVersion: v1
kind: ConfigMap
metadata:
name: rails-app-config
namespace: default
data:
RAILS_ENV: production
ACR (Azure Container Registry)
# Create a Container Registry
$ az acr -n <container-registry-name> -g <resource-group> --sku Basic
# List the URL prefix to tag the Docker images
$ az acr list -g <resource-group> --query "[].{acrLoginServer:loginServer}" --output table
# Login to the Container Registry
$ az acr login -n <container-registry-name>
ACR access to AKS
Execute the following script (with valid variables) to give AKS the permission to pull images from ACR
#!/bin/bash
AKS_RESOURCE_GROUP=<aks-resource-group>
AKS_CLUSTER_NAME=<cluster-name>
ACR_RESOURCE_GROUP=<acr-resource-group>
ACR_NAME=<registry-name>
# Get the id of the service principal configured for AKS
CLIENT_ID=$(az aks show --resource-group $AKS_RESOURCE_GROUP --name $AKS_CLUSTER_NAME --query "servicePrincipalProfile.clientId" --output tsv)
# Get the ACR registry resource id
ACR_ID=$(az acr show --name $ACR_NAME --resource-group $ACR_RESOURCE_GROUP --query "id" --output tsv)
# Create role assignment
az role assignment create --assignee $CLIENT_ID --role Reader --scope $ACR_ID
Deployment
Sample deployment YAML
# deployment.yml
apiVersion: apps/v1
kind: Deployment
metadata:
name: rails-app
labels:
app: rails-app
spec:
replicas: 2
selector:
matchLabels:
app: rails-app
strategy:
rollingUpdate:
maxSurge: 1
maxUnavailable: 1
template:
metadata:
labels:
app: rails-app
spec:
containers:
- image: <registry-url>/rails-app:v2
imagePullPolicy: Always
name: rails
ports:
- containerPort: 3000
env:
- name: RAILS_ENV
valueFrom:
configMapKeyRef:
name: rails-app-config
key: RAILS_ENV
dnsPolicy: ClusterFirst
restartPolicy: Always
volumes:
- name: secrets
secret:
secretName: rails-master-key
items:
- key: rails-master-key
path: config/master.key
Then deploy to the AKS cluster
# Create the deployment
$ kubectl create -f deployment.yml
# Expose using a LoadBalancer
$ kubectl expose deployment rails-app --type=LoadBalancer --port=80 --target-port=3000
# Wait for the Load Balancer's public IP Address to be assigned
$ kubectl get svc -w
Deploy supporting services using Helm
Local development with RabbitMQ made easy:
# This is the Bitnami Docker image
# We're using the default username `user` with a custom password
$ docker run -it --rm -e "RABBITMQ_PASSWORD=pass123" --name rabbitmq -p 15672:15672 -p 5672:5672 bitnami/rabbitmq:latest
The RabbitMQ UI website will be available on localhost
with port 15672
. For Ruby development using the Bunny gem to connect to the running RabbitMQ container you can use the following conneciton string:
# Sample connection string when working locally.
# Production grade code should probably connect to ENV variable or encrypted secret.
connection = Bunny.new("amqp://user:pass123@localhost:5672?automatically_recover=false")
To install RabbitMQ on AKS
$ helm init
$ helm install stable/rabbitmq --name=rabbitmq-dev --set rabbitmq.username=guest --set rabbitmq.password=guest
Conclusions
It’s very worth noting a kubectl Cheat Sheet on the official Kubernetes website, for bookmarking purposes.
This article hopefully exposed an easy way to get services running on AKS and have them available to the internet. However, there’s plenty of configuration left to be setup before calling it a production grade cluster.
I’m now familiarizing myself with the ins and outs of ingress controllers and RBAC. Hopefully I’ll write a future article about those too. Until then, Pura Vida.