Skip to main content

Use Dagger with Tekton

Introduction

Tekton is an open source framework for CI/CD implementation, with built-in support for Kubernetes and other CI/CD tools. This guide explains how to run Dagger pipelines using Tekton.

Requirements

This guide assumes that:

Step 1: Install Tekton

The first step is to install Tekton in the Kubernetes cluster and the Tekton CLI.

Follow the Tekton installation instructions and the Tekton CLI installation steps, adjusting them as needed to your own requirements. Once you've successfully installed Tekton and the Tekton CLI, continue to the next step.

Step 2: Install the git-clone Task

Next, install the git-clone Task from Tekton Hub. This Task adds repository cloning capabilities to your Tekton Pipeline, and is used by the Tekton Pipeline defined later in this guide.

tkn hub install task git-clone

Step 3: Create a Tekton Pipeline, Task and PipelineRun

Follow the steps below:

  1. Define a new Tekton Pipeline as follows, in a file named git-pipeline.yaml.

    apiVersion: tekton.dev/v1beta1
    kind: Pipeline
    metadata:
    name: dagger-pipeline
    spec:
    description: |
    This pipeline clones a Git repository, then runs the Dagger pipeline.
    params:
    - name: repo-url
    type: string
    description: The Git repository clone URL
    - name: dagger-cloud-token
    type: string
    description: The Dagger Cloud token
    workspaces:
    - name: shared-data
    description: |
    This workspace contains the cloned repository files, so they can be read by the
    next task.
    tasks:
    - name: fetch-source
    taskRef:
    name: git-clone
    workspaces:
    - name: output
    workspace: shared-data
    params:
    - name: url
    value: $(params.repo-url)
    - name: dagger
    runAfter: ["fetch-source"]
    taskRef:
    name: dagger
    workspaces:
    - name: source
    workspace: shared-data
    params:
    - name: dagger-cloud-token
    value: $(params.dagger-cloud-token)

    This Pipeline references two Tasks:

    • The git-clone Task, to check out the Git repository for the project into a Tekton Workspace;
    • A custom dagger Task, to run the Dagger pipeline for the project (defined below).
  2. Define a new Tekton Task as follows, in a file named dagger-task.yaml.

    apiVersion: tekton.dev/v1beta1
    kind: Task
    metadata:
    name: dagger
    spec:
    description: Run Dagger pipeline
    workspaces:
    - name: source
    params:
    - name: dagger-cloud-token
    type: string
    description: Dagger Cloud Token
    volumes:
    - name: dagger-socket
    emptyDir: {}
    - name: dagger-storage
    emptyDir: {}
    sidecars:
    - name: dagger-engine
    image: registry.dagger.io/engine:v0.9.1
    args:
    - "--oci-max-parallelism"
    - "num-cpu"
    securityContext:
    privileged: true
    capabilities:
    add:
    - ALL
    readinessProbe:
    exec:
    command: ["buildctl", "debug", "workers"]
    volumeMounts:
    - mountPath: /var/run/buildkit
    name: dagger-socket
    - mountPath: /var/lib/dagger
    name: dagger-storage
    env:
    - name: DAGGER_CLOUD_TOKEN
    value: $(params.dagger-cloud-token)
    steps:
    - name: read
    image: docker:dind
    workingDir: $(workspaces.source.path)
    script: |
    #!/usr/bin/env sh
    apk add nodejs npm curl
    curl https://dl.dagger.io/dagger/install.sh | BIN_DIR=/usr/local/bin sh
    npm i @dagger.io/dagger@latest
    dagger run node ./ci/index.mjs
    volumeMounts:
    - mountPath: /var/run/dagger
    name: dagger-socket
    env:
    - name: _EXPERIMENTAL_DAGGER_RUNNER_HOST
    value: unix:///var/run/dagger/buildkitd.sock
    - name: DAGGER_CLOUD_TOKEN
    value: $(params.dagger-cloud-token)

    This Task installs the dependencies needed to execute the Dagger pipeline for the project (which was checked out in the previous Tekton Pipeline) and then executes the pipeline using the npm run ci command.

  3. Define a new Tekton PipelineRun as follows, in a file named git-pipeline-run.yaml.

    apiVersion: tekton.dev/v1beta1
    kind: PipelineRun
    metadata:
    generateName: clone-read-run-
    spec:
    pipelineRef:
    name: dagger-pipeline
    podTemplate:
    securityContext:
    fsGroup: 65532
    workspaces:
    - name: shared-data
    volumeClaimTemplate:
    spec:
    accessModes:
    - ReadWriteOnce
    resources:
    requests:
    storage: 1Gi
    params:
    - name: repo-url
    value: YOUR_REPOSITORY_URL
    - name: dagger-cloud-token
    value: YOUR_DAGGER_CLOUD_TOKEN

    This PipelineRun corresponds to the Tekton Pipeline created previously. It executes the Tekton Pipeline with a given set of input parameters: the Git repository URL and an optional Dagger Cloud token. Update the YOUR_REPOSITORY_URL placeholder with the correct repository URL and, if you have a Dagger Cloud token, replace the YOUR_DAGGER_CLOUD_TOKEN placeholder with the token or a Kubernetes secret holding the token.

A few important points to note:

  • In the Task, the Dagger Engine runs as a sidecar and shares a socket with the Task itself. The Task uses dind as its runtime in order to have Docker available.
  • Setting the DAGGER_CLOUD_TOKEN environment variable in the Task and the dagger-cloud-token parameter in the Pipeline and PipelineRun is only necessary if integrating with Dagger Cloud.

Step 4: Run the Pipeline

  1. Apply the configuration:

    kubectl apply -f dagger-task.yaml
    kubectl apply -f git-pipeline-yaml
  2. Run the Tekton Pipeline:

    kubectl create -f git-pipeline-run.yaml

    The output will look something like pipelinerun.tekton.dev/clone-read-run-mwvkm created To see the logs from the PipelineRun, obtain the PipelineRun name from the output and run tkn pipelinerun logs clone-read-run-<id> -f.

Once the PipelineRun has successfully completed, run it again. Dagger's caching should result in a significantly faster second execution.

Conclusion

This example demonstrated how to integrate Dagger into a Tekton Pipeline using a custom Task.

To learn more about Dagger, use the API Key Concepts page and the Go, Node.js and Python SDK References. For more information on Tekton, refer to the official documentation.

Appendix A: Create a GitHub repository with an example project

This guide assumes that you have a Git repository with a project and a Dagger pipeline. If you don't, follow the steps below to create a GitHub repository and add a simple project and Dagger pipeline to it.

  1. Clone the Dagger starter application:
git clone git@github.com:dagger/hello-dagger.git
  1. Create a new ci subdirectory:
cd hello-dagger
mkdir ci && cd ci
  1. Add a simple Dagger pipeline as index.mjs:
index.mjs
import { connect } from "@dagger.io/dagger"

connect(
async (client) => {
// use a node:16-slim container
// mount the source code directory on the host
// at /src in the container
const source = client
.container()
.from("node:16-slim")
.withDirectory(
"/src",
client.host().directory(".", {
exclude: ["node_modules/", "ci/", "build/", ".git/"],
}),
)

// set the working directory in the container
// install application dependencies
const runner = source
.withWorkdir("/src")
.withMountedCache(
"/src/node_modules",
client.cacheVolume("node_module_cache"),
)
.withExec(["npm", "install"])

// run application tests
const test = runner.withExec(["npm", "test", "--", "--watchAll=false"])

// build application
// write the build output to the host
await test
.withExec(["npm", "run", "build"])
.directory("./build")
.export("./build")

// use an nginx:alpine container
// copy the build/ directory into the container filesystem
// at the nginx server root
// publish the resulting container to a registry
const imageRef = await client
.container()
.from("nginx:1.23-alpine")
.withDirectory(
"/usr/share/nginx/html",
client.host().directory("./build"),
)
.publish("ttl.sh/hello-dagger-" + Math.floor(Math.random() * 10000000))
console.log(`Published image to: ${imageRef}`)
},
{ LogOutput: process.stderr },
)
  1. Commit the changes:
cd ..
git add .
git commit -m "Initial commit"
  1. Log in to GitHub using the GitHub CLI:
gh auth login
  1. Create a repository in your GitHub account and push the changes to it:
gh repo create myapp --push --remote upstream --source . --public