@@ -5,8 +5,11 @@ import (
55 "fmt"
66 "os"
77 "runtime"
8+ "time"
89
910 containerd "github.com/containerd/containerd/v2/client"
11+ "github.com/containerd/containerd/v2/core/images"
12+ "github.com/containerd/containerd/v2/core/leases"
1013 "github.com/containerd/containerd/v2/pkg/namespaces"
1114 "github.com/containerd/platforms"
1215)
@@ -23,6 +26,7 @@ const (
2326func main () {
2427 if len (os .Args ) < 2 {
2528 fmt .Fprintf (os .Stderr , "Usage: %s <image-ref> [image-ref...]\n " , os .Args [0 ])
29+ fmt .Fprintf (os .Stderr , " %s --gc\n " , os .Args [0 ])
2630 fmt .Fprintf (os .Stderr , "Example: %s mcr.microsoft.com/oss/kubernetes/pause:3.9\n " , os .Args [0 ])
2731 os .Exit (1 )
2832 }
@@ -45,6 +49,15 @@ func main() {
4549
4650 ctx := namespaces .WithNamespace (context .Background (), ns )
4751
52+ if len (os .Args ) == 2 && os .Args [1 ] == "--gc" {
53+ if err := triggerGarbageCollection (ctx , client ); err != nil {
54+ fmt .Fprintf (os .Stderr , "Failed to trigger containerd GC: %v\n " , err )
55+ os .Exit (1 )
56+ }
57+ fmt .Println ("Triggered containerd GC" )
58+ return
59+ }
60+
4861 failed := 0
4962 for _ , ref := range os .Args [1 :] {
5063 if err := fetchImage (ctx , client , ref ); err != nil {
@@ -68,7 +81,7 @@ func main() {
6881// already-fetched content from the store and handles snapshotter resolution
6982// internally (namespace label → platform default).
7083func fetchImage (ctx context.Context , client * containerd.Client , ref string ) error {
71- fetchOnly := os .Getenv ("IMAGE_FETCH_ONLY" ) == "true"
84+ // fetchOnly := os.Getenv("IMAGE_FETCH_ONLY") == "true"
7285
7386 fmt .Printf ("Fetching %s ...\n " , ref )
7487
@@ -79,42 +92,55 @@ func fetchImage(ctx context.Context, client *containerd.Client, ref string) erro
7992 }
8093 platformMatcher := platforms .OnlyStrict (p )
8194
82- imageMeta , err := client .Fetch (ctx , ref ,
95+ // imageMeta, err := client.Fetch(ctx, ref,
96+ // containerd.WithPlatformMatcher(platformMatcher),
97+ // )
98+ // if err != nil {
99+ // return fmt.Errorf("fetch failed: %w", err)
100+ // }
101+
102+ // if fetchOnly {
103+ // fmt.Printf("OK %s -> %s (fetched)\n", imageMeta.Name, imageMeta.Target.Digest)
104+ // return nil
105+ // }
106+
107+ // image := containerd.NewImage(client, imageMeta)
108+
109+ // size, err := image.Size(ctx)
110+ // if err != nil {
111+ // fmt.Fprintf(os.Stderr, "WARN %s: could not determine image size, skipping unpack: %v\n", ref, err)
112+ // fmt.Printf("OK %s -> %s (fetched)\n", imageMeta.Name, imageMeta.Target.Digest)
113+ // return nil
114+ // }
115+
116+ // if size < pullSizeThreshold {
117+ // We use pull here instead of use unpack because some runtimes (e.g. containerd-shim-runsc-v1),
118+ // require pull to trigger unpacking into the correct snapshotter based on the image's platform.
119+ pullOpts := []containerd.RemoteOpt {
83120 containerd .WithPlatformMatcher (platformMatcher ),
84- )
85- if err != nil {
86- return fmt .Errorf ("fetch failed: %w" , err )
121+ containerd .WithPullUnpack ,
122+ containerd .WithChildLabelMap (images .ChildGCLabelsFilterLayers ),
87123 }
88124
89- if fetchOnly {
90- fmt . Printf ( "OK %s -> %s (fetched) \n " , imageMeta . Name , imageMeta . Target . Digest )
91- return nil
125+ imageMeta , err := client . Pull ( ctx , ref , pullOpts ... )
126+ if err != nil {
127+ return fmt . Errorf ( "pull failed: %w" , err )
92128 }
129+ fmt .Printf ("OK %s (pulled)\n " , imageMeta .Name )
130+ // } else {
131+ // fmt.Printf("OK %s -> %s (fetched, %s)\n", imageMeta.Name, imageMeta.Target.Digest, formatSize(size))
132+ // }
93133
94- image := containerd .NewImage (client , imageMeta )
134+ return nil
135+ }
95136
96- size , err := image .Size (ctx )
137+ func triggerGarbageCollection (ctx context.Context , client * containerd.Client ) error {
138+ ls := client .LeasesService ()
139+ l , err := ls .Create (ctx , leases .WithRandomID (), leases .WithExpiration (time .Hour ))
97140 if err != nil {
98- fmt .Fprintf (os .Stderr , "WARN %s: could not determine image size, skipping unpack: %v\n " , ref , err )
99- fmt .Printf ("OK %s -> %s (fetched)\n " , imageMeta .Name , imageMeta .Target .Digest )
100- return nil
101- }
102-
103- if size < pullSizeThreshold {
104- // We use pull here instead of use unpack because some runtimes (e.g. containerd-shim-runsc-v1),
105- // require pull to trigger unpacking into the correct snapshotter based on the image's platform.
106- if _ , err := client .Pull (ctx , ref ,
107- containerd .WithPlatformMatcher (platformMatcher ),
108- containerd .WithPullUnpack ,
109- ); err != nil {
110- return fmt .Errorf ("pull failed: %w" , err )
111- }
112- fmt .Printf ("OK %s -> %s (pulled, %s)\n " , imageMeta .Name , imageMeta .Target .Digest , formatSize (size ))
113- } else {
114- fmt .Printf ("OK %s -> %s (fetched, %s)\n " , imageMeta .Name , imageMeta .Target .Digest , formatSize (size ))
141+ return err
115142 }
116-
117- return nil
143+ return ls .Delete (ctx , l , leases .SynchronousDelete )
118144}
119145
120146func formatSize (bytes int64 ) string {
0 commit comments