I am curious how folks in the community reason about “containers” vs. “serverless” and different takes.
I recently came across the Dapr project: https://dapr.io/ which I think is a conceptually very interesting approach to system architecture that allows building a portable application that can be plugged into AWS, Azure, GCP, etc.
There is a reference eShop project on github: https://github.com/dotnet-architecture/eShopOnDapr
I have worked with Azure Functions, AWS Lambda, and AWS AppSync but not very heavily with containerized workloads.
Looking at the eShop reference project, I cannot get over how complex the application is compared to what it would take to build the same functionality with the same general application level characteristics (decoupled, event driven, service oriented) using Lambda, AppSync, or Functions. And this got me wondering where teams find this level of complexity worthwhile.
As I understand it, there are a handful of benefits gained from the containerized approach:
- Long running application logic. Most serverless frameworks have short timeout quotas so they are not suited for long running processes.
- Memory or CPU intensive workloads. With serverless, you have less control over resource intensive workloads. So if you have a workload that requires more control over memory or CPU, containers are a better alternative
- Portability. Containerized applications are more portable between different platforms. On-premise, AWS, Azure, or Google — you can deploy your containerized workloads easily between these platforms. It is possible with serverless as well IMO by moving most of your business logic into application libraries (e.g. a layer in Lambda) and using the serverless interface primarily as a bridge to I/O.
- (3a) Flexibility. Extending portability, a solution like Dapr would allow the underlying platform components to be replaced. Developing natively for Azure Functions requires using Functions specific bindings to event sources such as Service Bus or Event Grid whereas Dapr would allow the application to plug AWS SNS as an event source on AWS and Service Bus on Azure. In some mission critical scenarios, this may even be THE deciding factor as it allows a multi-cloud deployment (though you have a different challenge of synchronizing data between the clouds) that could theoretically stay up even if one of the major providers goes down.
- Legacy apps. Some legacy apps may be easier to “lift-and-shift” into containers whereas moving into Functions or Lambda is a re-write. For example, applications which are written as daemons. Some legacy apps would not fit into a serverless paradigm at all and would require mapping to another platform specific service.
- Persistent workloads. Serverless benefits from burst type workloads since there is no cost when the system is not operating. For example, enterprise line of business systems which tend to have predictable spikes in the start of a workday and early afternoon. At night, when there are no users, there is no cost component for the compute. On the other hand, some types of systems which see continuous throughput may be more cost effective with containers.
- Ops can be simplified in some cases. By deploying the application components and dependencies (e.g. Redis) as containers, it can be easier to to manage than building complex IAC configuration using ARM templates, CF templates, etc.
- Programming language. Functions will have limited support for programming languages so if you are using a less commonly deployed language, you would benefit from the container runtime.
I would love to hear from folks who are working with containerized workloads and who have worked with serverless to get some different angles and other perspectives I’m missing.
It seems to me that in the majority of cases, the application code and deployment model is considerably more concise and easier to reason about with serverless than with containerized workloads for most web application APIs if one is willing to accept the tradeoffs (e.g. lack of platform portability).