Every mature platform eventually has an architecture debate that is less about which technology is “better” and more about which technology fits the operating model.
For our fleet governance platform, one of those debates was whether to build the core automation layer on Azure Kubernetes Service or Azure Functions.
Both options were valid. Both could have supported the platform. Both are proven Azure-native approaches for running distributed workloads at scale. The decision was not based on AKS being wrong or Azure Functions being universally better. It came down to workload shape, operational responsibility, scale characteristics, and the kind of platform we were building.
In our case, we chose Azure Functions.
This post explains the debate, the tradeoffs, and why serverless was the better fit for our fleet automation model.
The Platform Context
The platform manages fleet-level governance across many Azure subscriptions and customer environments. Its responsibilities include:
- Detecting resource changes.
- Evaluating policy and monitoring requirements.
- Onboarding subscriptions safely and consistently.
- Correcting drift when resources fall out of compliance.
- Triggering remediation workflows.
- Maintaining operational state and inventory metadata.
- Integrating with enterprise governance, monitoring, and ticketing systems.
This is not a traditional web application with steady request volume. It is an event-driven governance and automation system.
The platform responds to activity across the fleet. Sometimes that means processing a small number of events. Other times it means handling bursts of resource changes, onboarding activity, compliance scans, or remediation jobs.
That workload shape heavily influenced the architecture decision.
Why AKS Was a Serious Option
AKS is a strong platform. For many engineering teams, it is the correct answer.
AKS gives you control over containerized workloads, deployment patterns, networking, service-to-service communication, scaling policies, and runtime consistency. If you are building a platform with multiple long-running services, custom APIs, background workers, internal services, and complex deployment topologies, Kubernetes can be an excellent foundation.
There were several reasons AKS deserved consideration:
Strong fit for containerized platforms
AKS is attractive when the platform is already organized around containers. It provides a consistent runtime for APIs, workers, agents, schedulers, and supporting services.
Control over scaling and runtime behavior
With Kubernetes, teams can tune horizontal pod autoscaling, node pools, resource requests, limits, affinity rules, and deployment strategies. That level of control is valuable for predictable, high-throughput systems.
Better fit for long-running services
If the workload depends on long-running processes, persistent in-memory workers, custom daemons, or services that need to stay warm at all times, AKS can be more natural than serverless.
Platform extensibility
Kubernetes has a large ecosystem: ingress controllers, service mesh, GitOps tooling, policy engines, secret management integrations, observability agents, and workload identity patterns. For organizations already operating Kubernetes well, AKS can become a powerful internal platform layer.
The Cost of AKS Is Not Just Compute
The challenge with AKS is that the cost is not only the node cost.
The real cost is operational ownership.
Running AKS well means owning:
- Cluster upgrades.
- Node image updates.
- Kubernetes version lifecycle.
- Ingress configuration.
- Pod security standards.
- Network policy.
- Workload identity.
- Secrets integration.
- Autoscaling behavior.
- Logging and metrics pipelines.
- Container vulnerability management.
- Base image governance.
- Cluster policy.
- Disaster recovery patterns.
- Capacity planning.
- Platform troubleshooting.
None of these are bad things. They are simply real things.
For a team whose primary product is governance automation, every hour spent maintaining the orchestration substrate is an hour not spent improving compliance logic, drift correction, resource intelligence, customer onboarding, or remediation quality.
That became a key point in the debate.
AKS would have given us more control, but it would also have increased the size of the platform we had to operate.
Why Azure Functions Fit the Workload
Azure Functions aligned closely with how the platform actually behaves.
The platform is event-driven by design. Resource changes, policy evaluations, onboarding steps, queue messages, scheduled scans, and remediation workflows are all discrete units of work. They do not need to run as always-on services in most cases. They need to wake up, process the event safely, update state, and exit.
That maps directly to Azure Functions.
Event-driven execution
Azure Functions integrates naturally with Event Grid, Service Bus, Storage Queues, timers, HTTP triggers, and Durable Functions. For a governance platform, that trigger model is extremely useful.
A resource changes. An event fires. A queue message is created. A function evaluates the resource. Another function updates state. Another function remediates drift if approved.
That pattern is clean, composable, and operationally simple.
Lower platform management burden
With Azure Functions, we do not manage Kubernetes clusters, node pools, ingress controllers, or cluster upgrades. The runtime still requires governance, monitoring, deployment discipline, and security hardening, but the operational surface area is smaller.
For our platform, that mattered.
We wanted the team focused on the governance domain, not on maintaining a container orchestration platform unless there was a clear need.
Better fit for bursty fleet operations
Fleet platforms often have uneven workloads. A large onboarding wave, a policy change, or a resource change event storm can generate a burst of processing. Then activity can return to normal.
Azure Functions is well suited to this kind of elastic, burst-driven execution model, especially when paired with queues and durable orchestration patterns.
Durable Functions for orchestration
One of the strongest arguments for Azure Functions was Durable Functions.
Fleet governance is full of workflows that require coordination:
- Validate subscription prerequisites.
- Check resource providers.
- Snapshot inventory.
- Determine applicable controls.
- Apply policies.
- Wait for remediation state.
- Verify compliance.
- Retry failed steps safely.
- Record final status.
Durable Functions provides a natural way to model these workflows without building a custom orchestration engine from scratch.
Strong separation of responsibilities
Functions encouraged us to break the platform into focused units:
- One function handles resource change intake.
- Another handles policy evaluation.
- Another handles remediation.
- Another handles inventory updates.
- Another handles scheduled validation.
- Another handles customer or subscription onboarding.
This model supports safer deployments, smaller blast radius, and easier troubleshooting.
Where Azure Functions Has Tradeoffs
Choosing Azure Functions does not mean ignoring its limitations.
Serverless has its own constraints.
Runtime and execution limits matter
Function execution duration, hosting plan selection, concurrency behavior, cold starts, dependency loading, and retry semantics all need to be understood. Poorly designed serverless systems can become difficult to troubleshoot.
Distributed workflows require discipline
A function-based platform can become fragmented if boundaries are not clear. Naming, logging, correlation IDs, idempotency keys, retry handling, and state management must be designed intentionally.
Observability is non-negotiable
Because work is distributed across triggers, queues, and orchestrations, observability must be built in from the start. Application Insights, structured logging, correlation IDs, dashboarding, and dead-letter queue monitoring are required.
Not every workload belongs in a function
Long-running APIs, latency-sensitive services, stateful compute, persistent workers, and workloads requiring deep runtime customization may be better suited to containers or AKS.
That was part of the conclusion: Azure Functions was right for our automation layer, not necessarily for every workload we will ever build.
The Decision Framework
The debate ultimately came down to a few architecture questions.
Is the workload event-driven or always-on?
Our workload was primarily event-driven. Azure Functions was a natural fit.
Do we need full control of the runtime?
For this layer of the platform, we did not need Kubernetes-level control. We needed reliable execution, orchestration, queue processing, and integration with Azure-native services.
Is operational complexity justified?
AKS would have added operational power, but also operational responsibility. For this use case, that responsibility was not justified.
Can the system be designed around idempotency?
Yes. In fact, our platform already depends on idempotency. Every onboarding, policy, monitoring, and remediation action needs to be safe to run repeatedly. That model works very well with event-driven functions.
Can we handle scale through queues and orchestration?
Yes. Service Bus, Event Grid, Durable Functions, and well-designed concurrency controls gave us the scaling model we needed without managing a Kubernetes control plane.
Why We Chose Azure Functions
We chose Azure Functions because it matched the operating model of the platform.
The platform needed to be:
- Event-driven.
- Idempotent.
- Highly automated.
- Easy to scale during bursts.
- Integrated with Azure-native messaging and monitoring.
- Focused on governance outcomes rather than infrastructure management.
- Simple enough for the team to operate across many customers and subscriptions.
Azure Functions gave us a clean way to build the automation layer around discrete events and durable workflows. It allowed us to focus engineering effort on policy intelligence, onboarding safety, drift detection, remediation quality, and customer visibility.
AKS would have been a valid choice if our primary need had been long-running services, container platform extensibility, or deep control over workload orchestration. But for this fleet governance use case, Azure Functions reduced unnecessary operational overhead.
The Final Architecture Direction
The final decision was not “Functions instead of Kubernetes forever.”
The decision was more specific:
Use Azure Functions for the fleet automation and governance execution layer.
That includes event intake, policy evaluation, onboarding workflows, drift detection, remediation jobs, scheduled validation, queue processing, and durable orchestration.
AKS remains a valid option for future platform components that may require long-running APIs, containerized services, custom runtimes, or workloads where Kubernetes provides a clear operational advantage.
This distinction matters. Good architecture does not turn tools into ideology. It chooses the right operating model for the workload.
Conclusion
The AKS versus Azure Functions debate was valuable because it forced us to clarify what kind of platform we were building.
If we were building a container-first application platform with many long-running services, AKS may have been the better choice.
But we were building a fleet governance automation platform. The workload was event-driven, bursty, distributed, and highly dependent on idempotent workflows. The platform needed to respond to change, evaluate state, remediate drift, and record outcomes across a large Azure estate.
For that model, Azure Functions was the right choice.
Not because Kubernetes was wrong.
Because serverless better matched the work.