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:
- Automated SSL configuration — ActivityInfo's built-in Let's Encrypt support.
- HTTPS proxy mode — when TLS is terminated by an ingress controller or reverse proxy.
- Use a public load balancer in AKS — expose the service with a public IP.
- Managed NGINX ingress in AKS — the application routing add-on.
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.