In this post, I will quickly show you multiple ways of building your containers without having to worry about the details of Dockerfiles.


Most developers that have set up a pipeline that uses Docker already are familiar with the details that come with building your own Docker image, but for someone that is new, this can be a bit overwhelming. Things that you have to keep into account like:

  • Advanced caching
  • Apply best practices regarding security
  • Multi-stage setup to have a lightweight final image
  • Keeping your base images up to date
  • Reproducibility of an image

If this is all completely new to you, your best bet to start with containers is by learning Buildpacks as the first step.



Buildpacks was started by Heroku back in 2011 and is now officially part of the Cloud Native Computing Foundation and recently went from sandbox to incubation (see post). It allows you to automatically detect based on source code which build tooling you need and it transforms your code into a ready to use image.


On Gitlab you have 2 approaches currently used:

  • docker-in-docker
  • Kaniko build executor

Both use a Dockerfile as a starting point, whereas Kaninko doesn't even need a docker daemon to run. This is why this is the most preferred (and advanced) approach in building containers. Below I will show different approaches in building your application starting with Auto DevOps. You can also find these approaches on an example Git repository fastify-example-buildpacks

Buildpacks with Auto DevOps

On Gitlab you can use Buildpacks out of the box with "Auto DevOps". "Auto DevOps" automatically uses a Herokuish builds as a default to build your project and publish it to your Gitlab registry. You can override this by making use of an AUTO_DEVOPS_BUILD_IMAGE_CNB_ENABLED environment variable on your GitLab agent. This allows you to make use of Buildpacks which is part of the Cloud Native Foundation. For now, this is still in Beta on Gitlab, but they expect this to become a replacement for the current Herokuish builds.

- template: Auto-DevOps.gitlab-ci.yml


Buildpacks with Pack CLI

If you want to have more control on which Buildpacks that are used, you can use Pack CLI which needs to be installed on your agent. This is easily done with the following example:

stage: build
- docker:19.03.12-dind
DOCKER_HOST: tcp://docker:2375
image: docker:19.03.12
- wget
- tar xvf pack-v0.13.1-linux.tgz
- rm pack-v0.13.1-linux.tgz
- ./pack build $IMAGE_NAME --builder

This explicitly uses the Buildpacks provided by Google. You can find more information about these on Github

Buildpacks with Google Cloud Platform

You can now even deploy your app directly to cloud Run. The only command you need is the following:

gcloud beta run deploy --source=[DIRECTORY] [CLOUD_RUN_SERVICE]


Custom build scripts are not supported so you still need to compile your typescript for example to allow your application to be packages as an image. Additionally, certain native dependencies could be an argument to start from your base images in the first place which makes the use of Buildpacks a bit obsolete. Last the images that are created are bigger because they serve a wider variety of use cases that could not be needed by your application.


Start with buidpacks and if you need to customize your container you can opt-out of the default image created for you and fully customize it to your liking with a Dockerfile.