Deploy on Azure Kubernetes Service

Language: English

This guide walks you through deploying the ActivityInfo Self-managed Server on Azure Kubernetes Service (AKS), backed by a Premium SSD v2 managed disk. It is intended for IT professionals who are familiar with Kubernetes and Microsoft Azure.

Use this deployment when the network latency of a shared file system limits database performance. See Deploy as an Azure Web App for a simpler option that uses Azure Files.

Before you start

The ActivityInfo Self-managed Server stores its data in an SQLite database. This shapes the whole deployment:

  • Run a single replica. The server is designed to scale vertically, not horizontally: to support more concurrent users, give the pod more CPU cores and memory rather than adding replicas.
  • Use durable block storage. A Premium SSD v2 managed disk gives near-local-disk latency with configurable IOPS and throughput. Because it is a network-attached managed disk, its data is replicated in the storage backend and survives the loss of a node: the disk detaches and reattaches to the node where the pod is rescheduled.

This tutorial ends by reaching the server from your own machine with port forwarding. Making the server available to users over HTTPS is covered by the links at the end of this guide.

Prerequisites

Install the Azure CLI and kubectl, then sign in:

az login

Set variables

RESOURCE_GROUP=activityinfo-rg
LOCATION=westeurope
CLUSTER=activityinfo-aks

Create a cluster

Create a resource group and an AKS cluster. The Azure Disk CSI driver, which provisions managed disks, is installed by default. Premium SSD v2 disks are zonal, so the node pool must run in an availability zone; --zones 1 places it in zone 1. One node is enough, since ActivityInfo runs as a single pod. Add a second node in the same zone if you want the pod to reschedule sooner during a node failure or upgrade.

az group create --name $RESOURCE_GROUP --location $LOCATION

az aks create \
  --resource-group $RESOURCE_GROUP \
  --name $CLUSTER \
  --node-vm-size Standard_D4s_v5 \
  --node-count 1 \
  --zones 1 \
  --generate-ssh-keys

Connect kubectl to the new cluster:

az aks get-credentials --resource-group $RESOURCE_GROUP --name $CLUSTER

Create a storage class

The built-in storage classes use older disk types. Define a storage class for Premium SSD v2. Save the following to storageclass.yaml:

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: activityinfo-premium-v2
provisioner: disk.csi.azure.com
parameters:
  skuName: PremiumV2_LRS
  cachingMode: None
  DiskIOPSReadWrite: "3000"
  DiskMBpsReadWrite: "125"
reclaimPolicy: Retain
allowVolumeExpansion: true
volumeBindingMode: WaitForFirstConsumer

WaitForFirstConsumer creates the disk in the same zone as the pod that uses it. reclaimPolicy: Retain keeps the disk if the claim is ever deleted, so the database is not lost by accident. Raise DiskIOPSReadWrite and DiskMBpsReadWrite above the free baseline of 3000 IOPS and 125 MB/s if your workload needs more. Apply it:

kubectl apply -f storageclass.yaml

Deploy ActivityInfo

Save the following to activityinfo.yaml. It defines a single-replica StatefulSet that requests a Premium SSD v2 disk from the storage class and mounts it at /data. The fsGroup in the security context makes the mounted disk writable by the container, which runs as a non-root user. A Service exposes the container on port 80 within the cluster.

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: activityinfo
spec:
  serviceName: activityinfo
  replicas: 1
  selector:
    matchLabels:
      app: activityinfo
  template:
    metadata:
      labels:
        app: activityinfo
    spec:
      securityContext:
        fsGroup: 1000
      containers:
        - name: activityinfo
          image: activityinfo/activityinfo:5.0.0
          ports:
            - containerPort: 8081
          env:
            - name: ACTIVITYINFO_DATA_DATA_DIRECTORY
              value: /data
          volumeMounts:
            - name: data
              mountPath: /data
  volumeClaimTemplates:
    - metadata:
        name: data
      spec:
        accessModes:
          - ReadWriteOnce
        storageClassName: activityinfo-premium-v2
        resources:
          requests:
            storage: 100Gi
---
apiVersion: v1
kind: Service
metadata:
  name: activityinfo
spec:
  selector:
    app: activityinfo
  ports:
    - port: 80
      targetPort: 8081

Apply the manifest:

kubectl apply -f activityinfo.yaml

Access the server

Wait for the pod to be ready, then forward a local port to the Service:

kubectl rollout status statefulset/activityinfo
kubectl port-forward service/activityinfo 8081:80

While the command runs, open http://localhost:8081, where you are prompted to create the first administrator user account. Press Ctrl+C to stop forwarding.

Expose the server to the Internet

Port forwarding only reaches the server from your own machine. To make ActivityInfo available to users, expose the Service and serve it over HTTPS. ActivityInfo can obtain and renew its own certificate through Let's Encrypt, or you can terminate TLS at an ingress controller. The following resources describe the options:

Back up the database

The managed disk survives node loss, but it does not protect against disaster, such as a data center fire. Take regular volume snapshots of the disk, or copy the contents of /data to durable storage such as Azure Blob Storage on a schedule. Keep backups outside the cluster so you can restore after a total cluster loss.

Next steps

Follow the Configuration guide to set up Email delivery and Single Sign-On through the web-based interface.

Next item
Other platforms