package docker import ( "context" "fmt" "io" "os" "path/filepath" "strings" "github.com/docker/docker/api/types" "github.com/docker/docker/client" ) func SaveImageTar(ctx context.Context, image, path, name string, doPull, rm bool) error { cli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation()) if err != nil { return fmt.Errorf("docker client error: %v", err) } defer cli.Close() if doPull { if err := pullImage(ctx, cli, image); err != nil { return fmt.Errorf("pull image %s failed: %v", image, err) } } if err := saveToTar(ctx, cli, image, path, name); err != nil { return fmt.Errorf("save image %s failed: %v", image, err) } if rm { if err := rmImage(ctx, cli, image); err != nil { return fmt.Errorf("remove image %s failed: %v", image, err) } } return nil } func pullImage(ctx context.Context, cli *client.Client, image string) error { // try pull image r, err := cli.ImagePull(ctx, image, types.ImagePullOptions{}) if err != nil { return fmt.Errorf("pull image %s failed: %v", image, err) } defer r.Close() io.Copy(os.Stdout, r) return nil } func rmImage(ctx context.Context, cli *client.Client, image string) error { _, err := cli.ImageRemove(ctx, image, types.ImageRemoveOptions{}) if err != nil { return err } return nil } func saveToTar(ctx context.Context, cli *client.Client, image, path, name string) error { out, err := cli.ImageSave(ctx, []string{image}) if err != nil { return fmt.Errorf("save image %s failed: %v", image, err) } defer out.Close() filename := name if filename == "" { strs := strings.Split(image, "/") filename = fmt.Sprintf("%s.tar", strings.ReplaceAll(strs[len(strs)-1], ":", "_")) } filep := filepath.Join(path, filename) target, err := os.Create(filep) if err != nil { return fmt.Errorf("create file %s failed: %v", filep, err) } defer target.Close() if _, err := io.Copy(target, out); err != nil { return fmt.Errorf("copy file %s failed: %v", filep, err) } return nil }