Skip to main content
Back to Blog
28 June 202514 min read

Azure Cloud Services: Building Enterprise Applications

AzureCloudEnterpriseMicrosoft

An overview of key Azure services for enterprise development. App Service, Functions, Container Apps, and integration with Microsoft ecosystem.


Azure Cloud Services: Building Enterprise Applications

Microsoft Azure provides comprehensive cloud services with deep integration into the Microsoft ecosystem. For enterprises already using Microsoft technologies, Azure offers seamless connectivity with Active Directory, Office 365, and development tools like Visual Studio.

Azure Compute Options

Service Comparison

Azure Compute Services:

App Service (PaaS)
├── Best for: Web apps, APIs, mobile backends
├── Languages: .NET, Node.js, Python, Java, PHP
├── Scaling: Automatic or manual
└── Features: Deployment slots, custom domains, SSL

Azure Functions (Serverless)
├── Best for: Event-driven, short-running tasks
├── Triggers: HTTP, Timer, Queue, Blob, Event Grid
├── Scaling: Automatic, scale to zero
└── Features: Durable Functions, bindings

Container Apps (Serverless Containers)
├── Best for: Microservices, APIs, background jobs
├── Based on: Kubernetes (managed)
├── Scaling: KEDA-based auto-scaling
└── Features: Dapr integration, traffic splitting

Azure Kubernetes Service (AKS)
├── Best for: Complex containerised workloads
├── Control: Full Kubernetes access
├── Scaling: Cluster and pod auto-scaling
└── Features: Azure AD integration, Azure CNI

When to Use Each

Use CaseRecommended Service
Simple web appApp Service
Event processingAzure Functions
MicroservicesContainer Apps
Complex orchestrationAKS
Background jobsContainer Apps or Functions
Legacy lift-and-shiftVMs or App Service

App Service

Terraform Configuration

# app-service.tf resource "azurerm_service_plan" "main" { name = "${var.project}-plan" resource_group_name = azurerm_resource_group.main.name location = azurerm_resource_group.main.location os_type = "Linux" sku_name = "P1v3" } resource "azurerm_linux_web_app" "api" { name = "${var.project}-api" resource_group_name = azurerm_resource_group.main.name location = azurerm_resource_group.main.location service_plan_id = azurerm_service_plan.main.id site_config { application_stack { node_version = "20-lts" } always_on = true health_check_path = "/health" cors { allowed_origins = var.allowed_origins } } app_settings = { "NODE_ENV" = var.environment "APPLICATIONINSIGHTS_CONNECTION_STRING" = azurerm_application_insights.main.connection_string "DATABASE_URL" = "@Microsoft.KeyVault(VaultName=${azurerm_key_vault.main.name};SecretName=database-url)" } identity { type = "SystemAssigned" } sticky_settings { app_setting_names = ["NODE_ENV"] } } # Deployment slots for blue-green deployment resource "azurerm_linux_web_app_slot" "staging" { name = "staging" app_service_id = azurerm_linux_web_app.api.id site_config { application_stack { node_version = "20-lts" } } app_settings = { "NODE_ENV" = "staging" } } # Auto-scaling resource "azurerm_monitor_autoscale_setting" "api" { name = "${var.project}-autoscale" resource_group_name = azurerm_resource_group.main.name location = azurerm_resource_group.main.location target_resource_id = azurerm_service_plan.main.id profile { name = "default" capacity { default = 2 minimum = 2 maximum = 10 } rule { metric_trigger { metric_name = "CpuPercentage" metric_resource_id = azurerm_service_plan.main.id time_grain = "PT1M" statistic = "Average" time_window = "PT5M" time_aggregation = "Average" operator = "GreaterThan" threshold = 75 } scale_action { direction = "Increase" type = "ChangeCount" value = "1" cooldown = "PT5M" } } rule { metric_trigger { metric_name = "CpuPercentage" metric_resource_id = azurerm_service_plan.main.id time_grain = "PT1M" statistic = "Average" time_window = "PT5M" time_aggregation = "Average" operator = "LessThan" threshold = 25 } scale_action { direction = "Decrease" type = "ChangeCount" value = "1" cooldown = "PT5M" } } } }

Azure Functions

Function App Configuration

# functions.tf resource "azurerm_storage_account" "functions" { name = "${replace(var.project, "-", "")}func" resource_group_name = azurerm_resource_group.main.name location = azurerm_resource_group.main.location account_tier = "Standard" account_replication_type = "LRS" } resource "azurerm_service_plan" "functions" { name = "${var.project}-functions-plan" resource_group_name = azurerm_resource_group.main.name location = azurerm_resource_group.main.location os_type = "Linux" sku_name = "Y1" # Consumption plan } resource "azurerm_linux_function_app" "main" { name = "${var.project}-functions" resource_group_name = azurerm_resource_group.main.name location = azurerm_resource_group.main.location storage_account_name = azurerm_storage_account.functions.name storage_account_access_key = azurerm_storage_account.functions.primary_access_key service_plan_id = azurerm_service_plan.functions.id site_config { application_stack { node_version = "20" } application_insights_connection_string = azurerm_application_insights.main.connection_string } app_settings = { "FUNCTIONS_WORKER_RUNTIME" = "node" "WEBSITE_RUN_FROM_PACKAGE" = "1" "ServiceBusConnection" = azurerm_servicebus_namespace.main.default_primary_connection_string } identity { type = "SystemAssigned" } }

Function Implementation

// functions/src/functions/processOrder.ts import { app, InvocationContext } from '@azure/functions'; import { ServiceBusMessage } from '@azure/service-bus'; interface OrderMessage { orderId: string; customerId: string; items: Array<{ productId: string; quantity: number }>; total: number; } export async function processOrder( message: ServiceBusMessage, context: InvocationContext ): Promise<void> { const order = message.body as OrderMessage; context.log(`Processing order ${order.orderId}`); try { // Process the order await validateOrder(order); await reserveInventory(order); await processPayment(order); await sendConfirmation(order); context.log(`Order ${order.orderId} processed successfully`); } catch (error) { context.error(`Failed to process order ${order.orderId}:`, error); throw error; // Message will be retried or sent to DLQ } } app.serviceBusQueue('processOrder', { connection: 'ServiceBusConnection', queueName: 'orders', handler: processOrder }); // HTTP trigger example app.http('getOrder', { methods: ['GET'], authLevel: 'function', route: 'orders/{orderId}', handler: async (request, context) => { const orderId = request.params.orderId; const order = await getOrderFromDatabase(orderId); if (!order) { return { status: 404, jsonBody: { error: 'Order not found' } }; } return { jsonBody: order }; } });

Container Apps

Configuration

# container-apps.tf resource "azurerm_container_app_environment" "main" { name = "${var.project}-env" location = azurerm_resource_group.main.location resource_group_name = azurerm_resource_group.main.name log_analytics_workspace_id = azurerm_log_analytics_workspace.main.id } resource "azurerm_container_app" "api" { name = "${var.project}-api" container_app_environment_id = azurerm_container_app_environment.main.id resource_group_name = azurerm_resource_group.main.name revision_mode = "Multiple" template { container { name = "api" image = "${azurerm_container_registry.main.login_server}/${var.project}-api:${var.image_tag}" cpu = 0.5 memory = "1Gi" env { name = "NODE_ENV" value = var.environment } env { name = "DATABASE_URL" secret_name = "database-url" } liveness_probe { path = "/health" port = 8080 transport = "HTTP" } readiness_probe { path = "/ready" port = 8080 transport = "HTTP" } } min_replicas = var.environment == "production" ? 2 : 0 max_replicas = 10 } ingress { external_enabled = true target_port = 8080 traffic_weight { percentage = 100 latest_revision = true } } secret { name = "database-url" value = var.database_url } identity { type = "SystemAssigned" } dapr { app_id = "${var.project}-api" app_port = 8080 app_protocol = "http" } }

Azure AD Integration

Authentication Configuration

// auth/azure-ad.ts import { ConfidentialClientApplication } from '@azure/msal-node'; const msalConfig = { auth: { clientId: process.env.AZURE_CLIENT_ID!, authority: `https://login.microsoftonline.com/${process.env.AZURE_TENANT_ID}`, clientSecret: process.env.AZURE_CLIENT_SECRET! } }; const cca = new ConfidentialClientApplication(msalConfig); // Validate token in Express middleware export const validateAzureToken = async ( req: Request, res: Response, next: NextFunction ) => { const authHeader = req.headers.authorization; if (!authHeader?.startsWith('Bearer ')) { return res.status(401).json({ error: 'Missing authorization header' }); } const token = authHeader.substring(7); try { // Validate token using MSAL const result = await cca.acquireTokenOnBehalfOf({ oboAssertion: token, scopes: ['api://my-api/.default'] }); req.user = { oid: result.account?.homeAccountId, name: result.account?.name, email: result.account?.username }; next(); } catch (error) { return res.status(401).json({ error: 'Invalid token' }); } };

Key Takeaways

  1. Microsoft integration: Azure shines when integrated with Microsoft ecosystem

  2. App Service simplicity: PaaS for straightforward web applications

  3. Container Apps: Modern alternative to AKS for simpler workloads

  4. Deployment slots: Enable zero-downtime deployments

  5. Azure AD: Native enterprise identity management

  6. Key Vault: Centralised secrets management

  7. Application Insights: Built-in observability

  8. Hybrid capabilities: Strong on-premises integration options

Azure provides enterprise-grade services with seamless Microsoft integration. Choose services based on complexity requirements and team expertise.

Share this article