Azure
There are different ways to deploy an application like Katalogue on Azure. This section covers two different methods that have been tested in production:
- Individual Azure Components
- Azure Kubernetes Service (AKS)
The Katalogue source code is assumed to be hosted in a git repo. The examples covered here uses GitHub, but the overall process is identical if e.g. Gitlab is used. However, there will be minor differences in setting up workflows etc. The goal is a completely automated CI/CD setup.
The high-level flow, regardless of method, is:
GitHub (Official Katalogue repo hosted by Kayenta in GitHub)
→ GitHub (Or e.g. GitLab. Copy of the Katalogue source code hosted in your organization’s private repo)
→ GitHub Actions (Or e.g. GitLab CI. Workflow that builds images. Trigger on e.g. merge to main branch)
→ Azure Container Registry (ACR) (or other container registry. Holds the built images)
→ Azure App Services or Azure Kubernetes Service (AKS) (pulls images from ACR and hosts the Katalogue services)
Chosing Method
Section titled “Chosing Method”Individual Azure Components
Section titled “Individual Azure Components”The Katalogue services are deployed as individual Azure components (PaaS-style).
- Database (
db): Azure Database for PostgreSQL Flexible Server (managed Postgres). - Backend (
api): Azure App Service (Web App) running the API/backend service. - Frontend (
spa): Azure App Service (Web App) serving the UI.
Required Azure resources:
- Resource Group - to group the resources below.
- App Service for frontend (
spaservice). - App Service for backend (
apiservice). - Azure Database for PostgreSQL flexible server (
dbservice). - Key Vault to store secrets used by the App Services.
- Container Registry (ACR) if containers are hosted on Azure. Can be any other registry outside of Azure as well.
- Entra Id for service principals/app registrations.
- Virtual Network, Private Endpoints, Network Security Groups etc for optional network config.
How It Works
Section titled “How It Works”- You build and deploy the frontend/backend as App Service apps (CI/CD, deployment slots, autoscale).
- App Services talk to Postgres via connection strings + Optional VNet integration/private endpoints.
- Azure handles most of the OS/runtime patching, basic scaling, TLS, certs, and a lot of the “platform” concerns.
Best Fit
Section titled “Best Fit”This method is simplest to get started with, but requires more fiddling with details (like networking, permissions, environment variables etc) between services and will probably be a higher maintenance burden over time as there are more components involved. This solution is optimal for organizations with moderate experience from Docker and Azure, no experience from Kubernetes and just want to get started using Katalogue.
To summarize, best fit for:
- Organizations running a small Katalogue installation.
- Organizations that want maximum managed experience and minimum cluster ops.
Azure Kubernetes Service (AKS)
Section titled “Azure Kubernetes Service (AKS)”The Katalogue services are deployed to Azure Kubernetes Service (AKS) via Helm.
- AKS runs your frontend (
spa) and backend (api) as Kubernetes workloads (Deployments, Services, Ingress). - You deploy using Helm charts (templated Kubernetes manifests). Kayenta supplies good defaults but you might need to tweak them to fit your organization.
- The Database (
db) is often still managed Postgres (recommended), but could also be in-cluster (usually discouraged for production).
Required Azure resources:
- Resource Group to group the resources below
- Azure Kubernetes Service (AKS) to host the Katalogue services (
spa,apiand optionallydbservices) - Azure Database for PostgreSQL flexible server optional if the
dbservice is not hosted as part of the Kubernetes cluster. (db service) - Key Vault to store secrets used by the App Services
- Container Registry (ACR) if containers are hosted on Azure. Can be any other registry outside of Azure as well.
- Entra Id for service principals/app registrations
How It Works
Section titled “How It Works”- CI builds container images, pushes to a registry (often ACR), then Helm upgrades/releases to AKS.
- You manage Kubernetes concepts (with good defaults provided by Kayenta): namespaces, ingress controllers, resource requests/limits, pod autoscaling, node pools, secrets/config, upgrades.
Best Fit
Section titled “Best Fit”This method requires a running Kubernetes cluster and might be a bit more techically challenging to setup. If your organization has an infra team that manages a Kubernetes cluster, this is more of a “plug-and-play” solution where details related to the Katalogue services has already been taken care of by Kayenta.
To summarize, best fit for:
- Organizations running a large Katalogue installation with multiple environments and/or want fine-grained control (routing, scaling per component, sidecars, service mesh, advanced rollout strategies).
- Organizations already standardized on Kubernetes across environments/clouds.
- If you need standardization/portability to easily move to othe Kubernetes solutions.
Guide: Individual Azure Components
Section titled “Guide: Individual Azure Components”These are the minimal steps required to get this method to work. Your organization might require additional steps to be fully compliant.
Prerequisities
Section titled “Prerequisities”This section assumes you have the following in place before you begin:
- Permissions to access and create resources in Azure
- The Azure CLI installed on your computer
- An Azure subscription for Katalogue
- An Azure resource group for Katalogue
Create Azure Container Registry
Section titled “Create Azure Container Registry”Login to Azure
Section titled “Login to Azure”You must have the Azure CLI installed on your computer to run az commands:
az loginSet subscription for your session, where $SUBSCRIPTION_ID is the subscription id. Consult your infra team to get a subscription you can use (it is common to associate subscriptions with cost centers).
az account set --subscription "$SUBSCRIPTION_ID"Create Azure Container Registry
Section titled “Create Azure Container Registry”Set $ACR_NAME to something unique, e.g. “yourorgkatalogueenvacr”. Consult your infra team for organization-specific naming conventions.
RG="<your-resource-group>"az acr create -g "$RG" -n "$ACR_NAME" --sku BasicSave the loginServer from the output. It should be “yourorgkatalogueenvacr.azurecr.io” with the example above, or use the following command to get the login server:
ACR_LOGIN_SERVER=$(az acr show -n "$ACR_NAME" --query loginServer -o tsv)Create Azure Auth for GitHub Actions
Section titled “Create Azure Auth for GitHub Actions”Create an Entra Id App Registration
Section titled “Create an Entra Id App Registration”$APP_NAME is the name of the app registration, e.g. “katalogue-prod-gh-oidc-acr-push”. Consult your infra team for organization-specific naming conventions.
az ad app create --display-name "$APP_NAME"Create Service Principal
Section titled “Create Service Principal”A “service principal” in Azure is an Enterprise Application in Entra Id (often confused with Azure app registrations).
$APP_ID is the application id from the app registration.
APP_ID=$(az ad app list --display-name "$APP_NAME" --query "[0].appId" -o tsv)az ad sp create --id "$APP_ID"Assign Permissions
Section titled “Assign Permissions”Let the GitHub Action push images to ACR by granting “AcrPush” on the container registry scope.
ACR_ID=$(az acr show -n "$ACR_NAME" --query id -o tsv)az role assignment create --assignee "$APP_ID" --role "AcrPush" --scope "$ACR_ID"Add Federated Identity Credential
Section titled “Add Federated Identity Credential”This is to let GitHub exchange its OIDC token for Azure access tokens without handling secrets in GitHub. The example below is for the main branch, you might have to tweak the “name”, subject” and “description” if your GitHub workflow triggers on something else than push to the main branch.
# Fill these inGITHUB_ORG="<your-github-org-or-user>"GITHUB_REPO="<your-github-repo>"FIC_NAME="<federated-credential-name>" # e.g. github-katalogue-prod
az ad app federated-credential create --id "$APP_ID" --parameters @- <<EOF{ "name": "$FIC_NAME", "issuer": "https://token.actions.githubusercontent.com", "subject": "repo:${GITHUB_ORG}/${GITHUB_REPO}:ref:refs/heads/main", "description": "GitHub OIDC for main branch", "audiences": ["api://AzureADTokenExchange"]}EOFCreate GitHub Secrets
Section titled “Create GitHub Secrets”These are required for the example github action found in the Katalogue repo: .github/workflows/_build_and_push_acr.html. You might have to set other environment variables depending on your setup.
Set these in GitHub → Repo → Settings → Secrets and variables → Actions (or if you are using environments: GitHub → Repo → Settings → Environments → <your-environment> → Environment Secrets). Replace the variable names with the actual value.
# Get your tenant idTENANT_ID=$(az account show --query tenantId -o tsv)- AZURE_CLIENT_ID = $APP_ID
- AZURE_TENANT_ID = $TENANT_ID
- AZURE_SUBSCRIPTION_ID = $SUBSCRIPTION_ID
- ACR_NAME = $ACR_NAME
- ACR_LOGIN_SERVER = $ACR_LOGIN_SERVER
- APPSETTINGS_SPA = JSON config object for the Katalogue
spaservice, e.g:
{ "api": { "API_URL": "https://demo-api.katalogue.se/api" }}Create Azure App Services
Section titled “Create Azure App Services”Create Azure App Services
Section titled “Create Azure App Services”This guide does not cover the steps to create an azure app service in detail, consult the Azure documentation for this.
The names and domains shown here are examples. Consult your infra team for organization-specific naming conventions.
Create two app services in Azure portal:
- katalogue-prod-spa (frontend, hosts the
spaimage) - katalogue-prod-api (backend, hosts the
apiimage)
Assign Custom Domains
Section titled “Assign Custom Domains”This step is highly recommended but not mandatory. If custom domains are not configured, the app services will be hosted at <web_app_name>.azurewebsites.net.
Consult the Azure documentation for details on how to do this.
- katalogue-prod-spa: katalogue.your_company.com
- katalogue-prod-api: katalogue-api.your_company.com
These domains also need to be correctly configured with CNAME (subdomain) and TXT (asuid.subdomain) records in the DNS that hosts the domain. Consult your network team to set this up.
CI/CD Config
Section titled “CI/CD Config”The config shown here assume that ACR is used. The steps should be similar if you use another container registry (just set the ACR_NAME and ACR_LOGIN_SERVER accordingly in step 3), but you will probably have to set login credentials for that registry in the web app differently (step 1 and 2).
For each App Service:
# 0. Define variablesRG="<your-resource-group>"WEBAPP_NAME="<your-web-app-name>" # e.g. katalogue-prod-apiACR_NAME="<your-acr-name>" # e.g. yourorgkatalogueenvacr (not *.azurecr.io)ACR_LOGIN_SERVER="${ACR_NAME}.azurecr.io"
# 1. Enable identityaz webapp identity assign -g "$RG" -n "$WEBAPP_NAME"
# 2. Grant AcrPull on the ACRACR_ID="$(az acr show -n "$ACR_NAME" -g "$RG" --query id -o tsv)"PRINCIPAL_ID="$(az webapp identity show -g "$RG" -n "$WEBAPP_NAME" --query principalId -o tsv)"
az role assignment create \ --assignee-object-id "$PRINCIPAL_ID" \ --assignee-principal-type ServicePrincipal \ --role "AcrPull" \ --scope "$ACR_ID"
# 3. Point the App Service to the new ACR imageIMAGE_REPO="<image-repo-name>" # e.g. api or spaTAG="latest"
az webapp config container set \ -g "$RG" -n "$WEBAPP_NAME" \ --container-image-name "${ACR_LOGIN_SERVER}/${image_repo}:${tag}"
# 4. Useful verification commands (optional)
# Confirm identity is enabled and get principalIdaz webapp identity show -g "$RG" -n "$WEBAPP_NAME" -o json
# Confirm what image the app is configured to runaz webapp config container show -g "$RG" -n "$WEBAPP_NAME"Or, if you prefer the Azure Portal / GUI:
- Enable identity
- Settings → Identity → System assigned → On → Save
- Grant AcrPull on the ACR
-
ACR → Access control (IAM) → Add role assignment
-
Role: AcrPull
-
Assign access to: Managed identity
-
Select your Web App’s system-assigned identity
- Point the App Service to the new ACR image
-
Deployment → Deployment Center
-
Image source: Azure Container Registry
-
Registry: your ACR
-
Image:
api / spa / spa_feedback(whatever each app runs) -
Tag:
latest(or sha-xxxx, which is immutable and is recommended by Microsoft to prevent caching errors. However, latest seems to work.)
Environment Variables
Section titled “Environment Variables”For the api App Service only, create environment variables and set their values properly (App Service → Settings → Environment variables). It is recommended to not set secrets here. Instead, add the secrets to an Azure Key Vault and enter the keyvault reference as value here instead, e.g. @Microsoft.KeyVault(SecretUri=https://your-key-vault-name.vault.azure.net/secrets/ENCRYPTION-KEY). See Use Key Vault references as app settings in Azure App Service.
These are the minimum config variables required to get the Katalogue api service to start properly. You might have to set others for your specific deployment. See Configuration Parameters for meaning and all available parameters.
- API_ENDPOINT_BASE_URL
- COOKIE_SAME_SITE
- COOKIE_SECURE
- CORS_ORIGIN
- ENCRYPTION_KEY
- REPOSITORY_HOSTNAME
- REPOSITORY_PORT
- REPOSITORY_USERNAME
- REPOSITORY_PASSWORD
- REPOSITORY_USE_SSL
Assign Permissions
Section titled “Assign Permissions”This step is only required if you let your GitHub Action update the container image tag set in the web apps, as is done in the Katalogue repo GitHub Action example.
For each App Service in the Azure Portal, do this to give GitHub permission to update web app settings:
#Fill these inRG="<your-resource-group>"WEBAPP_NAME="<your-web-app-name>"
WEBAPP_ID=$(az webapp show -g "$RG" -n "$WEBAPP_NAME" --query id -o tsv)
az role assignment create --assignee "$APP_ID" --role "Contributor" --scope "$WEBAPP_ID"Create Azure Database for PostgreSQL Flexible Server
Section titled “Create Azure Database for PostgreSQL Flexible Server”Not covered here, consult the Azure documentation.
Guide: Azure Kubernetes Service (AKS)
Section titled “Guide: Azure Kubernetes Service (AKS)”TODO