Book Image

The Definitive Guide to Modernizing Applications on Google Cloud

By : Steve (Satish) Sangapu, Dheeraj Panyam, Jason Marston
Book Image

The Definitive Guide to Modernizing Applications on Google Cloud

By: Steve (Satish) Sangapu, Dheeraj Panyam, Jason Marston

Overview of this book

Legacy applications, which comprise 75–80% of all enterprise applications, often end up being stuck in data centers. Modernizing these applications to make them cloud-native enables them to scale in a cloud environment without taking months or years to start seeing the benefits. This book will help software developers and solutions architects to modernize their applications on Google Cloud and transform them into cloud-native applications. This book helps you to build on your existing knowledge of enterprise application development and takes you on a journey through the six Rs: rehosting, replatforming, rearchitecting, repurchasing, retiring, and retaining. You'll learn how to modernize a legacy enterprise application on Google Cloud and build on existing assets and skills effectively. Taking an iterative and incremental approach to modernization, the book introduces the main services in Google Cloud in an easy-to-understand way that can be applied immediately to an application. By the end of this Google Cloud book, you'll have learned how to modernize a legacy enterprise application by exploring various interim architectures and tooling to develop a cloud-native microservices-based application.
Table of Contents (26 chapters)
1
Section 1: Cloud-Native Application Development and App Modernization in Google Cloud
5
Section 2: Selecting the Right Google Cloud Services
10
Section 3: Rehosting and Replatforming the Application
17
Section 4: Refactoring the Application on Cloud-Native/PaaS and Serverless in Google Cloud

Applying the 12-factor app principles on Google Cloud

The 12-factor app is a set of 12 principles or best practices for building software-as-a-service applications. Written in 2011, 12-factor app is 12 important principles that can be followed to minimize the time and cost of designing scalable and robust cloud-native applications.

The 12 principles can be applied to any programming language and any combination of backing services (database, queue, memory cache, and so on), and is increasingly useful on any cloud vendor platform. However, to make these principles easier to follow as well as to help you apply them yourself, we'll discuss the principles in the context of Google Cloud and, more importantly, how you can apply the 12-factor app principles on Google Cloud

The 12 factors are as follows.

Code base

One code base tracked in revision control, many deploys.

Tracking code in a version-controlled system (VCS) such as Git or Mercurial has many benefits, such as the following:

  • Enabling different teams to work together by keeping track of all the changes to the code.
  • Providing developers with an intuitive way of resolving merge conflicts (and avoiding them to an extent).
  • Allowing developers to quickly and easily roll back the code to a previous version.
  • A single code base also helps simplify things when creating a CI/CD pipeline.

You can apply this principle to your process by using Google's Cloud Source Repositories, which helps you to collaborate with other members of your team as well as other developers while tracking and managing your code in a scalable, private, and feature-rich Git repository. It also integrates with other Google services, such as Cloud Build, App Engine, Cloud Logging, and more, which is quite handy.

Dependencies

Explicitly declare and isolate dependencies.

This principle translates into two best practices. First, developers should always declare any dependencies into version control explicitly. An explicit dependency declaration enables developers, especially those who are new to the project, to quickly get started without needing to set up too many things. It's also a good practice to keep track of changes made to dependencies.

The second practice suggested by this principle is to isolate an app by packaging it into a container. Containers are crucial to a microservices architecture as they are what keeps the app and its dependencies independent from the environment. As you package and isolate more and more dependencies, you can use the Container Registry tool to manage container images, perform vulnerability analysis, and grant access to users, among other things.

Config

Store config in the environment.

You might have only a handful of configurations for each environment when starting out, but as your application grows and develops, the number of configurations is going to increase significantly, which makes managing configurations for deployments a bit more complex.

To avoid this and ensure your application is architected to be as scalable as possible, you should store configuration in environment variables. Environmental variables (or env vars) can be easily switched between deploys and work with any programming language and framework. If you're already using Google Kubernetes to manage your microservices, you can also use ConfigMaps to attach various information, including configuration files, directly to the containers as well as the secrets manager service in Google Cloud to store sensitive information.

Backing services

Treat backing services as attached resources.

This principle states that developers should treat backing services (such as datastores, messaging systems, and SMTP services) as attached resources because we want these services to be loosely coupled to the deployments. This enables developers to seamlessly switch between third-party or local backing services without any changes to the code.

Build, release, run

Strictly separate build and run stages.

The software development process of creating a 12-factor app is divided into three stages: build, release, and run. Each stage creates a unique identification code that can be used to identify different stages of the development process with the main goal of creating an audit log.

So, at the first stage, a unique identification number is attached to the build. After that, we reach the release stage and the identification number of the build is attached to the configuration of the environment. Every release will have a unique ID in chronological order and since each change leads to a new release, these unique IDs can be used to track changes as well.

Processes

Execute the app as one or more stateless processes.

A 12-factor app completely avoids sticky sessions and instead uses stateless processes that can be created and destroyed without affecting the rest of the application. Developers can use backing services as a database or Google Cloud Storage to persist any data that may need to be reused.

Port binding

Export services via port binding.

Traditional web apps are written to run environments or servers such as Apache Tomcat, but since cloud-native applications are completely self-contained, they do not require such servers to listen to requests. Instead, they export HTTP as a service by binding to a port and listening to that port for requests.

When building apps on Google Cloud it's best to provide port numbers in the environment using env vars instead of hardcoding port numbers in your code to maintain portability in your apps.

Concurrency

Scale out via the process model.

12-factor apps are extremely scalable and to achieve the same level of scalability, it's recommended to divide your app into different types of processes and assign these processes to different types of works (background processes, web processes, worker processes, and so on).

App Engine, Compute Engine, Cloud Functions, and Kubernetes Engine all support concurrency, and thus it's highly recommended to follow this principle to make the most of your cloud-native application.

Disposability

Maximize robustness with fast startup and graceful shutdown.

A 12-factor app treats the cloud infrastructure, processes, and session data as disposable, and the application should be able to shut down and restart quickly and gracefully. This improves agility, scalability, performance, and user experience as processes can be moved between machines without any problems.

The level of disposability of your app depends on various factors, but you can do the following to make your app robust against startups and shutdowns:

  • Use backing services as attached resources to decouple functionality.
  • Limit the amount of layering in your container images.
  • Use native features of Google Cloud to perform infrastructure tasks when possible.
  • Leverage SIGTERM (stop) signals to perform graceful shutdowns.

Dev/prod parity

Keep development, staging, and production as similar as possible.

With traditional applications, development and operations teams had very different environments. The same cannot exist in cloud-native applications because speed is of the essence. Everything must be fast, smooth, and no time or effort should be spent on altering apps to suit different tools in different environments.

This becomes a little easier with cloud platforms that have a large ecosystem of auxiliary services. For instance, you can use Google Cloud's services for development, testing, staging, and production to maintain consistency across environments and also to speed up collaboration between teams.

Logs

Treat logs as event streams.

Logs are a great source of information about the performance and health of your apps. During development, developers will use logs as an important tool for monitoring the app's behavior. However, when your application is already running on public clouds, logs become unnecessary and come in the way of dynamic scaling.

Therefore, it's best practice to decouple logs from core logic instead of using other tools (such as the Cloud Logging agent) for the collection, processing, and analysis of tools.

Admin processes

Run admin/management tasks as one-off processes.

Admin processes should be decoupled from the core app to reduce maintenance and coordination. Google Cloud has many services built in to encourage this practice. For instance, you can use CronJobs in Google Kubernetes Engine to control the timing, execution, and frequency of admin processes using containers. Similarly, App Engine and Compute Engine have fully managed tools such as Cloud Tasks and Cloud Scheduler that help simplify admin processes.

The cloud-native platform (cloud vendor) and the cloud-native architecture have some very powerful benefits that developers must consider and leverage in order to utilize the full potential of cloud computing. To make this easier, developers can follow the framework of the 12-factor app until these principles and best practices become second nature.