Many businesses begin their cloud migration by replicating their hosted environment. The software on a couple of servers is copied into machine images and deployed as virtual servers in an account using AWS' EC2, Azure's Virtual Machines, or Google's Compute Engine. Network rules are set up to ensure that only the customer-facing virtual servers are externally accessible, just as data center servers are firewalled from the outside world. When it's time to update your software, you have some downtime while your virtual server's software is shut down, updated, and restarted.
If your cloud experience ends here, you'll be left wondering what all the fuss is about. Although there may be some cost savings, and it is certainly faster to spin up an EC2 instance than to order and install a new physical server, the actual day-to-day work for your developers and operations teams does not change significantly. This is due to the fact that you have not adapted your tools and processes to take advantage of what the cloud has to offer. In short, your software is not yet cloud native.
What Exactly Is Cloud Native?
But what exactly is "cloud native"? What does it imply? The Cloud Native Computing Foundation, or CNCF, was founded as a branch of the Linux Foundation with the goal of "making cloud native computing ubiquitous."
They lead many of the projects that enable cross-platform cloud native software and have developed a definition of cloud native:
Cloud native technologies enable businesses to develop and deploy scalable applications in modern, dynamic environments such as public, private, and hybrid clouds. This approach is exemplified by containers, service meshes, microservices, immutable infrastructure, and declarative APIs.
These techniques enable resilient, manageable, and observable loosely coupled systems. When combined with strong automation, they enable engineers to make high-impact changes frequently and predictably with little effort.
Let's go over the most important terms there, see what they mean, and then walk through the cloud native platform tools that allow us to build cloud native systems.
The Key Principles of Cloud Native Software
The design of cloud native software is guided by 5 key principles. Understanding them is essential for developing software with a cloud native architecture:
Let's begin with scalable. One of the primary reasons for moving to the cloud is scalability. The most significant disadvantage of running your own data center is the lengthy time it takes to acquire and configure new hardware. This means you must reserve servers based on an estimate of how much capacity you will require on your busiest day. If your business has a busy season, you will have expensive excess capacity for the majority of the year. Worse, if you underestimate demand, your website will stop working just when you need it the most.
Making your services scalable will almost certainly necessitate changes to your developers' software. This can be difficult because it frequently necessitates rethinking how your applications are designed. The payoff, however, is well worth it.
The first step is to divide a large application into microservices. While a monolith can be run in the cloud, you cannot increase resources for a single component of a monolith; it is all or nothing. You can scale different functional areas of your application at different rates with microservices, depending on what they require.
In this post, you can learn more about microservices: 7 Microservices Advantages and How They Affect Development
When you've decided on microservices, the next step is to consider putting those microservices in containers. Docker popularized the concept of packaging software into immutable bundles and running them in isolation, without the need for a full operating system for each service. Because of the distinction between containers and virtual machines, you can run many more containers on the same underlying hardware than you could with VMs.
What distinguishes a cloud-native microservice?
There is nothing in microservices or containers that prevents them from being deployed in a data center. The issue is that you must still allocate and manage the underlying servers that house them. A cloud native microservice makes use of a cloud provider's services. Running in the cloud eliminates the need to worry about the state of your server's network cards and fans, and a cloud-native architecture eliminates the need to worry about allocating virtual servers.
Certain design principles govern cloud native microservices. The most important aspect is that they are intended to be stateless, immutable infrastructure.
This implies two things:
- The container that hosts your microservice stores no data.
- You do not modify a container once it has been launched.
This raises the question of how updates are made. In a cloud native architecture, whenever you want to change a cloud native microservice, you launch a new instance with the updates and shut down the old one. This is in contrast to the older method of performing updates on a single server. The practice is ostensibly referred to as the distinction between pets and livestock.
Developing cloud-native architecture
You're well on your way to building a cloud native architecture once you've created these immutable instances. Your teams can now use cloud provider services to increase the scalability of your systems. When no single server instance is unique, you can use cloud provider auto-scaling services or configure your environment to automatically add and remove virtual server instances as your system load changes.
Breaking down your services into smaller components can lead to increased scalability. In some cases, a cloud native microservice can be reduced to a single function. AWS refers to these as Lambdas, Google refers to them as Cloud Functions, and Azure simply refers to them as Functions. These are even easier to package than containers, often consisting of just a zip file containing some code. Your operations team only needs to configure the maximum number of functions that can run concurrently and how much memory each one should have. The cloud provider handles allocating the underlying machines and automatically scaling them up and down (and even off). These functions are frequently much more cost effective than a container that runs all of the time for infrequent processes or services with bursts of requests.
Cloud native architecture for scaling functionality
The benefits of cloud native architectures go far beyond the ability to scale the business logic of your application. Even if your infrastructure is stateless and immutable, your data must still reside somewhere. While third-party databases could be run on virtual servers, a cloud native architecture uses databases hosted by cloud providers themselves. All three of the largest cloud providers offer MySQL, Postgres, and Oracle, but only Azure offers a hosted version of Microsoft SQL Server. Because your cloud provider manages hosted databases, it's simple to allocate additional resources as needed, such as disk, memory, and CPU, scaling over time as your needs change.
You can also consider other non-relational data storage methods. S3, or Simple Storage Service, was one of AWS's first offerings. It allows you to organize files into "buckets" (Azure calls their version of this service Blob Storage and Google calls it Cloud Storage). Document databases, noSQL databases, graph databases, data warehouses, and even private blockchains are available. The ability to access these alternative data stores via an API is extremely useful. Your teams can find better solutions to their problems much faster and cheaper than they could in a self-managed environment.
As your teams gain confidence, they will look for new ways to focus on your company's core competencies. Consider the customer's identity. Instead of managing this information yourself, cloud providers (as well as third-party companies) offer identity management solutions based on standards such as OAuth2 and OIDC. There are similar solutions for other enabling technologies, such as machine learning or batch processing. Cloud native architectures not only scale your software, but they also scale the capabilities of your development team by allowing you to focus on what you do best.
Another important aspect of a cloud-native architecture is its resilience. What exactly does this mean? According to Matthew Titmus in "Cloud Native Go":
The resilience of a system (roughly synonymous with fault tolerance) is a measure of how well it withstands and recovers from errors and faults. When a component of a system fails, it is considered resilient if it can continue to function correctly (albeit at a reduced level) rather than failing completely.
Just as you must modify your software to make it more scalable, you must also modify it to make it more resilient. There are huge payoffs when you make your systems more resilient, similar to scalability, because they stay running and teams aren't scrambling to fix problems.
There are numerous excellent resources that discuss techniques for improving service resilience. (Unsurprisingly, "Cloud Native Go" is a must-read for teams developing cloud-native software in Go.) These patterns revolve around the flow of data through your services. When it comes to data entering a service, you should limit the amount of data to what can be processed in a reasonable amount of time. If there is too much traffic, load must be reduced in order to respond to the remaining requests in a reasonable amount of time. When your service requests data from another service, it must be designed to handle the inevitable errors and timeouts.
Cloud providers also provide some tools to aid in resiliency. Scalability and scalability overlap. If a microservice fails due to a rare error, an autoscaler can restart it. Autoscaling enables your systems to absorb rather than shed load. Other cloud provider tools can also be useful. When you use cloud-managed databases or data processing platforms, you can quickly increase their resources if they require more CPU or storage.
Cloud providers also enable you to increase resilience by distributing your services across multiple regions. A region is a geographical area that contains one or more data centers, such as the United States' East Coast or So Paulo, Brazil. Each data center within a region is assigned to one of several availability zones. It is recommended that you launch services across multiple availability zones to ensure that a failure in a data center does not cause an outage for your company. Following statelessness principles and treating your servers as livestock ensures that your system will continue to function even if a single availability zone or region fails. Furthermore, if you use a cloud provider's data store, it can automatically replicate data across availability zones and even regions.
Another important aspect of cloud-native computing is its manageability. All of these components can be viewed through a UI or their status can be queried through an API. Because you have an API for discovering and changing the state of your environment, you can write tools to do this work in a repeatable manner. It also means you can describe the environment in a script and then run it to deploy, update, or delete your components. AWS provides a tool called CloudFormation for this, but many businesses manage their environment with Terraform, a cross-platform tool from Hashicorp.
Observability is closely related to manageability. When you have multiple components running concurrently, you want to know what they are doing. You also want to be notified if something goes wrong. Even if your developers design for resiliency, your operations team still needs to be aware of problems as soon as they occur in order to prevent the situation from worsening. To provide this functionality, Amazon offers a service called CloudWatch. CloudWatch collects data from AWS about how your application is running as well as metrics about how well it performs. Furthermore, your application's logs can be sent to Cloudwatch, allowing you to see information from your code alongside AWS data.
(Azure offers a similar service called Monitor, which includes a component called Application Insights for collecting application telemetry, whereas Google offers Cloud Monitoring.)
In addition to watching your systems as they run, it's a good idea to watch the API calls to your cloud provider that configure your system. These calls can tell you if your systems are properly configured and can possibly detect malicious activity. AWS reports on API calls using CloudTrail, Google has Cloud Audit Logs, and Azure's Monitor service tracks both API calls and application performance.
Finally, to ensure consistency in your cloud environment, you must rely on automation. Automation connects all of our cloud native principles. We can scale because we automate the deployment of immutable infrastructure. Systems are more resilient when they can be restarted automatically in the event of a failure or when they automatically fail over to a backup system when a problem in a dependency is detected. Automation allows you to keep track of what is running, and it also allows you to detect when your observable systems are misbehaving.
There are additional ways in which automation enables cloud native software. When releasing new versions, you don't want to have a system administrator manually install software. Instead, use deployment pipelines that automate the build, test, and deployment processes, such as AWS' CodePipeline, Google Cloud Build, or Azure Pipelines. Automation ensures consistency and allows you to do things like test a new version of your software on a small subset of your servers to ensure it works properly.
Automation not only improves the deployment experience for cloud-native software, but it also aids in the management of your environment. You must ensure that all of your software's components are properly configured. This includes tasks such as validating access permissions, ensuring that only customer-facing applications are exposed to the public internet, and ensuring that all of your cloud resources are properly tagged with information to identify which team owns them. You may also want to implement cloud cost-cutting measures such as turning off components in a QA environment while engineers are sleeping and turning them back on when they return to work.
Migrating to the Cloud is worthwhile
As you can see, the goal of developing cloud native applications is not to keep up with the latest buzzwords. Following these principles and redesigning your applications with a cloud native architecture, your company will be able to produce more reliable software that better serves the needs of your internal teams and customers.
This will be difficult for businesses that have invested in a data center and older technologies.
As companies did 100 years ago when they switched from steam to electricity, becoming cloud native requires your developers and operations teams to make changes as they improve the scalability, resilience, maintainability, observability, and automation of your software and its environment. It necessitates changing some development patterns and embracing a cloud native architecture by utilizing cloud provider tools.
However, the payoffs are spectacular.
Need help optimizing your Cloud infrastructure costs? Our 24/7 certified Cloud team can help you get costs under control today! Contact us for a free consultation.