We are building a better Heroku


Ended up in a Heroku blackbox for your stateful web app? GitLab introduces a better Heroku integrated into your DevSecOps workflow: The 5 minute production app.

This blog post is Unfiltered

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

First steps with Heroku

Ok. After some trial and error, the name needs to be unique in the global namespace. Time to stop and read the documentation.

Reboot Heroku

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 Git URL unfortunately does not provide access.

No Git web access in Heroku

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?

Do not use Heroku

Apparently Heroku is not Open Source, making contributions not so easy. You cannot debug Heroku by reading the source code.

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

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