Heroku has deployed more services in a cloud environment than probably any other company. They
operate a massive "Platform-as-a-Service" that enables someone to deploy most kinds of apps just by doing a simple
git push. Along the way, they developed a pattern for how to write applications so that they can be easily and
consistently deployed in cloud environments. Their platform abides by this pattern, but it can be implemented in many
ways.
The 12-factor pattern can be summed up like this:
Treat all micro-services as disposable services that receive their configuration via environment variables and rely on
backing services to provide durability. Any time you need to make a change it should be scripted. Treat all
environments (dev, prod, qa, etc) as identical.
Of course, this assumes that the cloud-architecture plays along with this methodology for it to work. For a
cloud-architecture to be "12 factor app" compliant, here are some recommended criteria.
1. Codebase
Applications can be pinned to a specific version or branch
All deployments are versioned
Multiple concurrent versions can be deployed at the same time (e.g. prod, dev, qa)
2. Dependencies
Service dependencies are explicitly declared and loosely coupled
Dependencies can be isolated between services
Services can be logically grouped together
3. Config
All configuration is passed via environment variables and not hardcoded.
Services can announce availability and discover other services
Services can be dynamically reconfigured (E.g. using feature flags or changing environment)
4. Backing Services
Services depend on object stores to store assets (if applicable)
Services use environment variables to find backing services
Platform supports backing services like MySQL, Redis or Memcache
5. Build, release, run (PaaS)
Automation of deployments (build, release, run)
All builds produce immutable images
Deployment should result in zero down-time
6. Processes
Micro-services should consist of a single process
Processes are stateless and share-nothing
Ephemeral filesystem can be used for temporary storage
7. Port binding
Services should be able to run on any port defined by the platform
Service discovery should incorporate ports
Some sort of routing layer handles requests and distributes them to port-bound processes
8. Concurrency
Concurrency is easily achieved by replicating the micro-service
Scale automatically without human intervention
Only sends traffic to healthy services
9. Disposability
Services are entirely disposable (not maintain any local state)
They can be easily created or destroyed
They are not upgraded or patched (just redeploy!)
10. Dev/prod parity
All environments function the same way
Guarantees that all services in an environment are identical
Code runs the same way in all places
11. Logs
Logs treated as structured event streams (e.g. JSON) that can be subscribed to by multiple consumers
Logs collected from all nodes in cluster and centrally aggregated for auditing all activity
Alerts can be generated from log events
12. Admin processes
It should never be necessary to login to servers to manually make changes
APIs exist so that everything can be scripted
Regular tasks can be scheduled to run automatically