#can i copy from a container dir to a mounted volume in another container

1 messages · Page 1 of 1 (latest)

fallow smelt
#

hi folks. I am trying to copy files to my mounted volume cache

    cont := it.newContainer().
        WithDirectory(t3dp.app.latest, t3dp_cont.Directory(t3dp.app.bld))
func newContainer 
...
    return dag.Container().From("alpine:latest").
        //
        WithMountedCache(bldconf.cache, dag.CacheVolume("cont-cache")).
        WithEnvVariable("CONT_CACHE", bldconf.cache)

is this currently allowed ? i am trying to save binaries between dagger runs

rain path
#

@fallow smelt I believe cache volumes are only mounted during withExec. So withDirectory would not have access to the mounted volumes. Can you try withExec("cp ...") ?

fallow smelt
#

oh great .. but where am i cp from ?

#

those three dots .. lol

#

i think you mean mount the dir then copy ? i assume

rain path
#

once you setup a cache volume (WithMountedCache) it will be automatically mounted at all following calls to WithExec

#
cont := it.
 newContainer().
 WithMountedDirectory("/tmp/app", t3dp.app.bld).
 WithExec([]string{"cp", "-r", "/tmp/app", 3dp.app.latest)
fallow smelt
#

cooool thanks seem like it works yaaaay !

fallow smelt
#
    bldrcont := it.cloneGitRepo(tools).
        WithEnvVariable("PATH", t3dp.app.latest+":${PATH}",
            dagger.ContainerWithEnvVariableOpts{Expand: true},
        ).
    WithDirectory(t3dp.app.latest, t3dpcont.Directory(t3dp.app.latest)).
    WithExec([]string{"sh", "-c", "make rel"})

i am assuming this is also not allowed ? i am trying to mount the previously built binaries in the builder container. do i have to do the copy again ?

rain path
fallow smelt
# rain path can you distil your snippet to the core calls relevant to your question? Since I...

my apologies. i am trying to use tools located in my cached volume

    // copy from cache to a container
    cache := dag.Container()
        //
        WithMountedCache("/t3dp", dag.CacheVolume("cache-t3dp"))

    dag.Container().
        WithEnvVariable("PATH", "/t3dp/app/latest:${PATH}",
            dagger.ContainerWithEnvVariableOpts{Expand: true},
        ).
    WithDirectory("/t3dp/app/latest", cache.Directory("/t3dp/app/latest")).
    // use the tools from the cache volume
    WithExec([]string{"sh", "-c", "/t3dp/app/latest/my-tool do some work"}).

i need to be able to write to this cached folder and use it somewhere else in the code

#

do i have to first copy it in the target container ?

rain path
#

Oh I see, yes indeed that won't work either, the only way to read or write to a cache volume is by executing a command (withExec)

fallow smelt
#

coool ! thank you !!!

#

mmmm .. i am sorry but ... technically the above is a "withexec" ... why would it not work ?

fallow smelt
#

oh apologies again ... i thought i was using WithMountedDirectory

  // copy from cache to a container
    cache := dag.Container()
        //
        WithMountedCache("/t3dp", dag.CacheVolume("cache-t3dp"))

    dag.Container().
        WithEnvVariable("PATH", "/t3dp/app/latest:${PATH}",
            dagger.ContainerWithEnvVariableOpts{Expand: true},
        ).
        WithMountedDirectory("/t3dp/app/latest", cache.Directory("/t3dp/applatest")).
    // use the tools from the cache volume
    WithExec([]string{"sh", "-c", "/t3dp/app/latest/my-tool do some work"}).

my assumption is this should work ?

fallow smelt
#

i now have a simple example to show this failing. i can push to git if needed but here is a gist

#
✔ connect 0.3s
✔ initialize 3.8s
✔ prepare 0.0s
✔ tester: Tester! 0.0s
✘ Tester.buildTools: Container! 1.1s
! call function "BuildTools": process "/runtime" did not complete successfully: exit code: 2
┃ marshal: json: error calling MarshalJSON for type *dagger.Container: input: container.from.withMountedCache.withEnvVariable.withExec.directory resolve: /t3dp/app/latest: cannot retrieve path from cache                                                     
  ✔ Container.from(address: "alpine:latest"): Container! 0.6s
  ✘ Container.directory(path: "/t3dp/app/latest"): Directory! 0.0s
  ! /t3dp/app/latest: cannot retrieve path from cache
rain path
#

@fallow smelt I think what you want to do is mount the same cache in one container, then the other.

#

For example:

func (it *Tester) Demo(ctx context.Context) (string, error) {
 var err error
 cache := dag.CacheVolume("t3dp-cache")
 ctr1 := dag.Container().From("alpine").WithMountedCache("/cache", cache).WithExec([]string{"sh", "-c", "echo hello from container 1 > /cache/message.txt"})
 // Force execution of the first container, otherwise the engine won't see a dependency between ctr1 and ctr2
 ctr1, _ := ctr1.Sync(ctx)
 ctr2 := dag.Container().From("alpine").WithMountedCache("/cache", cache).WithExec([]string{"cat", "/cache/message.txt"})
 return ctr2.Stdout(ctx)
}
#

But it does feel weird to use cache volume in that way, it kind of creates a "shadow dag" (which is why my example requires forcing sync).

#

I think your approach is sound, it's just that you need to copy files out of the cache volume during your withExec, so that other operations can reach them

#

So:

func (it *Tester) CleanerDemo(ctx context.Context) (string, error) {
 var err error
 cache := dag.CacheVolume("t3dp-cache")
 outputDir := dag.
  Container().
  From("alpine").
  WithMountedCache("/cache", cache).
  WithExec([]string{"sh", "-c", "echo hello from container 1 > /cache/message.txt && cp -r /cache/ /output"}).
  Directory("/output")
 return dag.
  Container().
  From("alpine").
  WithDirectory("/data", outputDir).
  WithExec([]string{"cat", "/data/message.txt"}).
  Stdout(ctx)
}
#

Note the cp -r /cache/ /output this is the missing piece (I think) in your solution

#

Maybe I'm missing a cleaner way? cc @rustic needle @vernal moon @severe coral @tall fulcrum

rustic needle
#

Yes you need to do a cp like that right now if you want to move files/dirs out of a cache volume

rain path
#

But wasn't there a magical call where you could access a mount from a container? I vaguely remember something like that

#

The original intent of the core API spec was that Container.directory() would include all the mounts, whereas Container.rootfs.directory() would not - but I think that subtlety was lost in the shuffle and we never picked it back up (in part because it would be super hard to do). I still think we should support it, exactly for this kid of use case.

fallow smelt
#

indeeed it really complicates the code to save a directory and later use its results between runs. i am trying to now publish to a local registry instead see if the code becomes less overburden with the extra copying.

//to publish
tools_image.Publish(ctx, toolsCfg.Url)

//to get it back
tools_cont := dag.Container().From(toolsCfg.Url)
rain path
#

In my experience the extra copying is still the simplest way 🙂

#

Because the hack is contained in that one withExec, and everything is pretty clean

#

With a registry the hack is spreading to your infra

fallow smelt
#

the hope is that the api becomes much clearer

#

indeeeed .. i was mostly adressing from an api perspective

rain path
#

Typically the cache volume logic is tooling-specific, so for example you may have an npmBuild() function that produces a clean output directory, and it handles the cache volume / copying dance

#

This is the dominant pattern in the ecosystem of reusable modules (cc @worldly sapphire to keep me honest on this 🙂

fallow smelt
#

oh i totally understand if the orginal intent for cached volumes was only to support tooling cache specifics like the npm of the world

#

but i felt it could be used for another purpose .. i.e saving stuff between runs

worldly sapphire
#

I may be missing something here, but is there a reason to use cache volumes specifically for this when your artifacts from previous runs will more reliably exist in cache layers? (layers vs volumes at the top of this page https://docs.dagger.io/manuals/developer/cache-volumes/)

So rather than copying in from the cache volume, mount the directory or file from the previous container instead

rustic needle
fallow smelt
# worldly sapphire I may be missing something here, but is there a reason to use cache volumes spec...

thank you for asking ! that is exactly what i had before ... then problem is that i could not figure how to have a fixed "latest release". assume there is a cron job that runs every hour to produce those latest binaries. in a dagger function what i do is clone the repo build the artifacts then return a container as you suggested. i could not figure how to make the returned container to be the "latest" ..

#

so the dag that produces my latest release is return dag.Container(). withexec. git clone <dir>... build etc how do i make it so that it always returns the latest cont ?

#

when its a published artifact to a registry or a cached mounted dir its much easier to pin point

worldly sapphire
#

When you clone and build is that based on a specific commit/tag?

fallow smelt
# worldly sapphire When you clone and build is that based on a specific commit/tag?

it is indeed based on a specific commit sha. now the problem is that if i have a repo that depends on another one i cant (or dont want to) use the sha . i need something that says from this repo t3dp.app.latest string convert or map it to a commit sha. then bob is my uncle with the dagger magic. to think of it iwas going to store the whole binaries in the cache or in the registry. i think that all i need to store between runs is the mapping from a release string like t3dp.app.latest to a commit sha. i think i can use the mouned cache to store a json file there instead of publishing or storing all the binaries between runs

#

maybe there is a better way but that is what i am thinkin now