#How to push container to local Docker
1 messages · Page 1 of 1 (latest)
This is not a core primitive in the Dagger API (to avoid excessive dependency on Docker), but you can implement the same thing as code on top of Dagger (or reuse that logic from someone else using a library)
One way I see is with these steps:
- Create your container with the Dagger API (type
container) (example: - Export the container image to your filesystem with
container { export }(example: https://play.dagger.cloud/playground/nRBDKlh0OHw) - Run the
dockerCLI in a container, with your client machine's docker engine unix socket mounted, and the exported container directory also mounted - In that container, run
docker load
It's not ideal because the image data has to be copied to the host filesystem, then back out. But in terms of performance, it's not materially different from what docker build --load does. Assuming you use /tmp or equivalent your host, it's all memory anyway.
Awesome thanks so much Solomon, this is super useful step for when testing locally. I am currently building a little go wrapper I will add it here
in the future we should add support for streaming the image contents to a socket as a tar stream, then clients can skip the host filesystem
it’s not trivial because of how buildkit works
hmm, is there some way to apply the steps above when using the SDK (Node in my case) instead of GraphQL API?
ideally I'd just change publish to load in the tutorial e.g. .publish('ttl.sh/hello-dagger-' + Math.floor(Math.random() * 10000000)) but sounds like it's non-trivial 😄
FWIW, when you google this problem docs for the "old version of dagger" come up, if there's a good solution perhaps that's a good place to link from 🙂 https://docs.dagger.io/1216/docker-cli-load/
oh, I think I see now, you would use export to the local filesystem somewhere in the SDK and then manually docker load that? 🤔
OK, that works, was nice to find this at the top of #help 🙂
I wonder if I am missing something, I am trying to export like so...
func exportLocalImage(builder *Builder, container *dagger.Container, platform dagger.Platform) {
done := builder.LogSubSection(fmt.Sprintf("exporting %s", platform))
imagePath := path.Join(os.TempDir(), "localexport")
//defer os.RemoveAll(imagePath)
// export the image to the local path
_, err := builder.DaggerClient.
Container(dagger.ContainerOpts{Platform: platform}).
Export(
builder.ctx,
imagePath,
dagger.ContainerExportOpts{PlatformVariants: []*dagger.Container{container}},
)
if err != nil {
builder.LogError("error exporting image", err)
}
// run docker import to import to the local system
cmd := exec.Command(
"docker",
"import",
imagePath,
fmt.Sprintf("%s:local", *dockerRegistry),
)
var out bytes.Buffer
cmd.Stdout = &out
cmd.Stderr = &out
err = cmd.Run()
if err != nil {
builder.LogError("unable to import image", errors.New(out.String()))
}
done(fmt.Sprintf("export container complete for architecture %s", platform))
}
But when trying to run I get the following error
docker: Error response from daemon: failed to create shim task: OCI runtime create failed: runc create failed: unable to start container process: exec: "/bin/bash": stat /bin/bash: no such file or directory: unknown
When I do a publish this works fine
I think there must be an import problem, when I decompress the exported tarbal I can see all the right files
My bad, I am doing an import not a load
@delicate escarp , did changing it to load work for you?
Yes, thanks, I am just updating my example as there is a little more I need to do as load does not allow you add tags, it just uses the tags from export, of which there are none.
I just need to grab the sha from load and then tag
This is what I finally came up with...
func exportLocalImage(builder *Builder, container *dagger.Container, platform dagger.Platform) error {
done := builder.LogSubSection(fmt.Sprintf("exporting %s", platform))
outputDirectory := path.Join(os.TempDir(), "build_output")
os.MkdirAll(outputDirectory, os.ModePerm)
imagePath := path.Join(outputDirectory, "localexport.tar")
//defer os.RemoveAll(outputDirectory)
// export the image to the local path
_, err := builder.DaggerClient.
Container(dagger.ContainerOpts{Platform: platform}).
Export(
builder.ctx,
imagePath,
dagger.ContainerExportOpts{PlatformVariants: []*dagger.Container{container}},
)
if err != nil {
return err
}
// run docker import to import to the local system
cmd := exec.Command(
"docker",
"load",
"-i",
imagePath,
)
out := &bytes.Buffer{}
cmd.Stdout = out
cmd.Stderr = out
err = cmd.Run()
if err != nil {
return err
}
// get the sha from the output
r, err := regexp.Compile(`sha256:(.*)`)
if err != nil {
return err
}
res := r.FindStringSubmatch(out.String())
if len(res) != 2 {
return fmt.Errorf("expected sha from docker load output, got: %s", out.String())
}
sha := res[1]
cmd = exec.Command(
"docker",
"tag",
sha,
fmt.Sprintf("%s:local", *dockerRegistry),
)
out = &bytes.Buffer{}
cmd.Stdout = out
cmd.Stderr = out
err = cmd.Run()
if err != nil {
return err
}
done(fmt.Sprintf("export container complete for architecture %s", platform))
return nil
}