@@ -17,10 +17,13 @@ limitations under the License.
17
17
package image
18
18
19
19
import (
20
+ "context"
21
+ "io"
20
22
"os"
21
23
"path/filepath"
22
24
"time"
23
25
26
+ "github.com/docker/docker/client"
24
27
"github.com/google/go-containerregistry/pkg/name"
25
28
v1 "github.com/google/go-containerregistry/pkg/v1"
26
29
"github.com/google/go-containerregistry/pkg/v1/tarball"
@@ -84,7 +87,6 @@ func SaveToDir(images []string, cacheDir string, overwrite bool) error {
84
87
if err := g .Wait (); err != nil {
85
88
return errors .Wrap (err , "caching images" )
86
89
}
87
- klog .Infoln ("Successfully saved all images to host disk." )
88
90
return nil
89
91
}
90
92
@@ -158,6 +160,36 @@ func saveToTarFile(iname, rawDest string, overwrite bool) error {
158
160
return nil
159
161
}
160
162
163
+ func saveImageWithDockerClient (f * os.File , ref name.Reference ) error {
164
+ cli , err := client .NewClientWithOpts (client .FromEnv , client .WithAPIVersionNegotiation ())
165
+ if err != nil {
166
+ return errors .Wrap (err , "creating docker client" )
167
+ }
168
+ defer cli .Close ()
169
+
170
+ ctx := context .Background ()
171
+
172
+ _ , _ , err = cli .ImageInspectWithRaw (ctx , ref .String ())
173
+ if err != nil {
174
+ return errors .Wrapf (err , "inspect image %s via docker client" , ref .String ())
175
+ }
176
+
177
+ imageResponse , err := cli .ImageSave (ctx , []string {ref .String ()})
178
+ if err != nil {
179
+ return errors .Wrapf (err , "saving image %s via docker client" , ref .String ())
180
+ }
181
+ defer imageResponse .Close ()
182
+
183
+ // Copy image data stream to file
184
+ _ , err = io .Copy (f , imageResponse )
185
+ if err != nil {
186
+ return errors .Wrapf (err , "copying image %s data to file" , ref .String ())
187
+ }
188
+
189
+ klog .Infof ("Successfully saved image %s using Docker client" , ref .String ())
190
+ return nil
191
+ }
192
+
161
193
func writeImage (img v1.Image , dst string , ref name.Reference ) error {
162
194
klog .Infoln ("opening: " , dst )
163
195
f , err := os .CreateTemp (filepath .Dir (dst ), filepath .Base (dst )+ ".*.tmp" )
@@ -175,10 +207,27 @@ func writeImage(img v1.Image, dst string, ref name.Reference) error {
175
207
}
176
208
}()
177
209
178
- err = tarball .Write (ref , img , f )
179
- if err != nil {
180
- return errors .Wrap (err , "write" )
210
+ var imageSaved bool
211
+
212
+ // Using the Docker client to save the image for better performance
213
+ if useDaemon {
214
+ // Try to save the image using the Docker client
215
+ if err := saveImageWithDockerClient (f , ref ); err != nil {
216
+ if ! client .IsErrNotFound (err ) {
217
+ return errors .Wrap (err , "docker save" )
218
+ }
219
+ klog .Warningf ("Failed to save image with Docker client: %v, falling back to tarball.Write" , err )
220
+ } else {
221
+ imageSaved = true
222
+ }
181
223
}
224
+ // Fallback to saving the image using the tarball package
225
+ if ! imageSaved {
226
+ if err := tarball .Write (ref , img , f ); err != nil {
227
+ return errors .Wrap (err , "write" )
228
+ }
229
+ }
230
+
182
231
err = f .Close ()
183
232
if err != nil {
184
233
return errors .Wrap (err , "close" )
0 commit comments