Yesterday I was setting up a Gitlab CI/CD pipeline to deploy Docker containers to Heroku. Whilst it’s a fairly straightforward task, there are a few pitfalls, and I was surprised by the dearth of good tutorials which explained them.
So to successfully deploy a Docker container to Heroku, we have to do a number of things:
All of these steps are described in a .gitlab-ci.yml file, which is shown in full at the end of this document. The CI file breaks up the deployment logically into the three steps above:
stages:
- build
- push
- deploy
Building the Docker image
The first thing that we need to do is create a Docker image. To do so, we first have to log in to the Gitlab registry, which is a store of Docker images. Having done so, we build the image, and then tag the image as “latest”.
build_image:
image: docker:latest
services:
- docker:dind
stage: build
script:
- docker login -u gitlab-ci-token -p $CI_BUILD_TOKEN registry.gitlab.com
- docker build -t registry.gitlab.com/yourusername/yourapp .
- docker push registry.gitlab.com/yourusername/yourapp:latest
The “image” entry in the code above refers to the base image of the environment which will be spun up in order to build our image. So we’re spinning up a Docker container, and then building the image inside it, before pusing it to the Gitlab registry. Got that?
The “docker:dind” service which is specified under “services” allows us to run the full Docker toolset from within a docker container. “DinD” stands for “Docker in Docker”.
Pushing our container to Heroku
push_to_heroku:
image: docker:latest
stage: push
services:
- docker:dind
script:
- docker login -u gitlab-ci-token -p $CI_BUILD_TOKEN registry.gitlab.com
- docker pull registry.gitlab.com/bencollier/cobol-api:latest
- docker login --username=_ --password=<a password> registry.heroku.com
- docker tag registry.gitlab.com/bencollier/cobol-api:latest registry.heroku.com/cobol-api/web:latest
- docker push registry.heroku.com/cobol-api/web:latest
Releasing our container
Here’s the full .gitlab-ci.yml file:
stages:
- build
- push
- release
build_image:
image: docker:latest
services:
- docker:dind
stage: build
script:
- docker login -u gitlab-ci-token -p $CI_BUILD_TOKEN registry.gitlab.com
- docker build -t registry.gitlab.com/bencollier/cobol-api .
- docker push registry.gitlab.com/bencollier/cobol-api:latest
push_to_heroku:
image: docker:latest
stage: push
services:
- docker:dind
script:
- docker login -u gitlab-ci-token -p $CI_BUILD_TOKEN registry.gitlab.com
- docker pull registry.gitlab.com/bencollier/cobol-api:latest
- docker login --username=_ --password=<a password> registry.heroku.com
- docker tag registry.gitlab.com/bencollier/cobol-api:latest registry.heroku.com/cobol-api/web:latest
- docker push registry.heroku.com/cobol-api/web:latest
deploy_to_heroku:
image: node:latest
stage: deploy
services:
- docker:dind
script:
- npm install -g heroku
- heroku container:release web --app cobol-api