The 12-factor Principles guide how we build continuous delivery— or the constant delivering of our code to production— in modern software applications.
The 12-factor principles steer us away from doing ill-advised things like host-based and cluster-based deploys on Amazon EC2. This requires that you write your application code in specific, conforming ways. Unfortunately, if you haven’t started with a 12-factor application you may have some cost associated with switching to full 12-factor deployment.
There are several apps out there that do not begin 12-factor, and thus suffer from costs associated with deployment entropy (e.g. your server breaks and you don’t know why) and the inability to scale the team (e.g. adding new developers is prohibitively complicated or expensive).
While the lure of Kubernetes looks attractive, most apps would do well to just go 12-factor deploy and pick a 12-factor deploy provider from the list below.
12-factor deployment changed the world around 2007.
A lof the other solutions still struggle—even years later—with huge costs associated with DevOps time.
There’s a reason a generation of the most successful Rails apps were deployed on Heroku. Now some competitors (namely Render and Vercel) are also good 12-factor options, especially in the JS/TS and Jamstack world.
These deployments are based on the idea of a cluster architecture: several backend persistent services talking to one another. Ideally, these services are in the same internet topology (In fact, you can run any of these on any AWS region because the AWS backbone makes inter-AWS communication nearly instantaneous. You are still advised however to run your applications within the same AWS zone for best performance.)
The Principles of 12-Factor Deploy
- Codebase (One codebase tracked in revision control, many deploys)
- Dependencies (Explicitly declare and isolate the dependencies)
- Config (Store configurations in an environment)
- Backing Services (treat backing resources as attached resources)
- Build, release, and Run (Strictly separate build and run stages)
- Processes (execute the app as one or more stateless processes)
- Port Binding (Export services via port binding)
- Concurrency (Scale out via the process model)
- Disposability (maximize the robustness with fast startup and graceful shutdown)
- Dev/prod parity (Keep development, staging, and production as similar as possible)
- Logs (Treat logs as event streams)
- Admin processes (Run admin/management tasks as one-off processes)
These 12 principles affect how we write the code, and modern Rails applications typically meet these requirements.
What is the Jamstack?
In 2015 the world shifted again when Mathias Biilmann, then CEO of Makerloop, which would go on to rebrand as Netlify, touted what the world would see as the evolution of modern web standards. He called this Jamstack.
The Jamstack concept is that the application logic resides mostly on the client-side without being tightly coupled to a back-end server. They are mostly served with git-based CMS or headless CMS.
I have no affiliation with these providers and reviews here are provided as-is.
In all of these, you have to pick the size of your deployment instance (or dyno) ahead of time. You will do this based on the memory footprint of your application.
Different platforms have different methods for specifying what Ruby or Node version to use and what command start up your application.
|Year founded & History
|Good for Ruby?
|Developement: $ or 0
|Mesh layer; free-tier with low capacity on many add-ons
For Production: $
|No free-tier services for basic things like Redis or Postgres
|Best for React
A git-based deploy is a deploy in which you will push to a special git repository. Unlike a normal repository, this repo has a special purpose: To control the deployment itself. Once the git repo receives a commit, that kicks off the CI/CD pipeline which you configure
The Edge refers to the servers which act like, and sometimes as, a content delivery network. There are thousands of “edge network” services in your “fleet,” and when a customer (user) makes a request to one of these API endpoints, it uses code (as in the case of a serverless function) or content (as in the case of static content) that is stored on a server closest in geographical (network) proximity to where the user is. This means that all users have to wait a minimal amount of time to execute their request— for example, an HTTP call to a specific part of your app. If the node closest to them doesn’t have your code, it is able to load it dynamically through the magic of the cloud.
All of the platforms offer some serverless function, but under the hood they are all user AWS Lambdas. For this reason, many deploy setups just skip the provider-sold Lambdas (serverless functions) and provide AWS Lambda instances.
Databases and Data Storage
Again, all of the platforms offer some database storage but many setups choose to use Amazon RDS or Aurora services (both are great options). That means you sign up for your own AWS account, get billed directly from AWS, and have to use AWS to manage and backup your database. That’s the cost, but the benefit is that it is cheaper than provisioning databases through these providers.
Heroku Data is in fact its own implementation of Postgres, so an apples-to-apples comparison with, for example, Amazon Aurora, does not apply. If you’re on Heroku, Heroku Data is a great choice. Setting up RDS or Amazon Aurora costs a little more in DevOps cost but can be cheaper in the long run. For most small or medium-sized apps I recommend just sticking with Heroku or the platform-provided data solution.
If you do set up your own database with AWS, you provision your own database and then set the
DATABASE_URL in your app to give the platform access to your database.
This technique is only recommended if your application itself is also running on AWS, which is true of all of the 12-factor setups covered here.
If you provision your database through the provider then your provider bills you on their invoice. Like I said, this is typically better for small or medium apps but winds up being more costly for larger apps, so larger apps typically provision their own AWS database services to save cost.