Best practices I collected during writing my Dagger modules.
-
-
Save sagikazarmark/53a77bf72ad494154f691c0ccd968e35 to your computer and use it in GitHub Desktop.
Reusable modules generally operate on a single tool in a container under the hood. Allow specifying the tool version, so silent upgrades won't break your pipelines.
It's also a good practice to allow customizing the container itself (eg. install additional dependencies).
func New(
// Version (image tag) to use from the official image repository as a base container.
//
// +optional
version string,
// Custom container to use as a base container.
//
// +optional
container *Container,
// ...
) *Go {
if container == nil {
if version == "" {
version = defaultVersion
}
container = dag.Container().From(fmt.Sprintf("%s:%s", defaultImageRepository, version))
}
return &Go{container}
}
Note
A previous version of this recommended a third, image
parameter, but it was removed after @shykes made this comment.
I used to write modules that by default mounts cache volumes with some arbitrary default name (for example go-mod
for Go module cache).
Here is an example I used to do:
func New(
// ...
// Disable mounting cache volumes.
// +optional
disableCache bool,
// Go module cache volume.
// +optional
goModCache *CacheVolume,
) *Go {
var ctr *Container
// ...
m := &Go{ctr}
if !disableCache {
if goModCache == nil {
goModCache = dag.CacheVolume("go-mod")
}
m = m.
WithModuleCache(goModCache, nil, "")
}
return m
}
As you can see, there is also an option to disable mounting the cache.
The problem with this approach is you may end up sharing cache volumes across different projects (depending on how you run the engine and/or whether you use Dagger Cloud or not) resulting in a cache that grows endlessly.
As a result, you probably want to explicitly set cache volumes whenever you want to use any cache anyway, so disabling cache mounts by default makes more sense.
That isn't to say you can't have some sort of a default cache that you can enable explicitly if you don't care about the consequences (eg. you don't save the cache anyway).
Alternative approaches:
enableDefaultCache
option in the constructorWithDefaultCache
in your module API
But the differences may be negligible:
m := dag.Go().WithDefaultCache()
// vs
m := dag.Go().WithModuleCache(dag.CacheVolume("my-go-mod")).WithBuildCache(dag.CacheVolume("my-go-build"))
I recommend merging container
and base
in a single argument . They seem redundant to me. Remember you can pass a registry ref to a Container
argument in the CLI, so the string is not needed.
You can take a
CacheVolume
as an optional argument :)
Well, now you can. :) But yeah, that needs updating.
I recommend merging
container
andbase
in a single argument . They seem redundant to me. Remember you can pass a registry ref to aContainer
argument in the CLI, so the string is not needed.
I guess you mean container and image. Yeah, that's a great point, thanks!
BTW I have some more to add to this. Maybe we should convert it to a living document somewhere? Like a wiki.
You can take a
CacheVolume
as an optional argument :)