Cloud apps
Recently I completed some AWS certifications and in doing so thought it would be a good idea to dig into some of the methodologies or best practices behind running apps in the cloud.
AWS promotes its 6 pillars of the AWS well architected framework and the founder of Heroku published the 12 factor app, a collection of 12 principles for cloud hosted apps.
I want to go over the 12 factors, the overlap with AWS well architected framework and the practical implementations.
- Code base
A version controlled code base, usually Github or could be AWS CodeCommit or bitbucket, the ability to work on seperate branches of changes focused on a specific feature or area of code which can be merged to the main code branch after a review process.
The well architected frameworks suggests storing infrastructure as code in cloud formation or CDK, terraform is an open source solution that has providers for most cloud hosting providers, infrastructure changes can be pushed along with you code as part of your continous deployment.
- Dependencies
Never depend on an implicit exisitence of a system wide package.
Most modern languages have a way to track dependencies and versions within your application, golang uses a mod file and node use a package.json. Having the dependencies and versions allows the code to be run without external setup. In some cases and external dependcy is required that cannot be configure this way, say a node package that requires an external image lib written C++, docker can help manage these other dependencies.
- Application configuration
Seperation of config from code. Never include or hard code configuration in your codebase, it makes it difficult to change and insecure, possibly exposing important access tokens or secrets. AWS provides a config service or parameter store as ways of asbtracting these configuration details, most cloud hosting solutions provide ways of managing and injecting environment variables into the environment.
- Backing services
Should be a loosely coupled service, replaceable with a configuration change.
A database, cache service, api call should be external to your application making it easier to run and test locally as well as supporting of failover or moving providers.
- Build, release and run
Utilise continous integration and continous deployment, apply incremental code changes to the code base, automating build ands tests and pushing a new artifact live. Each change is can be audited via the repository, each build is tagged and a new artifact is created allowing easy rollback of versions.
- Processes
All process must be stateless and share nothing.
Again decoupling services, making them easier to run and test and ensuring state is stored in another service, eg cache, database This is key to being able to create multiple instances of an application to scale horizontally. AWS promotes serverless which are short running processes forcing this practice.
- Port binding
An app is fully contained and does not rely on any external server or process to be available. A service can be called with the correct protocol and port. This makes it easier to run locally, easier to move hosting provider, can scale horizontally behind a load balancer.
- Concurrency
Support concurrency via a load balancer and scaling out.
- Disposability
Shut down and restart gracefully and quickly, refusing new requests while finishing exisiting requests.
- Dev/Prod parity
Keep dev and prod environments as similiar as possible to minimise potential issues. Make the time from developement changes to prod as small and quick as possible. Developers involved in release rather seperate ops team. Keep dev and prod environments similiar as possible.
- Logs
Logs should be treated as event streams and decoupled from the application. They should be externally readable. AWS provides Cloudwatch a central log store for all services, there are also many external logging services like newrelic that also provide the ability to set alerts and dashboards.
- Admin processes
Things like data migrations or a one time script, should be run in an identical environment against a release. Code should live with the application code to keep them consistent.
Decoupling A consistent theme across the 12 factors is decoupling, it makes it much easier for developers to work with locally, to run and test, it always helps to decouple from the provider potentially making it easier to move integrate other providers. AWS promotes using it’s serverless offering lambda which other providers may be able to be used in a cloud agnostic way it’s likely you will want to use some the AWS specific features.
AWS Well architected framework
The aws well architected framework suggests some other best practices not included in the 12 factor app:
Anticipate failure, test when things fail, how to roll back and have a disaster recovery plan.
Anticipate failure, test when things fail, how to roll back and have a disaster recovery plan and learn from previous mistakes. AWS provides ways of handling instance fallure by using an auto scaling group, Route 53 can reroute traffic if a health check fails, it also provides failover support for databases in multi availability zones.
User serverless where applicable. This obviously depends on your use case but its obviously more efficient to only use resources as required.
Stop guessing capacity and test usage patterns, try to use the capacity needed and use auto scaling where applicable.
Cost optimization, use AWS cost analysis tools to ensure efficiency and cost effectiveness.
Ensure security at all layers, at rest and in transit.