This is a basic introduction to cloud native application development. First we will get a basic idea about the cloud concept and then move in to the 12-Factors.
What is cloud computing environment?
It’s a dynamic environment, which have the capability to allocate resources and release of resources from a virtualized, shared pool. This elastic environment enables more flexible scaling options for a high demand applications.
What is cloud native application?
Applications or processes which are run in software containers as isolated units. Applications or services (microservices) are loosely coupled with explicitly described dependencies. There are set of best practices which you need to follow when you’re planning moving to cloud with your application. Those are known as the 12-factors. Let’s investigate on those 12-factors.
The 12-factor application methodology was drafted by developers at Heroku. The factors represent a set of guidelines or best practices for portable, resilient applications that will thrive in cloud environments (specifically software as a service applications). Let’s move in to each factor and get a high level idea on how we can achieve / implement this in our application.
There should be a one-to-one association between a versioned codebase: Main idea is not to have different codebases for your application versions. You can have branches for different versions as a solution to avoid repository complexity.
Services should explicitly declare all dependencies, and should not rely on the presence of system-level tools or libraries: Main recommendation here is that avoid in pre-installed software in the system level which has a dependency with your application. As a solution we should try our level best to put application dependencies in our application manifest. Tools like Apache Maven can be used to maintain these dependencies in your application.
Configuration that varies between deployment environments should be stored in the environment: In this scenario the recommendation is to avoid having environment (Development, Staging and Production) specific configuration with in your application code. If you have any environment specific configurations those need to be stored in the environment not in the application. To have the configuration files in a centralized location we can use the spring config server
All backing services are treated as attached resources, which are managed (attached and detached) by the execution environment: Firstly backing service is any service that your application integrate with to perform its normal operations. So, examples for backing service would be database, web services, SMTP server or ftp server. Main idea of this practice is to treat those backing services as your own service.
- The delivery pipeline should have strictly separate stages: Build, release, and run: When we consider the three stages,
- Build: Takes the source code and bundle to a package which referred as the build
- Release: Combine the build and the config and create a release for deploy in an environment. Each release will have a unique identifier and related to a release management tool. It will ensure a quick rollback time.
- Run: Referred as the runtime. Execute the application in the corresponding environment
Applications should be deployed as one or more stateless processes: Specifically, transient processes must be stateless and share nothing. Persisted data should be stored in an appropriate backing service.
Self-contained services should make themselves available to other services by listening on a specified port: This means each application are self-contained and expose access over a HTTP port that is bound to it. Spring boot framework is a good example for this, which is having a inbuilt server where you can configure the HTTP port easily
Concurrency is achieved by scaling individual processes (horizontal scaling): Idea behind this is having multiple processes with distributed load. The application should be able to scale horizontally and handle requests load-balanced to multiple identical running nodes of the application. In addition application should be able to scale out processes or threads for parallel execution of work in an on-demand basis. This feature comes automatically with the JVM with multi-threading.
Processes must be disposable: Fast startup and graceful shutdown. If we elaborate more our application should minimize the startup time like using backing services rather than using in-memory caching. Also in shutdown process, when we stop the application it should not accept new work and let existing work to finish. We can use a queue to push the work and then shutdown if required.
All environments, from local development to production, should be as similar as possible: Development environment to production environment should be identical. It will ensure unexpected behavior in the application due to environment inconsistencies. Containerized environment like Dockers is a good solution for this.
Applications should produce logs as event streams (for example, writing to stdout and stderr), and trust the execution environment to aggregate streams: Application should not attempt to write to or manage logfiles. This stream output should mainly managed by the execution environment. This stream can be shipped to a log indexing systems such as Splunk, ELK stack which facilitate as a centralized logging system.
Run admin/management tasks as one-off process: If admin tasks are needed, they should be kept in source control and packaged alongside the application to ensure that it is run with the same environment as the application