Update: This post does not live up to its original title
We are building a better Heroku. It shows my own personal experience and reflects poorly on competitors. I am sorry about that.
It should have emphasized the building part, we're just starting. The current 5 minute production app doesn't hold a candle to Heroku at the moment. It should have made it clear the goals is to improve the speed with which you can configure a production app, not a development app. Development apps on Heroku are already close to perfect. The examples in this post are contrived since it talks about a development app, as rightly called out by Heroku people. It should have gone into why hyper clouds might be preferable. It should have talked about state, we made a small improvement in this MR but we should have done the planned work and made one post out of it.
We are very far from a better Heroku for production apps in a hyper cloud.
Creating a web application has become very convenient and easy. You’ll start in your local development environment, run a dev server and verify the changes looking good. At a certain point, you want to share it with your friends on the internet. A service or server?
Let's start with creating an account, login, and follow the web instructions to create a new app in the documentation.
$ cd ~/dev/opensource $ git clone https://github.com/kubowania/battleships $ cd battleships
Test it locally, optional.
$ npm install $ npm start
Install the Heroku CLI, on macOS with Homebrew.
$ brew install heroku/brew/heroku $ heroku autocomplete
This opens a new browser window to login. Lets create an app.
$ heroku create Creating app... done, ⬢ nameless-mountain-48655 https://nameless-mountain-48655.herokuapp.com/ | https://git.heroku.com/nameless-mountain-48655.git
The CLI command adds a new Git remote called
heroku where we need to push into.
$ git push heroku main remote: -----> Launching... remote: Released v3 remote: https://nameless-mountain-48655.herokuapp.com/ deployed to Heroku remote: remote: Verifying deploy... done.
Deployed in less than 5 minutes. Getting there and installing the pre-requisites on the CLI took longer than expected.
Lots of CLI commands involved, and it did not run in a CI/CD pipeline with additional tests before deploying it. Now the web application is deployed into a black box. Want to use Let’s Encrypt and your own domain name? How about adding the deployment natively to GitLab to have a single application in your DevOps workflow?
Setting up Persistence with Heroku
This gets more challenging. Imagine that your app uses a relational database, a caching layer and object storage. This requires lots of CLI commands and a deep dive into the application configuration. We did not touch persistent backends in the demo app above yet.
Heroku offers PostgreSQL, Redis and AWS S3.
heroku addons:create heroku-postgresql:hobby-dev heroku addons:create heroku-postgresql:hobby-dev --version=10 heroku pg:promote HEROKU_POSTGRESQL_YELLOW
heroku addons:create heroku-redis:hobby-dev -a 5-min-prod-app
Note that the default
hobby-dev plan allows unencrypted connections too.
heroku config:set S3_BUCKET_NAME=appname-assets heroku config:set AWS_ACCESS_KEY_ID=xxx AWS_SECRET_ACCESS_KEY=yyy
All stateful backends in Heroku need to be secured. This requires more commands to create self-signed certificates and encrypt transport layers in the backend.
After all, is there a better way to automate requesting stateful backend services and automate their provisioning?
A better Heroku: The 5 minute production app
the modern tech industry is basically folks just endlessly remaking remakes of heroku— Always Miso (@monkchips) March 8, 2021
Truth https://t.co/AFN9anBbQG— Sid Sijbrandij (@sytses) March 8, 2021
Cloud resources are cheap. AWS offers a free tier, HashiCorp Terraform has become an excellent tool to manage multi-cloud resources and GitLab integrates app packaging, container registry, deployment and TLS certificates.
There’s more application goodies: Provision a PostgreSQL VM, add Redis, SMTP email transport, custom domains with Let’s Encrypt.
Use the 5 minute production app
The documentation says to create a new AWS IAM role with credentials for automation.
The second step is to have the source code available in a GitLab project. You can use
New project > Import project > Repo by URL to automatically import the GitHub repository
Once imported, navigate into
Settings > CI/CD > Variables to specify the AWS credentials and region. Ensure to tick the
Masked checkbox to hide them in all job logs.
Navigate back into the project overview. Click the
Setup CI/CD button or open the Web IDE to create a new
.gitlab-ci.yml file. Add the remote CI/CD template include like this:
variables: TF_VAR_DISABLE_POSTGRES: "true" TF_VAR_DISABLE_REDIS: "true" include: remote: https://gitlab.com/gitlab-org/5-minute-production-app/deploy-template/-/raw/stable/deploy.yml
The battleship application does not need the PostgreSQL and Redis backends. They are disabled with setting
TF_VAR_DISABLE_REDIS variables to
Commit the change to the default branch.
8:43pm CET: Pipeline started with the build job. 2 min 33 sec.
8:45pm CET: Pipeline runs terraform_apply to provision AWS resources in 2min 47 sec.
8:48pm CET: Deployed in 1 min 11 sec.
The deploy job log greets with the URL in ~5 minutes, including a Lets Encrypt TLS certificate. There we go, let’s play some battleship!
Note that we never left the browser and there is no CLI involved. Next to the included template, there’s also room for adding more CI tests and security best practices while hacking on this project. You can navigate into your AWS console for debugging and troubleshooting and plan with production budgets, where needed.
Setting up Persistence with the 5 Minute Production App
Remember the stateful backends with Heroku above? By default, the 5 minute production app takes care of provisioning:
- PostgreSQL server and secured backend
- Redis cluster
- S3 object storage in AWS
The 5 minute production app uses the managed stateful services of a hypercloud so your data is persisted and secure. By leveraging these managed services (databases, caching, objects storage, etc.) you have less to maintain. Everything is provisioned through Terraform which has the following advantages:
- Terraform is the most popular IaC tool.
- Terraform works accross platforms.
- Terraform is well-documented.
- Terraform state can be stored and viewed in GitLab.
- You avoid the cost and complexity of Kubernetes.
- You have complete control to customize and extend.
We will explore more stateful backends in future apps and blog posts.
5 minute production app + DevSecOps = ❤️
Example for Dependency Scanning and SAST:
include: - remote: https://gitlab.com/gitlab-org/5-minute-production-app/deploy-template/-/raw/stable/deploy.yml - template: Dependency-Scanning.gitlab-ci.yml - template: Security/SAST.gitlab-ci.yml
More to use: Database backends, TLS, environments
This blog post covers the basic learning steps with Heroku and the 5 minute production app. A typical web app requires a database, storage or caching backend, which can get complicated to run with Heroku. We will explore the setup and production experience in future blog posts. In addition to backends, we will also look into TLS certificates and production environments in CD workflows.
Meanwhile, try the 5 min production app yourself:
Cover image by SpaceX on Unsplash
“.@gitlab is building #Heroku for production apps in hyper clouds: The 5 minute production app #SeeingIsBelieving” – Michael Friedrich
Click to tweet