Migrating .NET Workloads to Azure. App Service, AKS, and Landing Zone Setup.

Jerzy Kopaczewski 27 July 2026 20 min read
Contents

Migrating .NET Workloads to Azure - App Service, AKS, and Landing Zone Setup

You have a .NET application running on-premise or on legacy hosting. The decision to migrate to the cloud has been made, and Azure is the target - because Microsoft, because .NET, because you already have Windows Server licences. But from decision to a working production environment is a long road. This article covers the concrete steps: preparing a Landing Zone, choosing between App Service and AKS, and deploying your first production workload on Azure.

Migrating .NET applications to Azure looks straightforward on the surface - it’s Microsoft’s ecosystem, after all. In practice, organisations hit the same problems: no subscription structure, poorly designed networking, costs spiralling out of control after the first month. This guide describes a process that minimises those risks.

 

Why Azure for .NET Workloads

Azure is the natural home for .NET applications for several technical and business reasons:

  • Native .NET integration - App Service, Azure Functions, and AKS have full support for .NET 8/9. Hot reload, diagnostics, profiling - everything works immediately without configuring additional agents.
  • Azure Hybrid Benefit - if you have Windows Server or SQL Server licences with Software Assurance, you can use them in Azure at no additional cost. For a typical organisation with 10 Windows servers, that’s 40-60% savings on compute.
  • Entra ID (Azure AD) - if your organisation uses Microsoft 365, identities already exist. SSO to internal applications works immediately without building a separate IAM system.
  • European regions - multiple datacentres across Europe (West Europe, North Europe, plus country-specific regions). For applications requiring EU data residency, Azure provides comprehensive coverage.
  • Compliance - ISO 27001, SOC 2, GDPR compliance documentation available through Azure Compliance Manager for European regions.

This doesn’t mean Azure is the only option. If your application is a pure containerised API with no Microsoft ecosystem dependencies - AWS and GCP are excellent choices too. But if you have .NET + SQL Server + Active Directory + Microsoft licences - Azure provides the shortest path to the cloud.

 

Landing Zone - the Foundation Before Migration

A Landing Zone is a pre-configured Azure environment with correct management structure, networking, security, and policies. Without it, you’re migrating into chaos.

What Is an Azure Landing Zone

A Landing Zone is not a product you buy - it’s Microsoft’s reference architecture (Cloud Adoption Framework) that defines:

  • Management Group and subscription structure
  • Network topology (hub-spoke or Virtual WAN)
  • Governance policies (Azure Policy)
  • Baseline security services (Microsoft Defender for Cloud, Key Vault)
  • Monitoring (Log Analytics Workspace, Azure Monitor)

Without a Landing Zone, the typical scenario looks like this: a dev team creates a subscription, deploys an application, and after 3 months nobody knows who’s paying for what, networking is flat (everything can see everything), and security policies don’t exist.

Subscription Structure

The minimum sensible structure for an organisation migrating its first application:

Tenant Root Group
└── Organisation (Management Group)
    ├── Platform
    │   ├── sub-connectivity    (hub VNet, DNS, firewall)
    │   └── sub-management      (Log Analytics, Automation)
    └── Workloads
        ├── sub-prod            (production)
        └── sub-nonprod         (dev + staging)

Why separate subscriptions?

  • Cost isolation - you can see how much production costs vs. dev without tagging
  • Permission isolation - developers get Contributor on nonprod, Reader on prod
  • Limits - each subscription has separate quotas (vCPU, public IPs)
  • Budget alerts - separate thresholds per subscription

For an organisation of 20-50 people with one application - 4 subscriptions is the minimum. For larger organisations with multiple teams - one subscription per workload per environment.

Networking - Hub-Spoke Topology

Hub-spoke is the simplest topology that provides isolation and central control:

  • Hub VNet (sub-connectivity) - central point: Azure Firewall or NVA, VPN Gateway to on-premise, DNS Private Resolver
  • Spoke VNet (sub-prod, sub-nonprod) - application networks, peered with the hub
┌─────────────────────────────────────────────┐
│ Hub VNet (10.0.0.0/16)                      │
│  ├── AzureFirewallSubnet (10.0.1.0/24)      │
│  ├── GatewaySubnet (10.0.2.0/24)            │
│  └── DNSResolverSubnet (10.0.3.0/24)        │
└─────────────┬───────────────┬───────────────┘
              │ peering       │ peering
┌─────────────▼──────┐  ┌────▼──────────────┐
│ Spoke-Prod          │  │ Spoke-NonProd      │
│ (10.1.0.0/16)       │  │ (10.2.0.0/16)      │
│  ├── AppSubnet      │  │  ├── AppSubnet     │
│  ├── DataSubnet     │  │  ├── DataSubnet    │
│  └── AKSSubnet      │  │  └── AKSSubnet     │
└────────────────────┘  └────────────────────┘

Key decisions:

  • Azure Firewall vs NVA - Azure Firewall is a managed service (~$900/month base cost). For smaller organisations, NSG + Route Tables without a firewall is sufficient. Add the firewall when you have compliance requirements for egress traffic inspection.
  • DNS - Azure Private DNS Zones for PaaS services (Private Endpoints). If you have AD DS on-premise - DNS forwarding to on-prem DNS via Private Resolver.
  • VPN vs ExpressRoute - VPN Gateway (~$140/month) for traffic <1 Gbps. ExpressRoute (~$200/month + port fee from provider) for dedicated connection and lower latency.

 

App Service vs AKS - When to Use Which

This is the most common question when migrating .NET to Azure. The answer depends on application complexity, operational requirements, and team expertise.

App Service - When It’s Enough

App Service is a fully managed PaaS platform. You don’t manage servers, don’t configure the OS, don’t worry about patches. You deploy code or a container - Azure handles the rest.

Ideal for:

  • Monolithic .NET applications (Web API + frontend)
  • Simple microservices (up to ~5-10 services)
  • Teams without Kubernetes experience
  • Applications with predictable traffic
  • MVPs and early migration phases (lift-and-shift)

Limitations:

  • Max 30 instances per App Service Plan (horizontal scaling)
  • No control over OS and runtime beyond what the platform offers
  • Networking - VNet Integration works but with limitations (no inbound private endpoint below Premium v3)
  • Costs scale non-linearly at large scale

Typical .NET architecture on App Service:

Internet → Application Gateway (WAF)
    → App Service (Web API)
        → Azure SQL Database
        → Azure Cache for Redis
        → Azure Service Bus
        → Azure Blob Storage

Estimated cost (production, West Europe):

ComponentSKUCost/month
App Service PlanP1v3 (2 vCPU, 8 GB RAM)~$140
Azure SQL DatabaseS2 (50 DTU)~$75
Application GatewayWAF v2 (basic)~$250
Redis CacheC1 Basic (1 GB)~$40
Blob StorageLRS Hot (100 GB)~$2
Total~$507/mo

AKS (Azure Kubernetes Service) - When You Need It

AKS is managed Kubernetes. The control plane is free - you pay for nodes (VMs) and additional services. It gives full control but requires operational knowledge.

Ideal for:

  • Microservices architecture (>10 services)
  • Applications requiring advanced scaling (HPA, KEDA, node autoscaler)
  • Teams with Kubernetes experience
  • Applications requiring sidecar patterns (service mesh, observability)
  • Migrations from on-premise Kubernetes or Docker Swarm

Limitations:

  • Learning curve - Kubernetes is a complex system
  • Operational overhead - upgrades, node pool management, networking (CNI)
  • Minimum sensible production configuration costs more than App Service
  • You need an engineer who understands K8s at an operational level

Typical .NET architecture on AKS:

Internet → Azure Front Door (WAF + CDN)
    → AKS Ingress Controller (NGINX or AGIC)
        → Pod: Web API (.NET 8)
        → Pod: Background Worker
        → Pod: gRPC Service
    → Azure SQL Database (Private Endpoint)
    → Azure Service Bus
    → Azure Key Vault (CSI Secret Store)

Estimated cost (production, West Europe, 3-node cluster):

ComponentSKUCost/month
AKS Control PlaneFree tier$0
Node Pool (system)3× Standard_D2s_v5 (2 vCPU, 8 GB)~$210
Node Pool (applications)2× Standard_D4s_v5 (4 vCPU, 16 GB)~$280
Azure SQL DatabaseS2 (50 DTU)~$75
Azure Front DoorStandard~$35 + traffic
Container RegistryBasic~$5
Key VaultStandard~$1
Total~$606/mo

Decision Matrix

CriterionApp ServiceAKS
Number of microservices1-1010+
Team Kubernetes experienceNot requiredRequired
Time-to-production1-2 weeks3-6 weeks
ScalingUp to 30 instancesVirtually unlimited
Entry cost (production)~$150/mo~$500/mo
Operational overheadLowMedium-high
Vendor lock-inHigh (PaaS-specific)Low (K8s portability)
On-prem K8s compatibilityNoneFull

Our recommendation: If you don’t have a strong reason to use AKS - start with App Service. Migrating from App Service to AKS later is simpler than trying to learn Kubernetes during a production migration. Add AKS when App Service becomes a limitation (>10 services, need for service mesh, complex scaling requirements).

 

Step-by-Step Migration Process

Phase 1: Assessment (1-2 weeks)

Before you move anything, you need to know what you have:

Inventory:

  • List of applications and their dependencies (databases, queues, cache, files)
  • .NET Framework vs .NET Core/.NET 8 versions (critical - .NET Framework requires Windows containers or Windows App Service)
  • Latency requirements (does the application need to be close to users in a specific region?)
  • Current traffic patterns (peak hours, seasonality)
  • Dependencies on on-premise services (AD DS, file shares, legacy APIs)

Assessment tools:

  • Azure Migrate - discovery agent installed on-premise, scans VMs, maps dependencies, suggests Azure sizing
  • Azure App Service Migration Assistant - checks IIS/.NET application compatibility with App Service
  • .NET Upgrade Assistant - estimates effort required to migrate from .NET Framework to .NET 8

Phase output:

  • Decision: App Service vs AKS (per application)
  • Migration strategy: lift-and-shift vs re-platform vs re-architect
  • Preliminary Azure budget (target monthly cost)
  • Blocker list (e.g., application requires .NET Framework 4.5 + Windows-specific APIs)

Phase 2: Landing Zone Setup (1-2 weeks)

With Terraform or Bicep - never manually. Infrastructure must be repeatable.

Minimum to get started:

# Terraform - module structure example
module "management_groups" {
  source = "./modules/management-groups"
}

module "connectivity" {
  source              = "./modules/connectivity"
  hub_address_space   = "10.0.0.0/16"
  dns_servers         = ["10.0.3.4"]
  vpn_gateway_sku     = "VpnGw1"
  location            = "westeurope"
}

module "workload_prod" {
  source              = "./modules/spoke"
  spoke_address_space = "10.1.0.0/16"
  hub_vnet_id         = module.connectivity.hub_vnet_id
  environment         = "prod"
  location            = "westeurope"
}

Landing Zone checklist:

  • ☐ Management Groups and subscriptions created
  • ☐ Hub VNet with DNS configured
  • ☐ Spoke VNets with peering to hub
  • ☐ Azure Policy assigned (allowed locations)
  • ☐ Central Log Analytics Workspace
  • ☐ Key Vault per environment
  • ☐ RBAC - role assignments for teams
  • ☐ Budget alerts ($/month per subscription)
  • ☐ Microsoft Defender for Cloud enabled (at least Free tier)

Phase 3: Database Migration (1-3 weeks)

The database migrates first - it’s the riskiest element and requires the most testing.

SQL Server → Azure SQL Database:

The most common path for .NET applications. Azure SQL Database is fully managed PaaS - backups, patches, HA (99.99% SLA) handled by Azure.

Steps:

  1. Compatibility check - Azure SQL Database doesn’t support all SQL Server features (no SQL Agent, no cross-database queries, no linked servers). Use Data Migration Assistant to identify issues.
  2. Model selection - DTU (simple, predictable cost) vs vCore (flexible, Azure Hybrid Benefit). For migrations, start with DTU S2/S3, then optimise.
  3. Data migration - Azure Database Migration Service (DMS) for online migration (minimal downtime) or bacpac export/import for offline.
  4. Private Endpoint - database accessible only from your VNet, not from the public internet.
  5. Connection string update - change in application from Server=on-prem-sql to Server=tcp:mydb.database.windows.net,1433.
# Example - online migration via DMS (Azure CLI)
az dms project task create \
  --resource-group rg-migration \
  --service-name dms-prod \
  --project-name sql-migration \
  --task-name migrate-appdb \
  --source-connection-json '{
    "dataSource": "10.0.1.50",
    "authentication": "SqlAuthentication",
    "userName": "migration_user",
    "password": "***"
  }' \
  --target-connection-json '{
    "dataSource": "appdb-prod.database.windows.net",
    "authentication": "SqlAuthentication",
    "userName": "sqladmin",
    "password": "***"
  }' \
  --database-options-json '[{
    "name": "AppDatabase",
    "targetDatabaseName": "AppDatabase"
  }]'

Important: If you have SQL Server Enterprise licences with SA - use the vCore model with Azure Hybrid Benefit. Savings reach 55% vs full price.

Phase 4: Application Deployment (1-2 weeks)

App Service Path

For .NET 8 applications on Linux (recommended):

# 1. Create App Service Plan
az appservice plan create \
  --name asp-app-prod \
  --resource-group rg-app-prod \
  --sku P1v3 \
  --is-linux \
  --location westeurope

# 2. Create Web App
az webapp create \
  --name app-myapi-prod \
  --resource-group rg-app-prod \
  --plan asp-app-prod \
  --runtime "DOTNETCORE:8.0"

# 3. Configure VNet Integration
az webapp vnet-integration add \
  --name app-myapi-prod \
  --resource-group rg-app-prod \
  --vnet spoke-prod-vnet \
  --subnet app-subnet

# 4. Set connection string (Key Vault reference)
az webapp config appsettings set \
  --name app-myapi-prod \
  --resource-group rg-app-prod \
  --settings "ConnectionStrings__Default=@Microsoft.KeyVault(VaultName=kv-app-prod;SecretName=sql-connection-string)"

Key production configurations:

  • Always On = true - prevents cold start after 20 minutes of inactivity
  • Health Check - /health endpoint checked every 30 seconds, unhealthy instances removed from the load balancer
  • Deployment Slots - staging slot for blue-green deployment (swap without downtime)
  • Managed Identity - system-assigned identity for accessing Key Vault, SQL, and Storage without secrets in connection strings

AKS Path

For microservices architecture:

# Kubernetes deployment - .NET 8 API
apiVersion: apps/v1
kind: Deployment
metadata:
  name: api-orders
  namespace: production
spec:
  replicas: 3
  selector:
    matchLabels:
      app: api-orders
  template:
    metadata:
      labels:
        app: api-orders
        azure.workload.identity/use: "true"
    spec:
      serviceAccountName: sa-api-orders
      containers:
      - name: api
        image: acrmyapp.azurecr.io/api-orders:1.2.0
        ports:
        - containerPort: 8080
        resources:
          requests:
            cpu: "250m"
            memory: "256Mi"
          limits:
            cpu: "500m"
            memory: "512Mi"
        env:
        - name: ASPNETCORE_ENVIRONMENT
          value: "Production"
        - name: ConnectionStrings__Default
          valueFrom:
            secretKeyRef:
              name: sql-connection
              key: connection-string
        livenessProbe:
          httpGet:
            path: /health/live
            port: 8080
          initialDelaySeconds: 10
        readinessProbe:
          httpGet:
            path: /health/ready
            port: 8080
          initialDelaySeconds: 5

Key AKS elements for .NET:

  • Workload Identity - managed identity for pods (instead of static secrets). Configured through federated credentials in Entra ID.
  • KEDA - pod scaling based on external metrics (Service Bus queue length, Event Hub message count)
  • Azure CNI Overlay - networking for large clusters without exhausting IP addresses in the subnet
  • Azure Key Vault CSI Driver - mounting secrets from Key Vault directly as volumes in pods

 

CI/CD - Deployment Automation

Migration without CI/CD means rewriting yourself into manual deployments in a new environment. The pipeline should be ready in parallel with infrastructure.

For App Service (GitHub Actions):

name: Deploy to App Service
on:
  push:
    branches: [main]

permissions:
  id-token: write
  contents: read

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v4

    - uses: actions/setup-dotnet@v4
      with:
        dotnet-version: '8.0.x'

    - run: dotnet publish -c Release -o ./publish

    - uses: azure/login@v2
      with:
        client-id: $
        tenant-id: $
        subscription-id: $

    - uses: azure/webapps-deploy@v3
      with:
        app-name: app-myapi-prod
        slot-name: staging
        package: ./publish

    - name: Swap slots
      run: |
        az webapp deployment slot swap \
          --name app-myapi-prod \
          --resource-group rg-app-prod \
          --slot staging \
          --target-slot production

For AKS (GitHub Actions + ArgoCD):

In the Kubernetes ecosystem, we prefer GitOps with ArgoCD - the pipeline builds the image and pushes it to ACR, ArgoCD synchronises the manifest from the repository to the cluster. We covered the details in our article on Azure DevOps vs GitHub Actions.

 

Common Migration Mistakes

Based on migration projects we’ve delivered - here are the most common problems:

1. No Landing Zone - “we’ll put everything in one subscription”

Result: after 6 months nobody knows who’s paying for what, who has what permissions, and networking is a flat network without segmentation. Unwinding this state costs 2-3× more than doing it properly from the start.

2. Choosing an oversized SKU “just in case”

Teams accustomed to on-premise buy D8s_v5 (8 vCPU, 32 GB) for an application that needs 500 MB RAM. In the cloud, you start small and scale up. App Service P1v3 with autoscaling is a better choice than P3v3 running constantly.

3. Ignoring egress costs

Outbound traffic from Azure costs ~$0.087/GB (to the internet). If your application generates significant outbound traffic (e.g., integrations with external APIs, backup to external storage) - egress costs can surprise you. Private Endpoints eliminate this cost for communication between Azure services in the same region.

4. .NET Framework on Linux

App Service on Linux supports only .NET Core/.NET 5+. If the application is on .NET Framework 4.x - you need a Windows App Service Plan (more expensive) or Windows containers (slower cold start, fewer scaling options). Consider upgrading to .NET 8 before migration - it’s an investment that pays off.

5. No Private Endpoints

By default, Azure SQL Database, Storage Account, and other PaaS services are accessible from the public internet. A firewall rule with allowed IPs is an option, but it’s not Zero Trust. Private Endpoint places the service in your VNet with a private IP address - the only way to access it is being inside the virtual network.

6. Manual deployments after migration

“We’ll deploy manually for now, CI/CD later.” Later never comes. Deployment automation isn’t a luxury - it’s operational hygiene. Swap slots in App Service + GitHub Actions is a 2-hour configuration.

 

Timeline and Costs

PhaseDurationConsulting cost (typical)
Assessment + migration plan1-2 weeks$2,000 - $4,000
Landing Zone (Terraform/Bicep)1-2 weeks$3,000 - $6,000
Database migration1-3 weeks$2,500 - $5,000
Application deployment + CI/CD1-2 weeks$2,500 - $4,500
Testing + cutover + stabilisation1-2 weeks$2,000 - $3,000
TOTAL (App Service)5-10 weeks$12,000 - $22,500
TOTAL (AKS)8-14 weeks$17,500 - $35,000

What affects cost:

  • Number of applications to migrate (each additional +20-40% time)
  • State of source code (.NET Framework vs .NET 8)
  • Integration complexity (how many external systems?)
  • Compliance requirements (additional documentation and configuration)
  • Whether a Landing Zone already exists or needs to be built from scratch

Funding: The Microsoft Azure Migrate and Modernize programme offers Azure credits for the first 6 months after migration. Value depends on workload size - typically $10,000-$50,000 in credits.

 

How We Can Help

At Devopsity, we specialise in Azure migrations for organisations running .NET workloads. Typical engagement:

  • Assessment (1-2 days) - analysis of current infrastructure, App Service vs AKS recommendation, preliminary Azure cost estimate
  • Landing Zone (1-2 weeks) - Terraform setup, networking, governance, RBAC
  • Migration (2-6 weeks) - database, application, CI/CD, cutover
  • Optimisation (ongoing) - right-sizing, Reserved Instances, cost monitoring

If you’re planning a .NET migration to Azure - let’s discuss your case. No commitment, no sales pitch.

Jerzy Kopaczewski

Planning an Azure migration?

Book a free 30-minute technical consultation. We'll discuss your infrastructure and the best migration path.

 

Frequently Asked Questions

Can I migrate a .NET Framework 4.x application to Azure without rewriting it to .NET 8?

Yes. Windows App Service supports .NET Framework 4.x natively. Alternatively - Windows containers on AKS. But long-term, plan an upgrade to .NET 8: better performance, Linux support (cheaper plans), active framework development.

How long does migrating a single .NET application to Azure take?

Minimum 4-5 weeks (simple application + SQL on App Service). Typically 6-10 weeks for medium complexity. Migration to AKS with full Landing Zone - 10-14 weeks. The biggest impact on timeline is database state and number of integrations.

How much does Azure cost monthly after migration?

For a typical .NET application (API + frontend + SQL + cache): $400-$800/month on App Service, $600-$1200/month on AKS. With Azure Hybrid Benefit (existing Windows/SQL licences) - 30-55% cheaper.

Do I need Azure Firewall?

Not always. For small deployments (1-2 applications), NSG + UDR is sufficient. Add Azure Firewall when you have requirements for centralised egress traffic inspection, logging all network traffic, or compliance requires an L7 firewall.

What about data residency in the EU?

Azure offers multiple European regions (West Europe in the Netherlands, North Europe in Ireland, plus country-specific regions like France Central, Germany West Central, and others). For GDPR compliance, keeping data within EU regions is straightforward. Azure Compliance Manager provides documentation for regulatory requirements.

Azure cloud migration App Service AKS Landing Zone .NET Kubernetes Terraform

Read also:

Previous post