These days software is delivered as a service (SaaS). 12 factor app is methodology to build such services. I think these factors are very much valid for software created using Microservices.
- Codebase – each microservice should have single root repo, no code sharing with another microservice. A Codebase is any single repo which maps to many deploys. A deploy is nothing but running instance of microservice. The deploys could be of different versions across Dev, Staging or Prod setups but will have same Codebase.
- Dependencies – each microservice shouldn’t rely on implicit existence of system-wide packages or libraries. All dependent libraries are deployed with the microservice. If microservice needs a system tool or library, it should completely and exactly declare all dependencies.
- Config – Use environment variables to define or store config (like resource handles to database, credentials to external services or per-deploy values etc). No config defined in code. Even constant config should not be stored in code. Keep the config separated from code because config varies across deploys but code does not.
- Backing Services – each microservice may consume the exposed API’s of other microservice. It should treat it as attached resource and handle the unresponsive service dependencies robustly.
- Strictly separate Build, Release, run steps – each microservice uses strict separation between the build, release and run stages. It is impossible to make code changes to the code at run-time as these changes will not propagate back to build stage. The Codebase is transformed to deploy through 3 stages: 1) Build stage builds the version of code repo and gathers dependencies. 2) Release stage combines config with build. 3) Run stage runs the microservice in executable environment.
- Processes – the microservice is executed as a stateless process and share nothing. The memory or file system is used as single transaction cache. Any data that needs to persist must be stored in a stateful backing service (a database). Sticky sessions are violation of twelve-factor.
- Port Binding – your microservice listens/binds on port and avoids using (web) host. Webserver container like Apache or Tomcat may add configuration and communication complexity and it should be avoided by making the microservice self contained.
This port-binding approach also helps in to make one microservice as backing service for another microservice.
- Concurrency – this helps in scaling out via the process model. The share-nothing, horizontally partitionable nature of 12-factor service processes means that adding more concurrency is a simple and reliable operation. Use processes (single threaded) for isolation and spawn more of them to get concurrency.
- Disposability – processes can crash/be killed quickly (graceful shutdown) and start them fast. Sometimes they can be started or stopped a moment’s notice. Small startup time provides more agility. Avoid long initialization of microservice when it starts up.
- Dev/Prod parity – keep your development, staging, production environment similar. 12-factor microservice is designed for continuous deployment by keeping the development and production environment similar.
- Logs – each running process writes its event stream to stdout. It will not try to manage these logfiles. In development environment the service will be logging to console window and in production this can be redirected to log file and archive them. Basically it means to keep the logging simple as much possible.
- Admin processes – deploy and run admin tasks as processes. Any task to be done on the node, say setting pre-registry values or some environment variables, don’t log in to the node or remote desktop into it to make the changes. Rather automate this and let it run in predictable fashion and in consistent way.
What are main takeaways-
-The microservice should be simple enough to code, simple to build, simple to test, simple to deploy, simple to log, simple to start/shutdown.
-Service should be lightweight. Less dependencies on (OS/language/runtime/libraries), should run fast and use less RAM.
-Service should give reproducible results on Development, test, staging and production setups.