TL;DR: Dagger.io strømliner dine CI/CD-pipelines, fremtidssikre din applikations leveringsproces og øger din time to deliver.
CI/CD (Continuous Integration/Continuous Deployment) pipelines er blevet en standardmetode til at strømline softwareudvikling. Alligevel kan det være både vanskeligt og tidskrævende at administrere og optimere disse pipelines. Desuden er det dyrt at skifte mellem forskellige CI/CD engines, og det sker derfor sjældent. Her kommer Dagger.io ind i billedet: en programmerbar CI/CD engine, der kører dine pipelines hvor som helst. Ved at benytte Dagger.io og skrive dine pipelines “the Dagger way” vil du være i stand til at bygge løftbare pipelines, der kan køre i enhver CI/CD engine.
Dagger.io er et FOSS (Free and open-source software) skabt og vedligeholdt af nøglepersoner fra Docker teamet: Solomon Hykes, Sam Alba og Andrea Luzzardi.
Fordele ved Dagger.io
Ved at bruge Dagger.io kan vi strømline enhver pipeline og gøre den i stand til at køre hvor som helst vi ønsker. Dette er næste generation af CI-værktøjer og vil kunne erstatte gamle pipelines, der kun er skrevet til fx Jenkins. Dagger.io vil kunne hjælpe med at undgå at blive låst fast til en bestemt leverandør i fremtiden for CI-værktøjer. Nedenfor vises et lille eksempel på en pipeline skrevet i GO, der anvender Dagger SDK. Eksemplet begynder med at starte en ny container. Derefter bruger den containeren til at teste koden, bygge den og til sidst publicere den til et container registry. Bloggen fortsætter under kodeblokken
func main() {
ctx := context.Background()
// initialize Dagger client
client, err := dagger.Connect(ctx, dagger.WithLogOutput(os.Stderr))
if err != nil {
panic(err)
}
defer client.Close()
// use a node:20-slim container
// mount the source code in the container at /src in the container
source := client.Container().
From("node:20-slim").
WithDirectory("/src", client.Host().Directory(".", dagger.HostDirectoryOpts{
Exclude: []string{"node_modules/", "ci/", "build/"},
}))
// set the working directory in the new container
// install necessary application dependencies
runner := source.WithWorkdir("/src").
WithExec([]string{"npm", "install"})
// run application tests
test := runner.WithExec([]string{"npm", "test", "--", "--watchAll=false"})
// build the application and output into build/
buildDir := test.WithExec([]string{"npm", "run", "build"}).
Directory("./build")
// use an nginx:alpine container
// copy the build/ directory from the earlier
// publish the resulting container to a registry
ref, err := client.Container().
From("nginx:1.23-alpine").
WithDirectory("/usr/share/nginx/html", buildDir).
Publish(ctx, fmt.Sprintf("ttl.sh/hello-dagger-%.0f", math.Floor(rand.Float64()*10000000))) //#nosec
if err != nil {
panic(err)
}
fmt.Printf("Published image to: %s\n", ref)
}
- Eksempel fra Dagger.io Docs
Denne pipeline er enkel og kan køres ved hjælp af Dagger CLI i enhver CI/CD engine. GitHub Actions er blot en af de engines som er tilgængelig. Et lille eksempel på dette kan ses nedenfor. Andre motorer inkluderer, men er ikke begrænset til; Circle-CI, AWS Codebuild, Gitlab, Jenkins og endda lokalt ved blot at bruge Docker Engine.
name: 'go ci/cd'
on:
push:
branches:
- main
jobs:
dagger:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Setup Go
uses: actions/setup-go@v4
with:
go-version: '>=1.20'
- name: Install
run: go get dagger.io/dagger@latest
- name: Install Dagger CLI
run: cd /usr/local && { curl -L https://dl.dagger.io/dagger/install.sh | sh; cd -; }
- name: Release and deploy with Dagger
run: dagger run go run ci/main.go
Se det i aktion
At køre en pipeline lokalt kan forbedre konsistensen og fremskynde testning betydeligt. For at vise, hvordan dette kan gøres i praksis, har vi hos Tech Chapter lavet et simpelt eksempel, der er placeret i et public GitHub-repository:
https://github.com/techchapter/dagger-pipeline-example
Når vi kører pipelinen fra vores repo lokalt, får vi et lang output som i bunden viser os, hvordan vi kan køre det oprettede eksporterede image:
Output fra lokal Dagger-kørsel
$ dagger run go run ci/ci.go
Creating new Engine session... OK!
Establishing connection to Engine... 1: connect
1: > in init
1: starting engine
1: starting engine [0.07s]
1: starting session
1: [0.89s] OK!
1: starting session [0.20s]
1: connect DONE
OK!
7: upload . from 3201439c6656 (client id: l0z9uuhafnpu7dadyiks2zjdj) (exclude: ci/, .devcontainer/) DONE
7: > in host.directory .
8: blob://sha256:610f147de71b9045f9103cace3d061632115f56edf4f18947b2975c230bcc16e DONE
8: > in host.directory .
12: resolve image config for docker.io/library/golang:1.21
12: > in from golang:1.21
12: resolve image config for docker.io/library/golang:1.21 DONE
26: pull docker.io/library/golang:1.21
26: > in from golang:1.21
26: pull docker.io/library/golang:1.21 DONE
25: copy / /app
25: copy / /app DONE
26: pull docker.io/library/golang:1.21
26: > in from golang:1.21
26: pull docker.io/library/golang:1.21 DONE
22: exec go mod tidy
22: [0.11s] go: downloading github.com/go-playground/assert/v2 v2.2.0
22: [0.11s] go: downloading github.com/gin-gonic/gin v1.9.1
22: [0.30s] go: downloading google.golang.org/protobuf v1.32.0
22: [0.30s] go: downloading github.com/mattn/go-isatty v0.0.20
22: [0.30s] go: downloading github.com/gin-contrib/sse v0.1.0
22: [0.30s] go: downloading golang.org/x/net v0.20.0
22: [0.30s] go: downloading github.com/go-playground/validator/v10 v10.16.0
22: [0.30s] go: downloading github.com/pelletier/go-toml/v2 v2.1.1
22: [0.30s] go: downloading github.com/bytedance/sonic v1.10.2
22: [0.30s] go: downloading gopkg.in/yaml.v3 v3.0.1
22: [0.30s] go: downloading github.com/ugorji/go/codec v1.2.12
22: [0.30s] go: downloading github.com/goccy/go-json v0.10.2
22: [0.30s] go: downloading github.com/json-iterator/go v1.1.12
22: [0.41s] go: downloading github.com/go-playground/universal-translator v0.18.1
22: [0.41s] go: downloading github.com/gabriel-vasile/mimetype v1.4.3
22: [0.45s] go: downloading github.com/leodido/go-urn v1.2.4
22: [0.45s] go: downloading golang.org/x/crypto v0.18.0
22: [0.55s] go: downloading golang.org/x/text v0.14.0
22: [0.57s] go: downloading github.com/go-playground/locales v0.14.1
22: [0.61s] go: downloading golang.org/x/sys v0.16.0
22: [0.64s] go: downloading github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd
22: [0.64s] go: downloading github.com/modern-go/reflect2 v1.0.2
22: [0.80s] go: downloading github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d
22: [0.83s] go: downloading golang.org/x/arch v0.7.0
22: [1.06s] go: downloading github.com/twitchyliquid64/golang-asm v0.15.1
22: [1.07s] go: downloading github.com/stretchr/testify v1.8.4
22: [1.07s] go: downloading gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c
22: [1.07s] go: downloading github.com/google/go-cmp v0.5.8
22: [1.07s] go: downloading github.com/davecgh/go-spew v1.1.1
22: [1.17s] go: downloading github.com/klauspost/cpuid/v2 v2.2.6
22: [1.28s] go: downloading github.com/pmezard/go-difflib v1.0.0
22: [1.28s] go: downloading github.com/chenzhuoyu/iasm v0.9.1
22: [1.30s] go: downloading github.com/kr/pretty v0.3.1
22: [1.36s] go: downloading github.com/rogpeppe/go-internal v1.11.0
22: [1.36s] go: downloading github.com/kr/text v0.1.0
22: [3.55s] go: downloading github.com/kr/text v0.2.0
22: exec go mod tidy DONE
21: exec go test ./src/
21: [6.86s] ok github.com/techchapter/dagger-pipeline-example/src 0.004s
21: exec go test ./src/ DONE
20: exec go build -o /build/ping-socket ./src/ DONE
29: resolve image config for docker.io/library/alpine:3.19
29: > in from alpine:3.19
29: resolve image config for docker.io/library/alpine:3.19 DONE
35: pull docker.io/library/alpine:3.19
35: > in from alpine:3.19
35: pull docker.io/library/alpine:3.19 DONE
34: copy /build /
35: pull docker.io/library/alpine:3.19
35: > in from alpine:3.19
35: pull docker.io/library/alpine:3.19 DONE
34: copy /build / DONE
DEV environment: exported file to ./ping-socket.tar
To run use docker load -i ./ping-socket.tar
DEV environment: exported file to ./ping-socket.tar
To run use docker load -i ./ping-socket.tar
Hvis vi skulle køre den samme pipeline i GitHub Actions, ville vi få et lignende output, men i stedet for et lokalt image-output, publicerer pipelinen imaget til et registry:
Fuld GitHub Actions log fra Dagger-kørsel
Run dagger run go run ci/ci.go --env prod
1: connect
1: > in init
1: pulling registry.dagger.io/engine:v0.9.5
1: pulling registry.dagger.io/engine:v0.9.5 [3.85s]
1: starting engine
1: starting engine [3.07s]
Connected to engine 89207bc99e41 (version v0.9.5)
1: starting session
1: [8.93s] OK!
1: starting session [0.19s]
1: connect DONE
3: go run ci/ci.go --env prod
3: ...
8: upload . from fv-az1432-522 (client id: yp5rf7fzk3kku0auquqkxe31i) (exclude: ci/, .devcontainer/) DONE
8: > in host.directory .
8: upload . from fv-az1432-522 (client id: yp5rf7fzk3kku0auquqkxe31i) (exclude: ci/, .devcontainer/) DONE
3: go run ci/ci.go --env prod
3: ...
13: resolve image config for docker.io/library/golang:1.21
13: > in from golang:1.21
13: resolve image config for docker.io/library/golang:1.21 DONE
27: pull docker.io/library/golang:1.21
27: > in from golang:1.21
27: resolve docker.io/library/golang:1.21@sha256:7026fb72cfa9cc112e4d1bf4b35a15cac61a413d0252d06615808e7c987b33a7
27: resolve docker.io/library/golang:1.21@sha256:7026fb72cfa9cc112e4d1bf4b35a15cac61a413d0252d06615808e7c987b33a7 [0.01s]
27: pull docker.io/library/golang:1.21 DONE
26: copy / /app
26: copy / /app DONE
27: pull docker.io/library/golang:1.21
27: > in from golang:1.21
27: pull docker.io/library/golang:1.21 DONE
23: exec go mod tidy
23: [0.08s] go: downloading github.com/gin-gonic/gin v1.9.1
23: [0.08s] go: downloading github.com/go-playground/assert/v2 v2.2.0
23: [0.23s] go: downloading github.com/gin-contrib/sse v0.1.0
23: [0.23s] go: downloading github.com/mattn/go-isatty v0.0.20
23: [0.23s] go: downloading golang.org/x/net v0.20.0
23: [0.26s] go: downloading google.golang.org/protobuf v1.32.0
23: [0.48s] go: downloading github.com/stretchr/testify v1.8.4
23: [0.61s] go: downloading github.com/bytedance/sonic v1.10.2
23: [0.65s] go: downloading github.com/goccy/go-json v0.10.2
23: [0.67s] go: downloading github.com/json-iterator/go v1.1.12
23: [0.67s] go: downloading github.com/go-playground/validator/v10 v10.16.0
23: [0.78s] go: downloading github.com/pelletier/go-toml/v2 v2.1.1
23: [0.78s] go: downloading github.com/ugorji/go/codec v1.2.12
23: [0.78s] go: downloading gopkg.in/yaml.v3 v3.0.1
23: [0.81s] go: downloading golang.org/x/sys v0.16.0
23: [0.83s] go: downloading github.com/davecgh/go-spew v1.1.1
23: [0.83s] go: downloading github.com/pmezard/go-difflib v1.0.0
23: [0.84s] go: downloading github.com/google/go-cmp v0.5.8
23: [0.85s] go: downloading github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd
23: [0.86s] go: downloading github.com/modern-go/reflect2 v1.0.2
23: [0.87s] go: downloading github.com/gabriel-vasile/mimetype v1.4.3
23: [0.88s] go: downloading github.com/go-playground/universal-translator v0.18.1
23: [0.88s] go: downloading github.com/leodido/go-urn v1.2.4
23: [0.89s] go: downloading golang.org/x/crypto v0.18.0
23: [0.94s] go: downloading golang.org/x/text v0.14.0
23: [1.06s] go: downloading github.com/go-playground/locales v0.14.1
23: [1.84s] go: downloading gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c
23: [1.88s] go: downloading github.com/kr/pretty v0.3.1
23: [1.88s] go: downloading github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d
23: [1.88s] go: downloading golang.org/x/arch v0.7.0
23: [1.88s] go: downloading github.com/twitchyliquid64/golang-asm v0.15.1
23: [1.90s] go: downloading github.com/klauspost/cpuid/v2 v2.2.6
23: [1.94s] go: downloading github.com/kr/text v0.1.0
23: [1.94s] go: downloading github.com/rogpeppe/go-internal v1.11.0
23: [1.94s] go: downloading github.com/chenzhuoyu/iasm v0.9.1
23: [2.17s] go: downloading github.com/kr/text v0.2.0
23: exec go mod tidy DONE
22: exec go test ./src/
22: [16.1s] ok github.com/techchapter/dagger-pipeline-example/src 0.005s
22: exec go test ./src/ DONE
21: exec go build -o /build/ping-socket ./src/ DONE
30: resolve image config for docker.io/library/alpine:3.19
30: > in from alpine:3.19
30: resolve image config for docker.io/library/alpine:3.19 DONE
35: pull docker.io/library/alpine:3.19
35: > in from alpine:3.19
35: pull docker.io/library/alpine:3.19 DONE
34: copy /build /
34: copy /build / DONE
Published image to: ttl.sh/ping-socket-5507822@sha256:e335659c6f89315574c4f5245da2a666981e7f0fb902c14d28d2ac1608082748
3: go run ci/ci.go --env prod DONE
Published image to: ttl.sh/ping-socket-5507822@sha256:e335659c6f89315574c4f5245da2a666981e7f0fb902c14d28d2ac1608082748
Konklusion: Tag din CI/CD-pipeline til næste niveau med Dagger.io
For at opsummere, Dagger.io er en effektiv løsning, der kan fremme din kontinuerlige integrations- og leveringspipeline, ved at løse almindelige udfordringer som at opretholde konsistens på tværs af miljøer, håndtere testning, bygning og publicering, samt tillade langvarig brug uden besværet med at omskrive fra bunden. Dagger.io hjælper med at forenkle softwareleveringsprocessen ved at være det nye værktøj til løftbare CI/CD-pipelines. Vores bedste anbefalinger vil være at implementere Dagger som dit nye CI-værktøj og implementere det sammen med et GitOps-værktøj som Argo-CD for at opnå den højeste portabilitet og bedst strømlinede opsætning.
Læs mere om Dagger.io og hvordan vi kan hjælpe dig med at implementere det på vores side om færdigheder.
Tag et kig på vores andre Tech Chapter blog posts.