12 Factor App Principles with Cloud-Native Microservices
The 12-factor app is a technique or collection of principles for creating business applications that are performant, scalable, autonomous, and resilient. It defines the general guidelines and principles for developing business applications that are reliable. Since it aligns with Microservice principles, the 12-factor app principles have become very common.
The 12-Factor Principles
- Codebase (Many deployments from a single codebase that is monitored in revision control. )
- Dependencies (Declare and isolate dependencies explicitly. )
- Backing Services (treat backing resources as attached resources)
- Config (Store configurations in an environment)
- Dev/prod parity (Keep development, staging, and production as similar as possible)
- Processes (run the app as a single or multiple stateless processes )
- Build, release, and Run (separate build and run stages)
- Concurrency (Scale more via the process model)
- Admin processes (Run management tasks as one off processes)
- Port Binding (Export services through port binding)
- Disposability (Increase the robustness of your system with fast startup and graceful shutdown. )
- Logs (Treat logs as event streams)
1. Codebase (Many deployments from a single codebase that is monitored in revision control. )
Every application should have its own codebase, according to the 12-factor app (repos). It’s best to avoid having multiple codebases for different models.
Please note that having branches are acceptable. To put it another way, there should only be one repository for all deployment environments, not many.
The twelve-factor is broken when multiple applications share the same code.
From the standpoint of a 12-factor app, deploy refers to a running instance of an app, such as development, staging, or QA. In addition, each developer has a copy of the app installed in their local development environment, which counts as a deploy.
Multiple deploys which have different versions (a version is a code update that is available in one environment but not in another).
Microservices : every service in a microservices architecture should have its own codebase. Having a separate codebase makes the CI/CD process for your applications much easier.
Twelve-factor apps believe that code should not be shared between applications. If you want to share, you’ll need to build a library, add it as a dependency, and manage it with a package manager like Maven.
2. Dependencies (Declare and isolate dependencies explicitly. )
It describe using dependency management tools to handle dependencies rather than adding them to the codebase.
Gradle can be thought of as a dependency tool. All dependencies/libraries will be listed in the build.gradle file, and your program will download all of them from the repositories.
You must also understand the dependencies from the standpoint of the operating system and execution environment.
Microservices: Package managers such as sbt and maven can be used to control all framework packages.
3. Backing Services (treat backing resources as attached resources)
A backing service, according to the 12 factor app principles, is an application or service that the app uses over the network as part of its daily activity.
Backing services include databases, message brokers, and all other external networks through which the app interacts.
The 12-factor app will automatically switch from one service to another without requiring any additional changes to the code base.
Let’s say you want to move from Aurora to MySQL database server. You don’t need to require any source code changes to your system to accomplish this.
This possible to fix it with just a configuration adjustment.
Microservices: Everything external to the service is considered as an attached resource in a microservice ecosystem. The resource can be switched out at any time without disrupting the operation.
The interfaced dependent programming allows for dynamic provider swapping without affecting the device. You can also support several providers with a plug-in-based implementation.
4. Config (Store configurations in an environment)
Configuration refers to something that differs between deployment environments. This contains the following:
- Endpoints for device integration, database links and passwords
- External service credentials, such as Amazon S3 or Twitter, as well as any other external apps
- IP addresses, ports, and hostnames are examples of application-specific details.
Some configuration values should not be hardcoded as constants in the codebase. This is a clear breach of the values of the 12-factor app.
The configuration values should be saved in the environment variables, according to the 12-factor app principles.
It promotes a clear distinction between code and configurations. Regardless of where the program is deployed, the code must be the same.
What differs from one environment to the next must be transferred to configurations and controlled through environment variables, according to “config.”
Microservices: Decouple the application’s settings. You can manage the settings for your applications in a microservice service environment using a source control system like git (spring-cloud-config) and use environment variables to avoid storing confidential information in the source control.
5. Dev/prod parity (Keep development, staging, and production as similar as possible)
The twelve-factor approach recommends minimizing the distance between the creation and production environments.
This lowers the chances of bugs appearing in a particular setting.
Between creation and production, the twelve-factor developer avoids the temptation to use various backing services.
Microservices: This is a built-in function of microservices that use containerization techniques to operate.
6. Processes (run the app as a single or multiple stateless processes )
As a method, the app runs within the execution environment.
To satisfy user/customer demands, an app may have one or more instances/processes.
According to the 12-factor rules, the program need to save the data to a store and use it from there instead of storing it in memory.
In terms of state, the application can store it in the database rather than in the memory.
Sticky sessions are a breach of the 12-factor app rules and should be avoided.
If you want to save session data, you can use redis, memcached, or any other cache provider that meets your needs.
Your app will be highly scalable without affecting the framework if you obey these guidelines.
Microservices: By embracing REST’s stateless design, the services can be horizontally scaled to meet changing needs with no downtime.
If your device still needs to keep track of state, use the attached resources (redis, Memcached, or datastore) rather than in-memory storage.
7. Build, release, and Run (separate build and run stages)
The create, release, and run stages of the application must all be kept separate. Let’s take a closer look at each point.
Build stage: convert the code into a build package/executable bundle
Release stage: combine the build kit from the build stage with the deployment environment’s settings to make your application ready to run
Run stage: It’s the same as if you ran your app in the execution environment .
Microservices: You can simplify the deployment process with CI/CD software. Docker images make it simple to further isolate the create, release, and run stages.
8. Concurrency (Scale more via the process model)
This refers to the application’s scaling. Twelve-factor app concepts mean that instead of running the application as a single big method, you should consider running it as multiple processes/instances. Threads can also be enabled to enhance the concurrent handling of requests.
In a nutshell, the twelve-factor app guidelines encourage users to choose horizontal scaling over vertical scaling.
Horizontal scaling (increasing the number of instances of the app)
Microservices: Containerization allows systems to scale horizontally in response to demand.
9. Admin processes (Run management tasks as one off processes)
As part of the application implementation, there are a range of one-off processes such as data migration and running one-off scripts in a particular environment.
According to the Twelve-Factor Rules, such administrative functions should be held in the repository as part of the application codebase.
One-off scripts would then follow the same procedure as the rest of your codebase.
Make sure one-time scripts are automated so you don’t have to worry about manually running them before releasing the build.
The execution environment’s built-in tool can also be used to run such scripts on production servers, according to the twelve-factor principles.
Microservices: Containerization helps in this area by allowing one-off processes to be run as a job and then shut down automatically once the implementation is complete.
10. Port Binding (Export services through port binding)
The twelve-factor app is self-contained and does not depend on a webserver being injected into the execution environment at runtime to create a web-facing service.
By binding to a port and listening for requests coming in on that port, the web app exports HTTP as a service.
In a nutshell, this means that instead of deploying the application to one of the external web servers, you can run it on its own.
Microservices: By default, Spring Boot includes embedded Tomcat, Jetty, or Undertow.
11. Disposability (Increase the robustness of your system with fast startup and graceful shutdown. )
The processes in the twelve-factor app are disposable, which means they can be started or stopped at any time.
An instance does not affect the application state while it is shutting down or starting.
The importance of graceful shutdowns cannot be overstated.
The framework must ensure that the state is right.
When new instances are introduced or existing instances are taken down as required, the system should not be impacted.
Disposability of a device is another term for this.
Systems fail for variety of causes.
The framework should make sure that the effect is negligible and that the application is saved in a usable state.
Microservices: Through incorporating containerization into the microservices implementation phase, the application complies with this concept to the greatest extent possible.
Docker containers can be started and stopped in a matter of seconds.
In the event of a container crash, state, storing request, or other backing services or session data in queues ensures that a request is handled seamlessly.
12. Logs (Treat logs as event streams)
When it comes to troubleshooting production problems or understanding user actions, logs are important.
Logs provide insight into a running application’s actions.
The twelve-factor app principles support for separating log creation and log processing.
The system logs will be written as a standard output, and the executing environment will handle the capturing, storaging, curation, and archiving of such streams.
Microservices: Observability is a first-class citizen of Microservices. APM tools (ELK, Newrelic, and other tools) or log aggregation tools (Splunk, logs, and other tools) may be used to achieve observability.
To debug a problem, simply go to your tool’s central dashboard and check for it by following the above-mentioned guidelines.