Azure Citadel
  • Blogs

  • ARM
  • Azure Arc
    • Overview
    • Azure Arc-enabled Servers
      • Prereqs
      • Scenario
      • Hack Overview
      • Azure Landing Zone
      • Arc Pilot resource group
      • Azure Monitoring Agent
      • Additional policy assignments
      • Access your on prem VMs
      • Create onboarding scripts
      • Onboarding using scripts
      • Inventory
      • Monitoring
      • SSH
      • Windows Admin Center
      • Governance
      • Custom Script Extension
      • Key Vault Extension
      • Managed Identity
    • Azure Arc-enabled Kubernetes
      • Prereqs
      • Background
      • Deploy Cluster
      • Connect to Arc
      • Enable GitOps
      • Deploy Application
      • Enable Azure AD
      • Enforce Policy
      • Enable Monitoring
      • Enable Azure Defender
      • Enable Data Services
      • Enable Application Delivery
    • Useful Links
  • Azure CLI
    • Install
    • Get started
    • JMESPATH queries
    • Integrate with Bash
  • Azure Landing Zones
    • Prereqs
    • Day 1
      • Azure Baristas
      • Day 1 Challenge
    • Day 2
      • Example
      • Day 2 Challenge
    • Day 3
      • Day 3 Challenge
    • Useful Links
  • Azure Policy
    • Azure Policy Basics
      • Policy Basics in the Azure Portal
      • Creating Policy via the CLI
      • Deploy If Not Exists
      • Management Groups and Initiatives
    • Creating Custom Policies
      • Customer scenario
      • Policy Aliases
      • Determine the logic
      • Create the custom policy
      • Define, assign and test
  • Azure Stack HCI
    • Overview
    • Useful Links
    • Updates from Microsoft Ignite 2022
  • Marketplace
    • Introduction
      • Terminology
      • Offer Types
    • Partner Center
    • Offer Type
    • Publish a VM Offer HOL
      • Getting Started
      • Create VM Image
      • Test VM Image
      • VM Offer with SIG
      • VM Offer with SAS
      • Publish Offer
    • Other VM Resources
    • Publish a Solution Template HOL
      • Getting Started
      • Create ARM Template
      • Validate ARM Template
      • Create UI Definition
      • Package Assets
      • Publish Offer
    • Publish a Managed App HOL
      • Getting Started
      • Create ARM Template
      • Validate ARM Template
      • Create UI Definition
      • Package Assets
      • Publish Offer
    • Managed Apps with AKS HOL
    • Other Managed App Resources
    • SaaS Offer HOLs
    • SaaS Offer Video Series
      • Video 1 - SaaS Offer Overview
      • Video 2 - Purchasing a SaaS Offer
      • Video 3 - Purchasing a Private SaaS Plan
      • Video 4 - Publishing a SaaS Offer
      • Video 5 - Publishing a Private SaaS Plan
      • Video 6 - SaaS Offer Technical Overview
      • Video 7 - Azure AD Application Registrations
      • Video 8 - Using the SaaS Offer REST Fulfillment API
      • Video 9 - The SaaS Client Library for .NET
      • Video 10 - Building a Simple SaaS Landing Page in .NET
      • Video 11 - Building a Simple SaaS Publisher Portal in .NET
      • Video 12 - SaaS Webhook Overview
      • Video 13 - Implementing a Simple SaaS Webhook in .NET
      • Video 14 - Securing a Simple SaaS Webhook in .NET
      • Video 15 - SaaS Metered Billing Overview
      • Video 16 - The SaaS Metered Billing API with REST
  • Microsoft Fabric
    • Theory
    • Prereqs
    • Fabric Capacity
    • Set up a Remote State
    • Create a repo from a GitHub template
    • Configure an app reg for development
    • Initial Terraform workflow
    • Expanding your config
    • Configure a workload identity
    • GitHub Actions for Microsoft Fabric
    • GitLab pipeline for Microsoft Fabric
  • Packer & Ansible
    • Packer
    • Ansible
    • Dynamic Inventories
    • Playbooks & Roles
    • Custom Roles
    • Shared Image Gallery
  • Partner
    • Lighthouse and Partner Admin Link
      • Microsoft Cloud Partner Program
      • Combining Lighthouse and PAL
      • Minimal Lighthouse definition
      • Using service principals
      • Privileged Identity Management
    • Useful Links
  • REST API
    • REST API theory
    • Using az rest
  • Setup
  • Terraform
    • Fundamentals
      • Initialise
      • Format
      • Validate
      • Plan
      • Apply
      • Adding resources
      • Locals and outputs
      • Managing state
      • Importing resources
      • Destroy
    • Working Environments for Terraform
      • Cloud Shell
      • macOS
      • Windows with PowerShell
      • Windows with Ubuntu in WSL2
    • Using AzAPI
      • Using the REST API
      • azapi_resource
      • Removing azapi_resource
      • azapi_update_resource
      • Data sources and outputs
      • Removing azapi_update_resource
  • Virtual Machines
    • Azure Bastion with native tools & AAD
    • Managed Identities

  • About
  • Archive
  1. Home
  2. Azure Arc
  3. Azure Arc-enabled Kubernetes
  4. Azure Arc for Kubernetes - proctor guides
  5. Enable Application Delivery

Table of Contents

Enable Application Delivery

Run Azure PaaS services on your own compute.

LOCATION=westeurope
RESOURCE_GROUP="arc4k8s-$LOCATION"
APP_SVC_NAMESPACE="appservice-ns"
EXTENSION_NAME="arc4k8s-$LOCATION-appsvc"
CLUSTER_NAME="Arc-K3s-Demo"

# Create Log Analytics
WORKSPACE_NAME="ws-${RESOURCE_GROUP}"
az monitor log-analytics workspace create \
    --resource-group $RESOURCE_GROUP \
    --workspace-name $WORKSPACE_NAME

LA_WORKSPACE_ID=$(az monitor log-analytics workspace show \
    --resource-group $RESOURCE_GROUP \
    --workspace-name $WORKSPACE_NAME \
    --query customerId \
    --output tsv)
LA_WORKSPACE_ID_ENC=$(printf %s $LA_WORKSPACE_ID | base64) # Needed for the next step
LA_KEY=$(az monitor log-analytics workspace get-shared-keys \
    --resource-group $RESOURCE_GROUP \
    --workspace-name $WORKSPACE_NAME \
    --query primarySharedKey \
    --output tsv)
LA_KEY_ENC_SPACE=$(printf %s $LA_KEY | base64)
LA_KEY_ENC=$(echo -n "${LA_KEY_ENC_SPACE//[[:space:]]/}") # Needed for the next step

# Create App Service Extension
IP_ADDRESS=$(az network public-ip show -g $RESOURCE_GROUP -n Arc-K3s-Demo-PIP --output tsv --query ipAddress)

az k8s-extension create \
    --resource-group $RESOURCE_GROUP \
    --name $EXTENSION_NAME \
    --cluster-type connectedClusters \
    --cluster-name $CLUSTER_NAME \
    --extension-type 'Microsoft.Web.Appservice' \
    --release-train stable \
    --auto-upgrade-minor-version true \
    --scope cluster \
    --release-namespace $APP_SVC_NAMESPACE \
    --configuration-settings "Microsoft.CustomLocation.ServiceAccount=default" \
    --configuration-settings "appsNamespace=${APP_SVC_NAMESPACE}" \
    --configuration-settings "clusterName=${CLUSTER_NAME}" \
    --configuration-settings "loadBalancerIp=${IP_ADDRESS}" \
    --configuration-settings "keda.enabled=true" \
    --configuration-settings "buildService.storageClassName=local-path" \
    --configuration-settings "buildService.storageAccessMode=ReadWriteOnce" \
    --configuration-settings "customConfigMap=${APP_SVC_NAMESPACE}/kube-environment-config" \
    --configuration-settings "logProcessor.appLogs.destination=log-analytics" \
    --configuration-protected-settings "logProcessor.appLogs.logAnalyticsConfig.customerId=${LA_WORKSPACE_ID_ENC}" \
    --configuration-protected-settings "logProcessor.appLogs.logAnalyticsConfig.sharedKey=${LA_KEY_ENC}"

# Monitor the progress with

watch az k8s-extension show -g $RESOURCE_GROUP -c $CLUSTER_NAME -n $EXTENSION_NAME --cluster-type connectedClusters -o table


# Install Custom Location
EXTENSION_ID=$(az k8s-extension show -g $RESOURCE_GROUP -c $CLUSTER_NAME -n $EXTENSION_NAME --cluster-type connectedClusters --query 'id' -o tsv)
CUSTOM_LOCATION_NAME=$LOCATION-custom # Name of the custom location
CONNECTED_CLUSTER_ID=$(az connectedk8s show --resource-group $RESOURCE_GROUP --name $CLUSTER_NAME --query id --output tsv)

az customlocation create \
    --resource-group $RESOURCE_GROUP \
    --name $CUSTOM_LOCATION_NAME \
    --host-resource-id $CONNECTED_CLUSTER_ID \
    --namespace $APP_SVC_NAMESPACE \
    --cluster-extension-ids $EXTENSION_ID

CUSTOM_LOCATION_ID=$(az customlocation show \
  --resource-group $RESOURCE_GROUP \
  --name $CUSTOM_LOCATION_NAME \
  --query id \
  --output tsv)

az appservice kube create \
    --resource-group $RESOURCE_GROUP \
    --name $CLUSTER_NAME \
    --custom-location $CUSTOM_LOCATION_NAME \
    --static-ip $IP_ADDRESS

az appservice kube show \
    --resource-group $RESOURCE_GROUP \
    --name $CLUSTER_NAME
    

Problems

  • PVC not found storageclass.storage.k8s.io "default" not found

A StorageClass provides a way for administrators to describe the “classes” of storage they offer. Different classes might map to quality-of-service levels, or to backup policies, or to arbitrary policies determined by the cluster administrators. Kubernetes itself is unopinionated about what classes represent.

kubectl describe pvc arc4k8s-westeurope-appsvc-k8se-build-service -n appservice-ns

  Type     Reason              Age                   From                         Message
  ----     ------              ----                  ----                         -------
  Warning  ProvisioningFailed  XmXs (xX over Xm)  persistentvolume-controller  storageclass.storage.k8s.io "default" not found

You are missing a StorageClass called default in k3s and you specified this as the default when deploying the extension.

You can either change your extension deployment following:

-    --configuration-settings "buildService.storageClassName=default" \
+    --configuration-settings "buildService.storageClassName=local-path" \

Or you can create a new StorageClass based on the default from k3s

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: default
provisioner: rancher.io/local-path
reclaimPolicy: Delete
volumeBindingMode: WaitForFirstConsumer

You can view logs of the API using kubectl logs -lapp=reviewer-api -n app-dev-arc and UI using kubectl logs -lapp=reviewer-ui -n app-dev-arc

If you find that the app service is stuck pending a LoadBalancer this is because of a port conflict between Traefik and App Service.

some-ns    app-region-appsvc-k8se-envoy                    LoadBalancer   10.0.0.0.0    <pending>     80:32194/TCP,443:31968/TCP,8081:30415/TCP   16s

You will need to change the port that App Service is listening on

Enable Azure Defender Enable Application Delivery Next