Continuous deployment
Deploying the app is an activity that is best done continuously and automatically. I'd optimise to make it as easy and as quick as possible to deploy, this way when bugs affect users they only do so for a short period. We can enable continuous deployment for our app by adding it to the Gitlab CI/CD script.
To do this we first need credentials to interact with Heroku to be
available to the Gitlab CI runner. We can do this by adding the
following to infrastructure/gitlab.tf
,
resource "gitlab_project_variable" "heroku_app" {
key = "HEROKU_APP"
value = heroku_app.tozo.name
project = gitlab_project.tozo.id
protected = true
}
resource "gitlab_project_variable" "heroku_token" {
key = "HEROKU_API_KEY"
value = var.heroku_api_key
project = gitlab_project.tozo.id
protected = true
}
resource "gitlab_project_variable" "heroku_username" {
key = "HEROKU_USERNAME"
value = var.heroku_username
project = gitlab_project.tozo.id
protected = true
}
The deployment requires four steps, firstly we need to login to
Heroku's docker repository, then build the docker image, followed by
pushing it to Heroku's respository, and finally instruct Heroku to use
our new image for the app. This is achieved by adding the following to
.gitlab-ci.yml
,
heroku-cd:
stage: deploy
image: docker:latest
services:
- docker:dind
before_script:
- apk add --update curl
script:
- >
docker login registry.heroku.com
--username $HEROKU_USERNAME
--password $HEROKU_API_KEY
- >
docker build --build-arg CI_COMMIT_SHA=$CI_COMMIT_SHA
-t registry.heroku.com/$HEROKU_APP/web .
- docker push registry.heroku.com/$HEROKU_APP/web
- >
curl --fail
-X PATCH "https://api.heroku.com/apps/$HEROKU_APP/formation"
-H 'Content-Type:application/json'
-H 'Accept:application/vnd.herokujson; version=3.docker-releases'
-H "Authorization:Bearer $HEROKU_API_KEY"
-d '{"updates":[{"type":"web","docker_image":"'$(docker inspect registry.heroku.com/$HEROKU_APP/web --format={{.Id}})'"}]}'
only:
- main
To prevent us accidently trying to deploy a broken commit I've
introduced stages
to the CI, with the above being in the deploy
stage. This is achieved by adding the following to .gitlab-ci.yml
,
stages:
- lint-test
- deploy
and adding,
stage: lint-test
to the existing CI jobs.