Using Mage and the excellent Chainguard Go builder image, this example shows how to build a binary for the current platform and architecture, while wrapping up the entire build process inside the Dagger engine.
The output goes to the standard .artifacts directory, which is typically included in all projects, and should be ignored by Git.
package main
import (
"context"
"os"
"path/filepath"
"runtime"
"dagger.io/dagger"
"github.com/magefile/mage/mg"
"github.com/pterm/pterm"
)
type Build mg.Namespace // Build contains all the build-related Mage targets.
const (
ArtifactDirectory = ".artifacts" // ArtifactDirectory is a directory for project artifacts, and shouldn't be committed to source.
PermissionUserReadWriteExecute = 0o0700 // PermissionUserReadWriteExecute is the permissions for the artifact directory.
)
var TargetBuildDirectory = filepath.Join(ArtifactDirectory, "builds") // TargetBuildDirectory is the directory where the build artifacts will be placed.
// 🔨 MyAppName builds the service using Dagger for the current system architecture.
//
// Development notes: This is a fully containerized build, using Dagger. Requires Docker.
func (Build) MyAppName() error {
ctx := context.Background()
pterm.DefaultHeader.Println("Building with Dagger")
buildThis := "./myApp/main.go" // This is the specific file to build, could be an input variable/slice though
appName := "myApp"
// create the target directory
if err := os.MkdirAll(filepath.Join(TargetBuildDirectory, appName), PermissionUserReadWriteExecute); err != nil {
return err
}
// initialize Dagger client
client, err := dagger.Connect(ctx, dagger.WithLogOutput(os.Stdout))
if err != nil {
return err
}
defer client.Close()
// get reference to the local project
src := client.Host().Directory(".")
cachedBuild := client.CacheVolume("go-build-cache")
cachedMod := client.CacheVolume("go-mod-cache")
modcache := "/nonroot/.cache/go-mod-cache"
buildcache := "/nonroot/.cache/go-build-cache"
// get `golang` image
golang := client.Container().From("cgr.dev/chainguard/go:latest").
WithEnvVariable("CGO_ENABLED", "0").
WithEnvVariable("GOOS", runtime.GOOS).
WithEnvVariable("GOARCH", runtime.GOARCH).
WithEnvVariable("GOMODCACHE", modcache). // Attempt to optimize mod and build caching
WithEnvVariable("GOCACHE", buildcache)
// mount cloned repository into `golang` image
golang = golang.WithMountedDirectory("/src", src).
WithWorkdir("/src").
WithMountedCache(modcache, cachedMod).
WithMountedCache(buildcache, cachedBuild)
// define the application build command
outputDirectory := filepath.Join(TargetBuildDirectory, appName)
outputFile := filepath.Join(outputDirectory, fmt.Sprintf("%s-service",appName))
golang = golang.WithExec([]string{"build", "-o", outputFile, "-ldflags", "-s -w", "-trimpath", buildThis})
// get reference to build output directory in container
output := golang.Directory(outputDirectory).File(fmt.Sprintf("%s-service",appName))
// write contents of container build/ directory to the host
_, err = output.Export(ctx, outputFile)
if err != nil {
return err
}
return nil
}