Enterprise CIOs have been working on digitally transforming their IT infrastructure for a while now. Such digital transformations have traditionally been based on virtualization and Software-as-a-Service (or SaaS) offerings. With the development of cloud computing/ container technologies, transformational CIOs are looking into becoming cloud-native as well. But what is Cloud-Native?
The definition of cloud-native has evolved a lot in the past few years. It has evolved from a specific definition of applications to software architecture to design patterns to even team, technology, and culture. It also has evolved from being cloud-based (distributed, less stateful) to strictly container based (stateless, distributed, self-healing, micro-services based) to the higher level of abstractions such as Serverless. In this blog post, we will focus on design patterns and consumption patterns, not on culture.
The term ‘Digital Transformation’ informally refers to the application of digital technologies to transform how one runs business. It is an all-encompassing term that is applicable to Productivity Suites, data centers, to build pipelines to internal communications to customer experience, etc.. With developments in cloud computing/ container technologies, transformations based on such technologies have started influencing digital transformations so much that the term ‘Cloud-Native Transformations’ is increasingly being used to refer to ‘Digital Transformations’.
This blog post covers the evolution of cloud-native transformations and serves as a reference to future blog posts that discuss best paths to adopting such transformations from wherever one is at.
Waves of Digital/ Cloud-Native Transformations
The evolution of Cloud-native transformations can be best viewed as waves of successive abstractions rather than disconnected islands, with every abstraction developing upon the previous one. Even though these abstractions appear to be radically different from each other, each of them has also undeniably influenced and impacted the successive one. Every abstraction has resulted in a certain style of application design, thereby finding a niche set of applications more suitable for that abstraction. Following diagram captures these waves and shows their respective hype cycles/ hype peaks. One can also notice the increase in the shift towards application logic, away from the underlying infrastructure as the waves progress.
It is not hyperbolic to say that virtualization (CPU, storage, and network) set the tone for digital transformations. Through CPU virtualization technology, a virtualization-enabled physical server can ‘mimic’ multiple virtual servers, thereby increasing the amount of total number of resources it supports. With this came the promise of CapEx efficiency and cost savings.
Virtualization-based application design patterns largely followed patterns that were meant for physical servers — relying on highly available/ always available infrastructure, scaling up the infrastructure for heavier workloads, replicating physical network based isolation in virtual environments, etc. In essence, virtual machines were treated like physical servers (always on) and were expected to behave like physical ones. More often than not, enterprise IT organizations treated virtual machines like physical servers and followed same procedures for their life cycle management they employed for physical servers — for provisioning, installing/ updating operating systems, providing user access, securing through firewalls, network segregation, decommissioning, etc. Virtualization also enabled concepts of snapshots, live migration, backup & recovery, which went on to become core requirements of enterprise IT. Enterprises also standardized the delivery of such resources through processes such as ticketing, centralized control through a dedicated group (frequently referred to as the IT), etc.
Virtualization, in turn, enabled on-demand delivery of infrastructure resources (compute, storage, and networking) — AWS being the pioneer here, offering such capabilities since more than a decade ago.
In this model — called Infrastructure-as-a-Service (IaaS), one can consume a resource such as a virtual machine, whenever one wanted. Google and Microsoft also pioneered another type of as-a-service delivery — Platform as a Service (PaaS), at a level of abstraction higher than IaaS. In this model, one can directly consume an application environment (say a web server), instead of worrying about the underlying infrastructure (servers)that would power this environment.
These as-a-service delivery mechanisms were broadly classified as ‘Cloud’, key characteristics being (assumption of) infinite capacity, on-demand availability, and elasticity. When such services were offered by a third party provider from a location outside of the customer’s location/ data-centers (off-premises), they were commonly referred to as ‘Public Cloud’ and when they were delivered in-house from inside of the customer’s location/ data-centers (on-premises), ‘Private Cloud’.
These as-a-service delivery models enabled new consumption patterns — self-service/on-demand provisioning, against what has then become a common practice among enterprises — ticketing based, centrally controlled provisioning. Such as-a-service offerings changed the discussions from CapEx to OpEx.
A container (Linux or Windows) is an isolated, self-contained run-time environment which runs as a process on a host machine or virtual machine. A container contains necessary and sufficient dependencies and configuration files in order for an application to run. A container behaves just like a virtual machine in the sense that it appears to be a complete system, without the need for an entire operating system. Since a container doesn’t need the entire operating system, it operates much faster than a virtual machine.
Linux Container technology has been around for a decade now, but Docker Inc enabled packaging of the dependencies and configuration files more efficiently than ever before through ‘Docker Containers’. Such efficient packaging mechanism enabled developers to develop, deploy, and scale applications faster. This ease of use and efficiency captured the imagination of developers unlike ever before, so much that ‘Docker’ soon became synonymous with ‘Containers’.
Containers influenced design patterns that leveraged faster, efficient and smaller run-time environments. Faster startup/ shutdown times also meant applications no longer need to be worried about re-starts. In other words, an application could re-start in case of a failure/ crash with very less performance impact. This marked a considerable shift in the dependency on underlying infrastructure on ‘availability’. With physical servers and virtual machines, the applications expected them to be always available. With containers, the applications need not (or sometimes couldn’t) have such dependency. This meant that applications need to be more prepared in case of unavailability of the underlying infrastructure. In other words, they need to be more fault-tolerant. Lack of appropriate storage abstraction in the early days of this phase also meant applications tended to be almost state-less/ or less stateful.
Since each container is self-contained without any additional overhead, it could serve as a complete application or a part of an application, which could work with the rest of the application served by one or more containers. This provided a natural way to break down applications into smaller functions/ services — a pattern commonly referred to as ‘micro-services’.
These factors influenced a new application design pattern characterized by stateless (or less stateful), fault-tolerant, distributed, and micro-services based applications.
Containers, at scale, needed to be orchestrated together, bringing up the need for a container orchestration platform. While multiple such platforms came into existence, the industry appears to have standardized around Kubernetes.
Container-based application development introduced newer consumption pattern — CaaS (Containers as a Service), in both private and public cloud environments.
As the waves progress, one can observe that focus gradually shifts away from the underlying infrastructure and more towards the application itself. Continuing this trend is the wave of ‘Serverless Computing’, which refers to a computing paradigm in which developers can focus on the application code/ logic without having to worry anything about the infrastructure required to support/ power this logic.
Serverless computing was enabled by the availability of services which enable executing a slice of code, triggered by an event of a predetermined type. This ability is broadly categorized as Function-as-a-Service (FaaS). Services such as AWS Lambda, Azure Functions fall under this category. Platforms such as OpenWhisk enable one to build a FaaS platform on on-premises infrastructure.
Serverless application design patterns are characterized by two key factors — Event-Driven and Micro-Services. They also don’t expect any native storage abstractions (such as mounted volumes, file systems, etc) to be present, but consume storage-as-a-service offerings (DBaaS, object storage as a service, etc.). In theory, one could also mount a volume on a network share and expose that to these serverless applications, but there are less compelling reasons to do so.
Some include ‘Serverless Containers’ (services such as Amazon Fargate) under the Serverless computing category because they enable one to focus on applications (containers) without having to worry about the infrastructure (cluster) below. One might argue then, that managed infrastructure services (like Amazon EKS, Rackspace Managed Cloud etc.) can also be called Serverless since they don’t require one to manage the underlying infrastructure. For our purposes of design patterns leveraging Serverless Containers are not included under the Serverless Computing pattern as they were discussed under Containers.
Application Design Patterns
The successive waves of cloud-native transformations have influenced distinct application design patterns that leveraged the strengths of each transformation. Design patterns also evolved as the waves progressed.
Applications during early days of digital transformations tended to be monolithic (for example, a 3 tier web application). A typical 3 tier web application had a presentation layer (front end), an application layer, and a database layer. Design patterns then focused on making these individual components highly available (through redundancy) and scalable (through vertical scaling). These patterns continued during virtualization phase as well.
As cloud-based services became available, compute design patterns evolved to leverage the elasticity and scale that cloud-based services provided by being distributed, elastic, and less stateful. This is when application patterns such as Twelve-Factor App found more adoption. This is also when design patterns evolved to consume storage options available as a service rather than relying on locally available storage devices.
As containerization gained momentum, compute design patterns evolved to leverage the agility that containers provided through micro-services. Ephemeral nature of containers (without the right level of storage abstraction during the early days) also influenced stateless or almost stateless design patterns.
With serverless computing, compute design patterns have evolved to be event-driven and micro-services based.
Continuing the evolution of compute design patterns, we expect that the next iteration of design pattern would be similar to a better version of PaaS (which we call as PaaS 2.0 in order not to introduce new jargon) where one can focus on the application of one’s choice without having to restrict to a certain type (micro-services, event-driven, stateless etc).
It is also interesting to observe how storage design patterns have evolved, along with compute design patterns. Both compute and storage patterns have influenced each other all along, but one can see that as waves progressed, storage is becoming more influential (Data Gravity!)
During the early days of digital transformations, applications relied heavily on the underlying infrastructure for their high availability. This requirement of high availability reflected in storage design patterns as highly available, special purpose, storage appliances with redundancy, recovery/ automatic failover, etc.. Developments in storage virtualization further enhanced these patterns so much that enterprise customers wouldn’t consider any storage options that didn’t have these capabilities.
As cloud-based services evolved, various storage capabilities also started to be available as a service (such as block store as a service, object store as a service, databases as a service, etc.). Compute design patterns evolved to leverage these storage capabilities available as a service.
Storage design patterns for containerized applications have taken an almost full circle. Due to the lack of proper storage abstractions and ephemeral nature of containers, application design patterns tried to be stateless. Soon, the industry realized that not all applications can be stateless and more importantly, applications that enterprise cared the most were not stateless. Storage abstractions to enable running such applications within containers evolved — such as Stateful Sets and Persistent Volumes. These abstractions provide a way to attach or detach a storage volume to a container and if needed, data written to such volumes can be persisted even after the lifetime of containers.
While we are not fans of such retrofitted designs, it is important to observe that they enable containerization of a certain type of applications that are limited by their storage layer/ backends.
Serverless applications, don’t expect the presence of native storage options (such as mounted volumes, C:\ etc.). They consume storage-as-a-service options such as Amazon S3, Azure Blob Storage etc. We don’t expect any service provider to provide block storage abstractions (like attach/ detach volumes) to Serverless applications as it would be anti-thesis of their design patterns.
What’s next — Transformation Best Practices
No matter where one stands in their digital transformation journey, more transformation is possible. In the following posts, we will cover transformation best practices that optimize individual transformations based on where one is at.