Building a Cloud Native Twelve-Factor App on Choreo: Just Write the Code
By Shehan Dias
- 24 Aug, 2022
The Twelve-Factor Application is a methodology that describes principles and practices to create cloud native applications. Applications built following this methodology are portable across environments, can be deployed and scaled rapidly, and makes it easier to quickly react to market changes by adding new features.
Choreo is an internal developer platform that lets developers build cloud native applications that conform to the twelve-factor application methodology. Choreo makes developing and deploying applications simpler and faster by automating the steps to make applications cloud native.
In this article, we will look at how Choreo takes care of each element of the twelve-factor application methodology, plus three more factors that are important to modern cloud native application design.
A single codebase for each microservice, tracked with version control that can be deployed to many environments.
Each artifact created on Choreo is represented as a component under a given project, and each component gets its own source code repository on Github, out-of-the-box. Developers can connect their enterprise (or personal) Github repositories to maintain the source code of their components.
Choreo can deploy components developed to runtime environments (i.e., dev or prod) with a single click. Developers can pick commit IDs of the source repo to perform deployments, thereby allowing multiple deployments of the same source, including rolling back to earlier revisions as well. Figure 1 shows a component in Choreo.
Figure 1: Component in Choreo
Each microservice should isolate and package its own dependencies.
Choreo packages all executables into self-contained containers. This ensures that no implicit dependencies leak into the application runtime. Containerization of code happens transparently from the developer and therefore places no burden on the developer, nor does it require the developer to have any knowledge about this process. Developers can also take the code and run it elsewhere without issues.
Ballerina provides a dependency declaration manifest for developers who use Ballerina to implement components on Choreo. Ballerina executables pack all dependencies into a single Ballerina archive, which provides dependency isolation. All dependencies and their versions are declared in a configuration file. The dependencies are illustrated by Figure 2.
Figure 2: Dependencies in Choreo
Configuration information should be externalized and moved out of the microservice.
Choreo provides a first-class mechanism to externalize configurations from the source code. When developing components on Choreo using Ballerina, developers can declare configurable parameters using a special variable type called configurables.
Configurables are intended to hold values that are sensitive or values that can change based on environments. The component runtime engine in Choreo ensures that:
This saves a lot of developer time that would otherwise be spent figuring out how to externalize configurations, secure them, and inject them at runtime. Figure 3 shows an image of what configurables look like in Choreo.
Figure 3: Configurables
Backing services should be treated as attached resources.
Most services developed today depend on one or more attached resources such as a database, caching service, messaging service, or another API that can be accessed over the network. Choreo’s built-in Marketplace allows developers to easily discover and program using such attached resources.
The Choreo Marketplace contains third-party APIs, datastores, caches, message brokers, and more. Everything in the Marketplace has its own addressable URL that decouples it from the service it uses. By using the configurables support mentioned above, attached resources to a service can be easily swapped at runtime with no code changes and more importantly, without any burden on the developer as well. Figure 4 illustrates the Marketplace.
Figure 4: Marketplace
Build and run stages should be strictly separated.
The built-in CI/CD pipeline in Choreo ensures that any component developed on Choreo goes through a build → release → run workflow before it’s deployed to a runtime environment. Within Choreo, the build phase compiles the code, the release phase binds values to the relevant configurations, and the run phase deploys and starts (or schedules) the component in the relevant runtime environment. All this is done with just one click.
In addition, releases of Choreo components are immutable. Any change to the code base needs to be deployed as a new release. Each release comes with a unique build ID, which allows you to roll back to any previous build as well. Figure 5 shows what the build, release, and run workflow looks like.
Figure 5: Build, Release, Run
The application should be executed as one or more stateless processes isolated from other running processes.
Each component you develop and deploy in Choreo will be independent of other components. Choreo tracks each component’s state and runs it in its own Docker container as an isolated process. Choreo provides easy access to backing services through its Marketplace and configurables, encouraging developers to easily externalize states and configurations.
Processes in Choreo are created as components. These components can be of different types such as microservices, different types of APIs, scheduled jobs, or triggers (integrations). This factor is particularly important for microservices and APIs, for which autoscaling is a key requirement.
Each service should be self-contained and exported via port binding.
Each service in Choreo gets bound to a port by default, without any explicit attention required by the developer. Each service is completely self-contained and does not require runtime injection of a web server. At development, the service can be accessed via a URL that looks like https://localhost:8090. When the service is deployed into its relevant environments, a routing layer handles routing requests from a public facing host to the port bound address.
Services should be scaled horizontally on demand across multiple identical processes.
Every service you deploy on Choreo runs on a container in a Kubernetes cluster. Choreo provides a platform where every service you deploy on it can scale horizontally when needed. So, if you have a sudden surge of traffic to your service, Choreo will scale out your service by increasing the number of replicas it runs. When traffic returns to normal, Choreo will scale your service back in by gracefully shutting down the extra replicas it spawned. Choreo inherits the auto-scaling functionality offered by Kubernetes to make services horizontally scalable. It also supports auto-healing. In the event a service instance crashes, it would be brought back up based on the number of minimal replicas requested by the configuration.
Maximize robustness with fast startup and graceful shutdown.
Services deployed on Choreo can be started or stopped at a moment’s notice. Choreo’s concept of projects and components guides developers to design right-sized (usually smaller) microservices that makes them easier to boot up fast.
When Choreo receives a shutdown (undeploy) signal, Choreo components stop receiving any new traffic to the service and complete serving whatever requests it has already accepted. This way, developers get graceful shutdowns for their services out of the box. Inheriting Kubernetes capabilities, Choreo supports rolling updates which allows developers to make changes to their services with no impact on user traffic.
Keep development, staging, and production environments as similar as possible.
The twelve-factor app highlights three major challenges with having multiple environments.
a. Time taken to deploy code - Code takes too long to get into production.
b. Different personas being involved in the process - A developer writes code, an Ops engineer does deployments, and the developer has no visibility into what happens at deployments.
c. Differences in infrastructure and backing services - Different environments run on various resource allocations and services being bound to different backing services on different environments. For example, using MySQL in the development environment while using Postgres in production.
Choreo provides clean solutions that automatically tackles all three challenges seamlessly.
Figure 6 displays the environments in Choreo.
Figure 6: Environments in Choreo
Treat logs generated by services as event streams.
Developers on Choreo do not have to concern themselves with routing or storage of the output stream of their services. Instead, Choreo writes each event stream to stdout, which is then streamed to a log processing engine for storage and indexing. Developers get a comprehensive UI for viewing, searching, and even downloading logs of their services, all with no extra effort. Figure 7 shows an image of the logs.
Figure 7: Log
Run admin/management tasks as one-off processes.
Every component developed on Choreo is deployed on a Kubernetes cluster either as a service or a job. Jobs can be scheduled to run periodically or as one-time tasks. The twelve-factor app defines admin processes as one-time execution tasks that should be run. Choreo supports these out-of-the-box as one-time execution jobs, and they can be run on the same environments as other services. Figure 8 shows an admin process.
Figure 8: An Admin Process
In addition to the above factors discussed in the Twelve-Factor application methodology, we believe there are three more that should be considered. These come from the book, Beyond the Twelve-Factor App. Let’s find out what they are and how Choreo incorporates them.
Make everything a service.
Any service-type component created in Choreo has an interface. These could be REST, GraphQL, gRPC, WebSockets, etc. Developers must associate the interface specification to the type of service they are developing. Choreo also allows exposing these services to either internal or external consumers.
Include monitoring domain specific and health/system data.
Choreo provides deep observability that provides logs, tracing, and metrics to troubleshoot your components. Choreo represents these data visually to make it easy for the developer to troubleshoot their components. It also provides business insights to help organizations relate technical KPIs to business performance. This is shown by Figure 9.
Figure 9: Observability in Choreo
Implement identity from the start.
Security is not an afterthought on Choreo. Instead, it gives organizations a zero-trust environment by making every component deployed on Choreo secured by default. Choreo enforces security on components without requiring explicit attention by developers, even for those with little or no knowledge about how to secure their components, Choreo assumes default levels of security and applies them so their components are always secure.
Choreo comes with two API gateways out-of-the-box: one for internal API exposure and one for external API exposure. When exposing APIs, Choreo supports API keys and OAuth2.0 security. For end-user authentication of APIs, Choreo allows you to use Asgardeo or any other IDP as shown by Figure 10.
Figure 10: External IDPs in Choreo
Choreo aspires to make cloud native application development simple and efficient. It allows application developers to focus on their business logic code while automating everything else. Choreo takes care of all the factors presented by the Twelve-factor application methodology plus three more. Applications built on Choreo are portable across environments and cloud providers.
Sign up by visiting Choreo today!