This blog post is Unfiltered

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?

Use Heroku

I have been a backend developer in the past 20 years. Web development is often fighting with Javascript and CSS. Especially Heroku as a deployment platform is a new area for me.

Let's start with creating an account, login, and follow the web instructions to create a new app in the documentation.

Let’s try a fun demo, a battleship game to learn Javascript on the client and NodeJS on the server.

$ 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.

Battleship web app deployed with Heroku

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

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 https://github.com/kubowania/battleships.git.

Import the GitHub repository into GitLab

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.

Configure AWS credentials as masked CI/CD variables

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_POSTGRES and TF_VAR_DISABLE_REDIS variables to false.

Commit the change to the default branch.

8:43pm CET: Pipeline started with the build job. 2 min 33 sec.

GitLab pipeline builds the Docker image with Auto-Build

8:45pm CET: Pipeline runs terraform_apply to provision AWS resources in 2min 47 sec.

GitLab pipeline runs Terraform to provision cloud resources in AWS

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!

Battleship web app deployed in AWS with the 5 minute production app

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:

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:

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

Git is a trademark of Software Freedom Conservancy and our use of 'GitLab' is under license