Containers, functions and serverless development have transformed the way we think about modern computing, each contributing to a more flexible, reliable IT environment. However, confusion around the differences—and how to utilize the services appropriately—continues to muddle the technology industry. So, what are the key differentiators between containers and functions, and how can developers leverage each for optimal results?
Containers and Functions: The Basics
Let’s start with containers. There’s been quite a bit of hype around containers in the last few years with Docker and Kubernetes taking flight. Docker defines a container image as “a lightweight, stand-alone, executable package of a piece of software that includes everything needed to run it: code, runtime, system tools, system libraries and settings.” Essentially, a container can “contain” anything from a webservice to a complete DBMS system, to even the data tier that DBMS writes into, and offers a way for developers to package code (and dependencies) so that they are suitable to run anywhere. On top of that, containers are virtually endless, having the ability to run on and on.
Functions, on the other hand, have well-defined purposes, taking a reasonably short input while providing a similarly short output, and can run independently once receiving the necessary input. Functions also, by nature, consist of a set of known characteristics: short run times, need to be pushed to structured/unstructured storage, required to be invoked by defined events over HTTP, TCP or another protocol, to name a few.
Finally, what is commonly referred to as “serverless” is a category of software design where the abstraction layer for developers is set at the application tier, above the OS, infrastructure and cloud IaaS APIs—in other words, so that developers do not have to think about infrastructure when developing.
While most people can agree on these definitions, the confusion usually originates from the emergence of “container-native” frameworks, in which the Docker container is a first-class citizen and any image can be used as the function itself. The confusion is easily understandable: If the function is the container, and the container is a function, then what is the difference, and which is best used when?
The reality is that to fully take advantage of functions, developers should package them into a container, which allows them to think and reason about that container differently, as a new atomic unit of compute. Indeed, a function packaged in a container gives us a new “atomic unit of computing,” in which software can be broken down in building blocks such as an image processing function or a sentiment analysis function. These functions can be shared and extended, as well as build composite applications, much like molecules form complex organisms.
A New Atomic Unit of Compute
When considering function, not only do we get this new atomic unit of compute, but we also retain all the benefits of the container itself: standardized packaging format, runtimes, storage, transport and so on. Increasingly, the tools and platforms available can be specialized and purpose-built for this new atomic unit of compute, giving rise to a thriving ecosystem around functions and serverless computing.
Now, by applying this unit to a few core software development concepts, we’re able to uncover additional units that make development easier. Applied to scaling, for example, functions enable us to scale out at a much finer-grained precision than traditionally, because individual processes can be singled out and scaled far more effectively by spinning up containers utilizing free resources.
Similarly, applied to billing, functions represent an exciting advancement, as instead of running servers or VMs for days or months, businesses can now effectively pay by the time consumed by a particular function, sometimes down to milliseconds. Not only does it enable cost reduction of lightly used apps, but also cheaper iterations on testing out app features in market, among other benefits.
Finally, functions packaged in containers with their own contract should be inherently shareable, so that composite applications can be built and reused at will, although this requires function orchestration tools.
While most people focus on the differences between containers and functions, the reality is that the full potential of both is achieved through combination. Now as more and more developers become familiar with the two terms, we’re hoping this better understanding will help bring the architecture and its benefits to the early majority, for both simple and complex applications.