Building Docker Images in GitLab CI with Depot
Tags: docker, devops, gitlab
Published: 2022-10-24 06:11:55

---
title: Building Docker Images in GitLab CI with Depot
published: true
description: Building Docker images in GitLab CI comes with security, complexity, and performance tradeoffs. With Depot, you can go back to building Docker images quickly and securely from your existing GitLab CI jobs, no tradeoffs needed. 
tags: #docker #devops #gitlab
canonical_url: https://depot.dev/blog/build-docker-images-in-gitlab-ci 
cover_image: https://depot.dev/images/banner/building-docker-images-in-gitlab-ci.webp
---

Today, there are three different options for building Docker images in GitLab CI, and each of them comes with security and complexity tradeoffs. Depot fixes a lot of these tradeoffs, and can be used to build images in GitLab CI quickly and securely.

## Current options for building Docker images in GitLab CI

There are three different options for building images in GitLab CI/CD jobs:

1. You can use the `shell` executor on your own GitLab Runners. This requires configuring the Docker Engine and granting the `gitlab-runner` user full root permissions to invoke `docker` commands.
2. You can use Docker in Docker (`dind`) with registered runners. This uses the `dind` image provided by Docker, so it contains all the `docker` tools. To build new containers with `dind`, you have to run the runner container in privileged mode.
3. Or, you can bind to the Docker socket by bind mounting `/var/run/docker.sock` into the container where your build is running.

All these options come with tradeoffs and downsides.

The first option requires you to manually configure your own runners and grant them root permissions. The second option requires that each build job get its own instance of the Docker engine, so jobs are slower because there is no layer caching, and privileged mode is still required. The third option requires you to bind mount the Docker socket into your container, which exposes the underlying host and any other processes on that host to privilege escalation.

## Building Docker images in GitLab CI with Depot

With Depot, you can build your Docker images from GitLab CI/CD jobs without needing to configure `shell` executor runners, work around slow builds with `dind`, or bind mount the Docker socket. Instead, the `depot` CLI builds the container using Depot's remote builders, and can optionally push the resulting image to a registry.

The Depot CLI can be installed via a `before_script`:

```yaml
before_script:
  - curl https://depot.dev/install-cli.sh | DEPOT_INSTALL_DIR=/usr/local/bin sh
```

After the CLI is installed, you can build your image with the `depot build` command:

```yaml
script:
  - depot build -t org/image:tag .
```

Most likely, you will want to push your image to a registry, with the `depot build --push` flag. Depot uses the local Docker registry credentials when pushing, so you will need to configure those credentials using one of two options: using the `docker` CLI or creating the configuration manually.

### Registry authentication with `docker login`

The easiest way to configure registry authentication is to use the `docker login` command. This will create a `~/.docker/config.json` file that Depot will use to authenticate with your registry. Note that this requires running the Docker daemon with Docker-in-Docker (`dind`) to perform the login. However, you **do not** need to run the GitLab CI runner in privileged mode, the daemon is only used for registry login:

```yaml
image: docker:20.10.16
services:
  - docker:20.10.16-dind
variables:
  DOCKER_HOST: tcp://docker:2376
  DOCKER_TLS_CERTDIR: '/certs'

build-job:
  before_script:
    - apk add --no-cache curl # install curl as it is not available in the docker:20.10.16 image
    - curl https://depot.dev/install-cli.sh | DEPOT_INSTALL_DIR=/usr/local/bin sh
  script:
    - docker login registry.gitlab.com --username your-username --password $REGISTRY_TOKEN
    - depot build -t registry.gitlab.com/your-username/myimage:$CI_COMMIT_SHA . --push
  variables:
    DEPOT_TOKEN: $DEPOT_TOKEN
```

With this workflow, you can build native multi-platform images directly from GitLab CI and push them to a private registry. The `depot` CLI is installed via `curl` and the `dind` service is configured with TLS enabled. Giving you the ability to run `docker login` to authenticate to a private registry, but leave the build part to Depot.

The Docker-in-Docker service is only used for authentication and not for the actual build. This means you get significantly faster builds because Depot manages the caching of layers for you, unlike `dind` which has no layer caching when you use `docker build`.

### Registry authentication via `~/.docker/config.json`

If you already have a Docker `config.json` file with your registry credentials, you can skip the `docker login` step and provide the config contents directly via a `DOCKER_AUTH_CONFIG` environment variable. Your workflow can save the contents of that variable to `$HOME/.docker/config.json`, and Depot will read from that file when pushing. This removes the need for the `docker` CLI and `dind` service at all in your image build:

```yaml
build-image:
  before_script:
    - curl https://depot.dev/install-cli.sh | DEPOT_INSTALL_DIR=/usr/local/bin sh
    - mkdir -p $HOME/.docker
    - echo $DOCKER_AUTH_CONFIG > $HOME/.docker/config.json
  script:
    - depot build -t registry.gitlab.com/repo/image:tag . --push
  variables:
    DEPOT_TOKEN: $DEPOT_TOKEN
```

Before the `depot build` runs, contents of the `DOCKER_AUTH_CONFIG` environment variable are saved as `$HOME/.docker/config.json`.

You may be able to generate a `config.json` file locally by running `docker login` and then copying the contents of the `$HOME/.docker/config.json` file and saving it as `DOCKER_AUTH_CONFIG`, if you have static authentication credentials for your registry.

## Conclusion

There are multiple options for building Docker images in GitLab CI, each with security and complexity tradeoffs. They are not impossible to work around, but they are inconvenient and cause a lot of friction. This friction can manifest as slow builds, security concerns, or having to maintain complex build infrastructure. It's totally unnecessary.

Instead, you can use Depot to build Docker images in GitLab CI quickly and securely, using Depot's remote builders, without needing to configure `shell` executor runners, work around slow builds with `dind`, or bind mount the Docker socket, and all without having to grant root access to your CI runners.

If your interested in trying out Depot, we offer a [14-day free trial with no credit card required](https://depot.dev/).