#Export from Service Container

1 messages · Page 1 of 1 (latest)

sly sorrel
#

I can't get files exported from containers which are bound using WithServiceBinding, is this not possible?
When I attempt to export a dir, or get content of a file, from the service it always runs its entrypoint script, causing it to start its services.

To reproduce I created a script which also does not properly run but shows my intent:

func main() {

    ctx := context.Background()

    client, err := dagger.Connect(ctx, dagger.WithLogOutput(os.Stderr))
    if err != nil {
        log.Fatalln(err)
    }
    defer func(client *dagger.Client) {
        err := client.Close()
        if err != nil {
            log.Println(err)
        }
    }(client)

    cntSvc := client.Container().From("alpine").
        WithExec([]string{"apk", "update"}).
        WithExec([]string{"apk", "add", "netcat-openbsd"}).
        WithEnvVariable("time", time.Now().String()).
        WithExec([]string{"sh", "-c", "echo \"${time}\" > /tmp/test"}).
        WithEntrypoint([]string{"nc"}).
        WithDefaultArgs(dagger.ContainerWithDefaultArgsOpts{Args: []string{"-l", "-p", "8080"}}).
        WithExposedPort(8080).
        WithExec(nil)

    _, _ = client.Container().From("alpine").
        WithExec([]string{"sh", "-c", "echo 1"}).
        WithServiceBinding("serviceCnt", cntSvc).
        //  ERROR exec sh -c echo 2                 
        //┃ │ host alias: lookup s1jn3amhp8uem on 10.87.0.1:53: no such host     
        WithExec([]string{"sh", "-c", "echo 2"}).
        Sync(ctx)

    content2, err := cntSvc.File("/tmp/test").Contents(ctx)
    if err != nil {
        log.Fatalln(err)
    }

    log.Println("this does not work: ", content2)
}
#

I attempted using cache within another, new, container, but it seems the cache does not get released until the other containers are fully "terminated" which seems only to happen once the client closes.

light tundra
#

have you tried overwriting the entrypoint that the service image uses?

something like

withEntrypoint(null)
sly sorrel
#

jup i tried, but didn't change the behavior.
also tried setting defaultArgs nil etc.

#

it always lands in the entrypoint, i assumed that this happens because i have a .exec(nil) earlier, where the entrypoint was still set, to start the service

vital spear
#

Correct, this is currently not possible because it behaves like exporting the result of a command that never exits. The workaround is to use a cache volume: have the service write/copy to the cache volume, and then mount the cache volume to another container.

sly sorrel
#

👍 will try it this way

sly sorrel
#
package main

import (
    "context"
    "dagger.io/dagger"
    "log"
    "os"
    "time"
)

func main() {

    ctx := context.Background()

    client, err := dagger.Connect(ctx, dagger.WithLogOutput(os.Stderr))
    if err != nil {
        log.Fatalln(err)
    }
    defer func(client *dagger.Client) {
        err := client.Close()
        if err != nil {
            log.Println(err)
        }
    }(client)

    cacheDir := client.CacheVolume("cache")
    _, _ = client.Container().From("alpine").
        WithEnvVariable("time", time.Now().String()).
        WithMountedCache("/some_container_path", cacheDir).
        WithExec([]string{"sh", "-c", "echo \"${time}\" > /some_container_path/test"}).
        Stdout(ctx)

    cnt, err := client.Container().From("alpine").
        WithMountedCache("/some_container_path", cacheDir).
        WithExec([]string{"sh", "-c", "cat /some_container_path/test"}).
        Sync(ctx)
    if err != nil {
        log.Fatalln(err)
    }

    _, err = cnt.
        WithMountedCache("/some_container_path", cacheDir).
        Directory("/some_container_path").
        Export(ctx, "host_path")
    if err != nil {
        log.Fatalln(err)
    }
}

#

i monkeyd around with it a while and it fails with /some_container_path: cannot retrieve path from cache all the time.

i thought i had to run it in a container which was 'synced' just having a container with the mounted cache and exporting it does also not work

vital spear
#

True, this is another limitation of cache volumes (they don't behave like directories). A workaround for the workaround is to copy back out into a regular directory and export from there.

atomic ibex
vital spear
atomic ibex
#

since you'll be calling Stop instead?

vital spear
#

it's even more bespoke once we're running via the gateway, since it's not even a vertex in buildkit anymore 😛

atomic ibex
#

so some sort of hack it's still needed to avoid re-running that long-running process, right?

vital spear
#

yeah exactly

#

with services v2 there's a distinct Service type so we could potentially implement directory and file APIs that let you access files from a running service, in whatever way that has to be implemented (likely lots of internal APIs)

sly sorrel
#

i just tried to client.Close() and reconnect to a new client, but it seems I would have to stop the engine altogether to hack this.

all in all, final solution will be using stdout/stderr what I need, should be enough.

atomic ibex
#

I'd recommend to go the cache volume route as Vito was suggesting @sly sorrel

sly sorrel
atomic ibex
#

I must be missing something, any of my attempts using the caching volume resulted in "couldn't retrieve from cache".

this is expected, you can't export from cache that's why you need to copy the files or folders you need from the cache volume to a container before exporting them. cc @sly sorrel

quaint river
#

Maybe I missed, was the possibility of accessing the mount mentioned? container.mount

atomic ibex
sly sorrel
#

sorry for my absence, I was traveling and will return to work tomorrow and give this another look.

sly sorrel
# atomic ibex vito mentioned it here: https://discord.com/channels/707636530424053791/11488644...

True, this is another limitation of cache volumes (they don't behave like directories). A workaround for the workaround is to copy back out into a regular directory and export from there.

how would I accomplish to copy something back from the service container?

Some basic directions would do, I am just not yet well versed in the dagger api and the different scopes buildkit and dagger inhabit.

atomic ibex
#

you can use WithMountedCache("cache", mycache).WithExec([]string{"cp", "/cache/foo", "/foo").File("/foo").Export(ctx, "foo")

quaint river
#

Per @vital spear , isn't this possible as well?

WithMountedCache("cache", mycache).Directory("cache").Export(ctx, "cache")

--> unfortunately not... 😭 😭

sly sorrel
sly sorrel
#

this indeed works, thank you!

i will refactor this to use caches for all my artifacts and defer their export to streamline this a bit more.


    cntPhpExporter := ci.client.Container().
        From("anx-cr.io/hub.docker.com/alpine:3.14").
        WithMountedCache("/cache", cacheEngineLogs).
        WithExec([]string{"cp", "-vr", "/cache", "/export"}, cntExecWithoutEntrypoint)
    ci.exportDir(cntPhpExporter, path.Join("/export"), path.Join("output", "engine"))

atomic ibex
crude elm
#

Also, why aren't "used modules" available via dagger call or dagger functions ?

atomic ibex
crude elm