Pular para o conteúdo

Dagger

Motor de CI/CD programavel que executa pipelines em conteineres usando SDKs de Go, Python ou TypeScript.

ComandoDescricao
curl -fsSL https://dl.dagger.io/dagger/install.sh | shInstalar a CLI do Dagger no Linux/macOS
brew install dagger/tap/daggerInstalar no macOS com Homebrew
choco install daggerInstalar no Windows com Chocolatey
scoop install daggerInstalar no Windows com Scoop
nix profile install nixpkgs#daggerInstalar no NixOS/com Nix
dagger versionMostrar a versao do Dagger instalada
ComandoDescricao
dagger initInicializar um novo modulo Dagger
dagger init --sdk=pythonInicializar modulo com SDK Python
dagger init --sdk=typescriptInicializar modulo com SDK TypeScript
dagger init --sdk=goInicializar modulo com SDK Go
dagger init --name=my-pipelineInicializar modulo com nome personalizado
dagger init --sdk=go --source=./ciInicializar em um subdiretorio
ComandoDescricao
dagger callChamar uma funcao do modulo atual
dagger call buildChamar a funcao de build
dagger call test --source=.Chamar funcao de teste com argumento de origem
dagger call build --source=. export --path=./distCompilar e exportar saida localmente
dagger call lint --source=. stdoutExecutar lint e imprimir stdout
dagger call publish --source=. --tag=v1.0Chamar funcao de publicacao com tag
dagger functionsListar funcoes disponiveis no modulo
dagger shellAbrir shell interativo do Dagger
dagger queryExecutar consulta GraphQL bruta contra o motor
dagger run cmdExecutar comando dentro de uma sessao Dagger
ComandoDescricao
dagger loginAutenticar com o Dagger Cloud
dagger logoutRemover autenticacao
dagger configExibir configuracao do modulo
dagger cloud tracesVisualizar traces de pipeline no Dagger Cloud
DAGGER_CLOUD_TOKEN=token dagger call buildExecutar com token do Dagger Cloud
ComandoDescricao
dagger install github.com/org/repoInstalar um modulo de dependencia
dagger install github.com/org/repo@v1.0Instalar versao especifica
dagger install github.com/org/repo/subpathInstalar modulo de subdiretorio
dagger developGerar/atualizar bindings do SDK
dagger develop --sdk=pythonMudar modulo para SDK diferente
dagger mod syncSincronizar dependencias do modulo
dagger mod updateAtualizar dependencias do modulo
dagger publish ttl.sh/my-modulePublicar modulo no registro
dagger publish ghcr.io/org/module:v1.0Publicar no GitHub Container Registry
ComandoDescricao
func (m *MyModule) Build(ctx context.Context, src *dagger.Directory) *dagger.ContainerDefinir funcao de build
dag.Container().From("golang:1.22")Criar conteiner a partir de imagem
container.WithDirectory("/src", src)Montar diretorio no conteiner
container.WithExec([]string{"go", "build", "."})Executar comando no conteiner
container.WithEnvVariable("KEY", "value")Definir variavel de ambiente
container.File("/app/binary")Obter arquivo do conteiner
container.Directory("/app/dist")Obter diretorio do conteiner
container.WithServiceBinding("db", dbSvc)Vincular dependencia de servico
container.WithWorkdir("/src")Definir diretorio de trabalho
container.WithUser("nonroot")Definir usuario do conteiner
container.Publish(ctx, "ttl.sh/my-image")Publicar conteiner como imagem
container.Export(ctx, "./output.tar")Exportar conteiner como tarball
package main

import (
	"context"
	"dagger/my-pipeline/internal/dagger"
)

type MyPipeline struct{}

func (m *MyPipeline) Build(ctx context.Context, src *dagger.Directory) *dagger.Container {
	goCache := dag.CacheVolume("go-mod")
	buildCache := dag.CacheVolume("go-build")

	return dag.Container().
		From("golang:1.22-alpine").
		WithMountedCache("/go/pkg/mod", goCache).
		WithMountedCache("/root/.cache/go-build", buildCache).
		WithDirectory("/src", src).
		WithWorkdir("/src").
		WithExec([]string{"go", "mod", "download"}).
		WithExec([]string{"go", "build", "-o", "/app/server", "./cmd/server"})
}

func (m *MyPipeline) Test(ctx context.Context, src *dagger.Directory) (string, error) {
	return m.Build(ctx, src).
		WithExec([]string{"go", "test", "-v", "./..."}).
		Stdout(ctx)
}

func (m *MyPipeline) Publish(ctx context.Context, src *dagger.Directory, tag string) (string, error) {
	build := m.Build(ctx, src)
	return dag.Container().
		From("cgr.dev/chainguard/static:latest").
		WithFile("/app/server", build.File("/app/server")).
		WithEntrypoint([]string{"/app/server"}).
		Publish(ctx, "ttl.sh/my-app:"+tag)
}
ComandoDescricao
@functionDecorar funcao para expor ao Dagger
async def build(self, src: dagger.Directory) -> dagger.ContainerDefinir funcao de build assincrona
dag.container().from_("python:3.12")Criar conteiner a partir de imagem
container.with_directory("/src", src)Montar diretorio
container.with_exec(["pip", "install", "-r", "requirements.txt"])Executar pip install
await container.stdout()Obter saida do comando
container.with_workdir("/app")Definir diretorio de trabalho
container.with_user("nonroot")Definir usuario do conteiner
await container.publish("ttl.sh/my-app")Publicar conteiner como imagem
import dagger
from dagger import dag, function, object_type

@object_type
class MyPipeline:
    @function
    async def build(self, src: dagger.Directory) -> dagger.Container:
        pip_cache = dag.cache_volume("pip")
        return (
            dag.container()
            .from_("python:3.12-slim")
            .with_mounted_cache("/root/.cache/pip", pip_cache)
            .with_directory("/app", src)
            .with_workdir("/app")
            .with_exec(["pip", "install", "--no-cache-dir", "-r", "requirements.txt"])
            .with_exec(["pip", "install", "."])
        )

    @function
    async def test(self, src: dagger.Directory) -> str:
        return await (
            self.build(src)
            .with_exec(["pytest", "-v", "--tb=short"])
            .stdout()
        )

    @function
    async def lint(self, src: dagger.Directory) -> str:
        return await (
            self.build(src)
            .with_exec(["ruff", "check", "."])
            .stdout()
        )

    @function
    async def publish(self, src: dagger.Directory, tag: str) -> str:
        build = self.build(src)
        return await (
            dag.container()
            .from_("cgr.dev/chainguard/python:latest")
            .with_directory("/app", build.directory("/app"))
            .with_entrypoint(["python", "-m", "myapp"])
            .publish(f"ttl.sh/my-python-app:{tag}")
        )
import { dag, Container, Directory, object, func } from "@dagger.io/dagger"

@object()
class MyPipeline {
  @func()
  build(src: Directory): Container {
    const nodeCache = dag.cacheVolume("node-modules")
    return dag
      .container()
      .from("node:20-slim")
      .withMountedCache("/app/node_modules", nodeCache)
      .withDirectory("/app", src)
      .withWorkdir("/app")
      .withExec(["npm", "ci"])
      .withExec(["npm", "run", "build"])
  }

  @func()
  async test(src: Directory): Promise<string> {
    return this.build(src)
      .withExec(["npm", "test"])
      .stdout()
  }

  @func()
  async lint(src: Directory): Promise<string> {
    return this.build(src)
      .withExec(["npm", "run", "lint"])
      .stdout()
  }

  @func()
  async publish(src: Directory, tag: string): Promise<string> {
    return dag
      .container()
      .from("cgr.dev/chainguard/node:latest")
      .withDirectory("/app", this.build(src).directory("/app/dist"))
      .withEntrypoint(["node", "/app/index.js"])
      .publish(`ttl.sh/my-node-app:${tag}`)
  }
}
ComandoDescricao
container.WithMountedCache("/go/pkg", dag.CacheVolume("gomod"))Montar volume de cache persistente (Go)
container.with_mounted_cache("/root/.cache/pip", dag.cache_volume("pip"))Montar cache do pip (Python)
dag.CacheVolume("node-modules")Criar volume de cache nomeado
container.WithMountedCache("/root/.cache/go-build", dag.CacheVolume("gobuild"))Cachear artefatos de build Go
container.WithMountedCache("/root/.npm", dag.CacheVolume("npm"))Cachear pacotes npm
container.WithMountedCache("/root/.cargo/registry", dag.CacheVolume("cargo"))Cachear dependencias Rust
ComandoDescricao
container.WithEnvVariable("CACHE_BUSTER", time.Now().String())Invalidar cache quando necessario
dagger call --focus=false buildExecutar sem foco/cache automatico
container.WithoutEnvVariable("CACHE_BUSTER")Remover variavel de invalidacao de cache
ComandoDescricao
dag.SetSecret("token", os.Getenv("API_TOKEN"))Criar segredo a partir de variavel de ambiente
container.WithSecretVariable("API_KEY", secret)Definir variavel de ambiente a partir de segredo
container.WithMountedSecret("/run/secrets/key", secret)Montar segredo como arquivo
dagger call deploy --token=env:API_TOKENPassar segredo do ambiente via CLI
dagger call deploy --token=file:./token.txtPassar segredo de arquivo via CLI
dagger call deploy --token=cmd:"vault read -field=token secret/app"Passar segredo de comando
ComandoDescricao
container.WithServiceBinding("db", dbSvc)Vincular um servico a um conteiner
container.WithExposedPort(8080)Expor uma porta de um conteiner
container.AsService()Converter conteiner em um servico
dag.Container().From("postgres:16").WithExposedPort(5432).AsService()Criar um servico de banco de dados
service.Start(ctx)Iniciar um servico explicitamente
service.Stop(ctx)Parar um servico em execucao
func (m *MyPipeline) IntegrationTest(ctx context.Context, src *dagger.Directory) (string, error) {
	postgres := dag.Container().
		From("postgres:16-alpine").
		WithEnvVariable("POSTGRES_PASSWORD", "test").
		WithEnvVariable("POSTGRES_DB", "testdb").
		WithExposedPort(5432).
		AsService()

	redis := dag.Container().
		From("redis:7-alpine").
		WithExposedPort(6379).
		AsService()

	return m.Build(ctx, src).
		WithServiceBinding("db", postgres).
		WithServiceBinding("cache", redis).
		WithEnvVariable("DATABASE_URL", "postgres://postgres:test@db:5432/testdb").
		WithEnvVariable("REDIS_URL", "redis://cache:6379").
		WithExec([]string{"go", "test", "-v", "-tags=integration", "./..."}).
		Stdout(ctx)
}
func (m *MyPipeline) BuildProduction(ctx context.Context, src *dagger.Directory) *dagger.Container {
	// Estagio 1: Compilar dependencias
	deps := dag.Container().
		From("golang:1.22-alpine").
		WithDirectory("/src", src, dagger.ContainerWithDirectoryOpts{
			Include: []string{"go.mod", "go.sum"},
		}).
		WithWorkdir("/src").
		WithMountedCache("/go/pkg/mod", dag.CacheVolume("gomod")).
		WithExec([]string{"go", "mod", "download"})

	// Estagio 2: Compilar binario
	build := deps.
		WithDirectory("/src", src).
		WithExec([]string{"go", "build", "-ldflags=-s -w", "-o", "/app/server", "./cmd/server"})

	// Estagio 3: Runtime minimo
	return dag.Container().
		From("cgr.dev/chainguard/static:latest").
		WithFile("/app/server", build.File("/app/server")).
		WithExposedPort(8080).
		WithEntrypoint([]string{"/app/server"})
}
name: CI with Dagger
on:
  push:
    branches: [main]
  pull_request:

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Install Dagger
        run: |
          curl -fsSL https://dl.dagger.io/dagger/install.sh | sh
          sudo mv ./bin/dagger /usr/local/bin/
      - name: Run pipeline
        env:
          DAGGER_CLOUD_TOKEN: ${{ secrets.DAGGER_CLOUD_TOKEN }}
        run: |
          dagger call build --source=.
          dagger call test --source=.
          dagger call lint --source=.
      - name: Publish
        if: github.ref == 'refs/heads/main'
        run: |
          dagger call publish --source=. --tag=${{ github.sha }}
stages:
  - build
  - test

variables:
  DAGGER_CLOUD_TOKEN: $DAGGER_CLOUD_TOKEN

build:
  stage: build
  image: alpine:latest
  before_script:
    - apk add curl
    - curl -fsSL https://dl.dagger.io/dagger/install.sh | sh
    - export PATH=$PWD/bin:$PATH
  script:
    - dagger call build --source=.
    - dagger call test --source=.
ComandoDescricao
dagger call --debug buildExecutar com log de depuracao
dagger call build --interactiveAbrir shell interativo em caso de falha
container.WithExec(["sh", "-c", "cat /etc/os-release"])Depurar conteudo do conteiner
container.Terminal()Abrir terminal no conteiner (Go)
export DAGGER_LOG_LEVEL=debugDefinir log detalhado
dagger query '{ container { from(address:"alpine") { exec(args:["ls"]) { stdout } } } }'Depurar com GraphQL bruto
dagger call build 2>&1 | tee dagger-output.logSalvar saida em arquivo de log
container.WithExec(["ls", "-la", "/app"])Listar arquivos para depuracao
container.WithExec(["env"])Imprimir variaveis de ambiente
  1. Use volumes de cache generosamente — monte caches para gerenciadores de pacotes (pip, npm, cargo, modulos Go) para reduzir drasticamente os tempos de build entre execucoes.

  2. Mantenha modulos pequenos e componiveis — divida pipelines grandes em funcoes reutilizaveis que fazem uma coisa bem feita, depois componha-as.

  3. Use segredos em vez de variaveis de ambiente — nunca passe valores sensiveis como strings simples; sempre use dag.SetSecret() ou referencias de segredos da CLI.

  4. Fixe versoes de imagens base — use tags especificas como golang:1.22 em vez de latest para builds reproduziveis.

  5. Aproveite padroes multi-estagio — separe dependencias de build do runtime para produzir conteineres finais minimos.

  6. Use vinculacao de servicos para testes de integracao — inicie bancos de dados, caches e outras dependencias como servicos em vez de simula-los.

  7. Exporte artefatos explicitamente — use .Export() ou .Publish() para disponibilizar saidas fora do motor Dagger.

  8. Habilite o Dagger Cloud — conecte-se ao Dagger Cloud para cache de pipeline, rastreamento e depuracao colaborativa.

  9. Use --interactive para depuracao — quando uma etapa falha, --interactive coloca voce dentro do conteiner no ponto de falha.

  10. Teste localmente antes do CI — pipelines Dagger rodam de forma identica em laptops e no CI, entao valide tudo localmente primeiro.