Skip to main content

GitLab CI

Dagger provides a programmable container engine that allows you to replace your YAML pipeline definitions in GitLab with Dagger Functions written in a regular programming language. This allows you to execute your pipeline the same locally and in GitLab, with the additional benefit of intelligent caching.

How it works

When running a CI pipeline with Dagger using GitLab CI, the general workflow looks like this:

  1. GitLab receives a trigger based on a repository event.
  2. GitLab begins processing the stages and jobs in the .gitlab-ci.yml file.
  3. GitLab downloads the Dagger CLI.
  4. GitLab executes one (or more) Dagger CLI commands, such as dagger call ....
  5. The Dagger CLI attempts to find an existing Dagger Engine or spins up a new one inside the GitLab runner.
  6. The Dagger CLI calls the specified Dagger Function and sends telemetry to Dagger Cloud if the DAGGER_CLOUD_TOKEN environment variable is set.
  7. The pipeline completes with success or failure. Logs appear in GitLab as usual.

Prerequisites

Examples

Docker executor

The following example demonstrates how to call a Dagger Function in a GitLab CI/CD pipeline using the (default) Docker Machine executor or the Docker executor. In both these cases, the Dagger Engine is provisioned "just in time" using a Docker-in-Docker (dind) service.

.gitlab-ci.yml
.docker:
image: docker:latest
services:
- docker:${DOCKER_VERSION}-dind
variables:
DOCKER_HOST: tcp://docker:2376
DOCKER_TLS_VERIFY: '1'
DOCKER_TLS_CERTDIR: '/certs'
DOCKER_CERT_PATH: '/certs/client'
DOCKER_DRIVER: overlay2
DOCKER_VERSION: '27.2.0'
# assumes the Dagger Cloud token is
# in a masked/protected variable named DAGGER_CLOUD_TOKEN
# set via the GitLab UI
DAGGER_CLOUD_TOKEN: $DAGGER_CLOUD_TOKEN
.dagger:
extends: [.docker]
before_script:
- apk add curl
- curl -fsSL https://dl.dagger.io/dagger/install.sh | BIN_DIR=/usr/local/bin sh
hello:
extends: [.dagger]
script:
- dagger -m github.com/shykes/daggerverse/hello@v0.1.2 call hello --greeting="bonjour" --name="monde"
# for ephemeral runners only: override the default docker stop timeout and
# give the Dagger Engine more time to push cache data to Dagger Cloud
- docker stop -t 300 $(docker ps --filter name="dagger-engine-*" -q)

The following is a more complex example demonstrating how to create a GitLab pipeline that checks out source code, calls a Dagger Function to test the project, and then calls another Dagger Function to build and publish a container image of the project. This example uses a simple Go application and assumes that you have already forked it in your own GitLab repository.

.gitlab-ci.yml
.docker:
image: docker:latest
services:
- docker:${DOCKER_VERSION}-dind
variables:
DOCKER_HOST: tcp://docker:2376
DOCKER_TLS_VERIFY: '1'
DOCKER_TLS_CERTDIR: '/certs'
DOCKER_CERT_PATH: '/certs/client'
DOCKER_DRIVER: overlay2
DOCKER_VERSION: '27.2.0'
# assumes the Dagger Cloud token is
# in a masked/protected variable named DAGGER_CLOUD_TOKEN
# set via the GitLab UI
DAGGER_CLOUD_TOKEN: $DAGGER_CLOUD_TOKEN
.dagger:
extends: [.docker]
before_script:
- apk add curl
- curl -fsSL https://dl.dagger.io/dagger/install.sh | BIN_DIR=/usr/local/bin sh
test:
extends: [.dagger]
script:
- dagger -m github.com/kpenfound/dagger-modules/golang@v0.2.0 call test --source=.
# for ephemeral runners only: override the default docker stop timeout and
# give the Dagger Engine more time to push cache data to Dagger Cloud
- docker stop -t 300 $(docker ps --filter name="dagger-engine-*" -q)
build:
extends: [.dagger]
needs: ["test"]
script:
- dagger -m github.com/kpenfound/dagger-modules/golang@v0.2.0 call build-container --source=. --args=. publish --address=ttl.sh/my-app-$RANDOM
# for ephemeral runners only: override the default docker stop timeout and
# give the Dagger Engine more time to push cache data to Dagger Cloud
- docker stop -t 300 $(docker ps --filter name="dagger-engine-*" -q)

Kubernetes executor

The following example demonstrates how to call a Dagger Function in a GitLab CI/CD pipeline using the Kubernetes executor.

.gitlab-ci.yml
.dagger:
image: alpine:latest
variables:
# assumes the Dagger Cloud token is
# in a masked/protected variable named DAGGER_CLOUD_TOKEN
# set via the GitLab UI
DAGGER_CLOUD_TOKEN: $DAGGER_CLOUD_TOKEN
before_script:
- apk add curl
- curl -fsSL https://dl.dagger.io/dagger/install.sh | BIN_DIR=/tmp sh
hello:
extends: [.dagger]
script:
- dagger -m github.com/shykes/daggerverse/hello@v0.1.2 call hello --greeting="bonjour" --name="monde"
# for ephemeral runners only: override the default docker stop timeout and
# give the Dagger Engine more time to push cache data to Dagger Cloud
- docker stop -t 300 $(docker ps --filter name="dagger-engine-*" -q)

The following is a more complex example demonstrating how to create a GitLab pipeline that checks out source code, calls a Dagger Function to test the project, and then calls another Dagger Function to build and publish a container image of the project. This example uses a simple Go application and assumes that you have already forked it in your own GitLab repository.

.gitlab-ci.yml
.dagger:
image: alpine:latest
variables:
# assumes the Dagger Cloud token is
# in a masked/protected variable named DAGGER_CLOUD_TOKEN
# set via the GitLab UI
DAGGER_CLOUD_TOKEN: $DAGGER_CLOUD_TOKEN
before_script:
- apk add curl
- curl -fsSL https://dl.dagger.io/dagger/install.sh | BIN_DIR=/tmp sh
test:
extends: [.dagger]
script:
- dagger -m github.com/kpenfound/dagger-modules/golang@v0.2.0 call test --source=.
# for ephemeral runners only: override the default docker stop timeout and
# give the Dagger Engine more time to push cache data to Dagger Cloud
- docker stop -t 300 $(docker ps --filter name="dagger-engine-*" -q)
build:
extends: [.dagger]
needs: ["test"]
script:
- dagger -m github.com/kpenfound/dagger-modules/golang@v0.2.0 call build-container --source=. --args=. publish --address=ttl.sh/my-app-$RANDOM
# for ephemeral runners only: override the default docker stop timeout and
# give the Dagger Engine more time to push cache data to Dagger Cloud
- docker stop -t 300 $(docker ps --filter name="dagger-engine-*" -q)

In both cases, each GitLab Runner must be configured to only run on nodes with pre-provisioned instances of the Dagger Engine. This is achieved using taints and tolerations on the nodes, and pod affinity.

The following code listings illustrate the configuration to be applied to each GitLab Runner, with taints, tolerations and pod affinity set via the dagger-node key. For an example of the corresponding node configuration, refer to the OpenShift integration page.

To use this configuration, replace the YOUR-GITLAB-URL placeholder with the URL of your GitLab instance and replace the YOUR-GITLAB-RUNNER-TOKEN-REFERENCE placeholder with your GitLab Runner authentication token.

runner-config.yml
kind: ConfigMap
apiVersion: v1
metadata:
name: dagger-custom-config-toml
data:
config.toml: |
concurrent = 10
[[runners]]
environment = ["HOME=/tmp","FF_GITLAB_REGISTRY_HELPER_IMAGE=1", "_EXPERIMENTAL_DAGGER_RUNNER_HOST=unix:///var/run/dagger/buildkitd.sock"]
pre_build_script = "export PATH=\"/tmp/:$PATH\""
name = "GitLab Runner with Dagger"
url = YOUR-GITLAB-URL
executor = "kubernetes"
[runners.kubernetes]
namespace = "dagger"
pull_policy = "always"
privileged = true
[runners.kubernetes.affinity]
[runners.kubernetes.affinity.node_affinity.required_during_scheduling_ignored_during_execution]
[[runners.kubernetes.affinity.node_affinity.required_during_scheduling_ignored_during_execution.node_selector_terms]]
[[runners.kubernetes.affinity.node_affinity.required_during_scheduling_ignored_during_execution.node_selector_terms.match_expressions]]
key = "dagger-node"
operator = "In"
values = ["true"]
[runners.kubernetes.node_tolerations]
"dagger-node" = ""
[runners.kubernetes.pod_security_context]
run_as_non_root = false
run_as_user = 0
[[runners.kubernetes.volumes.host_path]]
name = "dagger"
mount_path = "/var/run/dagger"
host_path = "/var/run/dagger"
runner.yml
apiVersion: apps.gitlab.com/v1beta2
kind: Runner
metadata:
name: dagger-runner
namespace: dagger
spec:
config: dagger-custom-config-toml
gitlabUrl: YOUR-GITLAB-URL
tags: dagger
token: YOUR-GITLAB-RUNNER-TOKEN-REFERENCE
runUntagged: false

Resources

If you have any questions about additional ways to use GitLab with Dagger, join our Discord and ask your questions in our GitLab channel.

About GitLab

GitLab is a popular Web-based platform used for version control and collaboration. It allows developers to store and manage their code in repositories, track changes over time, and collaborate with other developers on projects.