Are You 12-Factor Application Ready?
Design modularity and flexibility into your applications with the 12-Factor design process.
Join the DZone community and get the full member experience.Join For Free
There are a lot of frameworks in app development, but not all of them are tailored for today’s cloud environment. Many of them lack modularity and flexibility; some don’t even leverage the benefits of using cloud computing. The 12-Factor application principles are designed specifically for modern, containerized cloud environments from the beginning. Each component is tailored to the flexibility of containers and cloud deployment, all while creating a standard for every team member—and third-party developers— to follow.
At the same time, the 12-Factor app creates a more straightforward approach to developing a cloud app with microservices. It takes into account the need for a positive user experience and how virtual environments can be utilized for higher availability.
So, the big question is: Are you 12-Factor app ready?
12-Factor Application Principles of Design
The 12-Factor app methodology has one main objective: to make the created app completely agnostic to cloud environments and dependencies. By achieving this objective, the app can be deployed in different virtual environments without the need for specific drivers or requirements.
You may also enjoy: The Twelve-Factor App: What It Is and How to Monitor It
The 12-Factors governed by this methodology are basic factors that determine the scalability and flexibility of your app. They are:
1. Base Code
By using a uniformed codebase, apps can be deployed in different environments by customizing the configuration files rather than the apps or microservices directly. 12-Factor app config is the only thing you need to customize, too; not the actual environment. As the 12-Factor website puts it, “A twelve-factor app is always tracked in a version control system, such as Git, Mercurial, or Subversion. A copy of the revision tracking database is known as a code repository, often shortened to code repo or just repo. A codebase is any single repo (in a centralized revision control system like Subversion), or any set of repos who share a root commit (in a decentralized revision control system like Git).”
Package managers are the better, more efficient way to go when it comes to managing dependencies. Instead of adding dependencies to the codebase directly, you will have an easier time reproducing deployment across environments with a package manager. Moreover, “A twelve-factor app never relies on the implicit existence of system-wide packages. It declares all dependencies, completely and exactly, via a dependency declaration manifest.”
Config is treated as an Environment Variable, keeping the codebase free of environment-specific parameters. As mentioned in the first factor, configuration made independent is how you keep the app flexible.
Ensuring compatibility with backing services is also an important step since it allows you to switch service providers or services without having to make changes to your code. You can keep microservices running in more environments with this approach.
Build, Run, Release
The 12-Factor methodology separates Build, Run, and Release phases firmly. Code moves from one phase to another as they are reviewed and tested, which means the deployed codes are always up to the job they are meant to do.
The days of adding state to your services are officially gone now that the 12-Factor app methodology supports stateless services all the way.
This component is easy to deploy since it basically means making services available through port binding. The result is an app – with microservices as components – that is independent.
To help make scaling up manageable, microservices are made as small as possible. Microservices can also be scaled up as units or as an entire app thanks to their stateless nature (Factor 6).
Yes, every process in the app is disposable. The approach makedds handling failures and tracking inefficiencies easier.
Matching environments is the key to making your CI/CD cycles more effective.
No good framework is complete without sufficient logging for debugging and general health checks. “A twelve-factor app never concerns itself with routing or storage of its output stream. It should not attempt to write to or manage logfiles. Instead, each running process writes its event stream, unbuffered, to stdout. During local development, the developer will view this stream in the foreground of their terminal to observe the app’s behavior. In staging or production deploys, each process’ stream will be captured by the execution environment, collated together with all other streams from the app, and routed to one or more final destinations for viewing and long-term archival. These archival destinations are not visible to or configurable by the app, and instead, are completely managed by the execution environment. Open-source log routers (such as Logplex and Fluentd) are available for this purpose.”
To complete the set, there is a need for management tasks to run as one-time processes rather than continuous cycles. Process formation is the array of processes that handle an app’s regular business (such as web requests, etc.,) when it runs. Alternatively, developers will often want to do one-off administrative or maintenance tasks for the app. Run these one-off admin processes in an identical environment as the regular long-running processes of the app. Run them against a release, using the same codebase and config as any process run against that release. Admin code must ship with application code to avoid synchronization issues. Such one-off processes can include:
- “Running database migrations (e.g. manage.py migrate in Django, rake db: migrate in Rails).
- Running a console (also known as a REPL shell) to run arbitrary code or inspect the app’s models against the live database. Most languages provide a REPL by running the interpreter without any arguments (e.g., python or perl) or in some cases have a separate command (e.g.,
rails consolefor Rails).
- Running one-time scripts committed into the app’s repo (e.g., php scripts/fix_bad_records.php).”
12-Factor Application Principles in Kubernetes
Many of the 12-Factor application principles are among the things that make Kubernetes so popular. Modularity, disposability, and concurrency are some of the strong suits of deploying apps and microservices using Kubernetes.
If you take a look at some 12-Factor app example deployments, you will also find that they work really well with Kubernetes pods and config files. Pods utilize port binding to remain visible, use config and requirements that are defined for each of them, and are incredibly scalable.
In fact, tools like the Horizontal Pod Autoscaler (HPA) make scaling Kubernetes pods easier. Lifecycle controllers that are native to Kubernetes, including DaemonSets and ReplicationControllers, allows for concurrent pods to make high availability possible.
States in a Stateless Environment
The only real challenge of adopting the 12-Factor application principles is whenever your Kubernetes application needs to use states (or you have to develop a stateful application). States are crucial in maintaining processes and enabling efficient resource sharing. It may seem like a complete dead-end at first, but there are ways to get around the states in Kubernetes when implementing 12-Factor.
Persistent datastore attached to the Config of your Kubernetes environment is an elegant solution to the issue. It allows you to have scalable pods without sacrificing data storage and the benefits of service states.
The 12-Factor approach is a framework that can be implemented in virtually any development situation. More importantly, it is a framework that works better with Kubernetes than many believe. If you are looking for a standard to adopt for your app development projects, becoming 12-Factor app-ready is the way to go.
Published at DZone with permission of Mauricio Ashimine. See the original article here.
Opinions expressed by DZone contributors are their own.