Kaniko is a wonderful tool to build container images from a Dockerfile without needing access to the Docker Daemon since it is not accessible in the Kubernetes Cluster. This is great and quite straightforward if that container is also going to be deployed into a Kubernetes Cluster since CI/CD can easily integrate with a Kubernetes cluster.
However, things become quite tricky if that image needs to be deployed on Heroku since many of the Heroku CLI commands are actually running tasks that interact with the Docker Daemon under the hood.
In this post, I will discuss how to use Kaniko to build an image in a CI/CD pipeline and then deploy that image on Heroku.
Prerequisites
-
Familiarity with CI/CD pipelines (this blog will focus on Gitlab, but should translate well to other platforms)
-
Familiarity with heroku-cli
-
Basic understanding of Kaniko
Build the Container Image
Start by verifying that the HEROKU_API_KEY
environment variable is set in the CI/CD environment variables. If it is not there, generate an API key with the Heroku CLI and add that value to the HEROKU_API_KEY
CI/CD variable.
Next, create a phase in the CI pipeline that contains the logic to build the container from a Dockerfile using Kaniko:
build: stage: build
image:
name: gcr.io/kaniko-project/executor:v1.9.0-debug
entrypoint: [""]
varables:
- HEROKU_API_KEY=$HEROKU_API_KEY
- HEROKU_IMAGE_TAG: registry.heroku.com/<app-name>/<process-type>
script:
- echo "{\"auths\":{\"$CI_REGISTRY\":{\"username\":\"$CI_REGISTRY_USER\",\"password\":\"$CI_REGISTRY_PASSWORD\"},\"registry.heroku.com\":{\"username\":\"_\",\"password\":\"$HEROKU_API_KEY\"}}}" > /kaniko/.docker/config.json`
- /kaniko/executor
--context "${CI_PROJECT_DIR}"
--dockerfile "${CI_PROJECT_DIR}/Dockerfile"
--destination "${CI_REGISTRY_IMAGE}:${CI_COMMIT_TAG}"
--destination "${HEROKU_IMAGE_TAG}"
rules: - if: $CI_COMMIT_TAG
In the script above, the echo
command is going to write the credentials to the config.json
for Docker so Kaniko can authenticate to both the Gitlab container registry and the Heroku container registry.
A variable named HEROKU_IMAGE_TAG
has also been defined and that is being used as the destination for the Heroku container registry. This will ensure that the build version of the container is pushed to the correct application. Heroku does not work with tagging, so applying a tag will cause Heroku to not deploy the newly built container.
Release the Container Image
Once the container has been built and pushed to the Heroku container registry, the only thing left is to release that container via the Heroku CLI. Add another stage to the CI/CD pipeline:
release: stage: release
image: "buddy/heroku-cli"
cache: {}
variables:
HEROKU_API_KEY: $HEROKU_API_KEY
script:
- heroku container:release -a <app-name>
needs:
- build
This stage will use the heroku-cli
container image, and it will issue only the heroku container:release
command to release the container. This will tell Heroku to deploy the container that was pushed to its registry in the previous step, and the changes should be deployed.
Why Not Use Heroku Container:Push?
In the Heroku Container Registry Docs they discuss the heroku container:push
command as being a way to build and push a container to the Heroku registry. However, since this command is actually relying on the Docker Daemon (presumeably it’s just an alias for docker build
and docker push
with some tagging involved) to be available on the machine running the command, this command will fail when the CI/CD pipeline is being run on Kubernetes since the Docker Daemon is not available.
I hope this was helpful! Feel free to check out my Github or my LinkedIn.