Skip to content

Conversation

wswsmao
Copy link
Contributor

@wswsmao wswsmao commented Aug 25, 2025

The optimize command requires a running container; however, this isn’t always feasible—for example, when the container needs GPU hardware while the service that performs image format conversion (e.g. a webhook) runs in an environment without GPUs. In such situations, users can collect the required dependency files themselves and provide them as input; the --prefetch-list option allows the format conversion to be carried out in the constrained environment.

@wswsmao wswsmao closed this Aug 25, 2025
@wswsmao wswsmao reopened this Aug 25, 2025
@wswsmao wswsmao closed this Aug 26, 2025
@wswsmao wswsmao reopened this Aug 26, 2025
return paths, nil
}

func analyzePrefetchList(ctx context.Context, client *containerd.Client, srcRef string, prefetchPaths []string) (digest.Digest, map[digest.Digest][]estargz.Option, func(converter.ConvertFunc) converter.ConvertFunc, error) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A large portion of this function looks the same as a part of analyze function (

// Parse record file
srcImg, err := is.Get(ctx, srcRef)
if err != nil {
return "", nil, nil, err
}
manifestDesc, err := containerdutil.ManifestDesc(ctx, cs, srcImg.Target, platforms.DefaultStrict())
if err != nil {
return "", nil, nil, err
}
p, err := content.ReadBlob(ctx, cs, manifestDesc)
if err != nil {
return "", nil, nil, err
}
var manifest ocispec.Manifest
if err := json.Unmarshal(p, &manifest); err != nil {
return "", nil, nil, err
}
// TODO: this should be indexed by layer "index" (not "digest")
layerLogs := make(map[digest.Digest][]string, len(manifest.Layers))
ra, err := cs.ReaderAt(ctx, ocispec.Descriptor{Digest: recordOut})
if err != nil {
return "", nil, nil, err
}
defer ra.Close()
dec := json.NewDecoder(io.NewSectionReader(ra, 0, ra.Size()))
added := make(map[digest.Digest]map[string]struct{}, len(manifest.Layers))
for dec.More() {
var e recorder.Entry
if err := dec.Decode(&e); err != nil {
return "", nil, nil, err
}
if *e.LayerIndex < len(manifest.Layers) &&
e.ManifestDigest == manifestDesc.Digest.String() {
dgst := manifest.Layers[*e.LayerIndex].Digest
if added[dgst] == nil {
added[dgst] = map[string]struct{}{}
}
if _, ok := added[dgst][e.Path]; !ok {
added[dgst][e.Path] = struct{}{}
layerLogs[dgst] = append(layerLogs[dgst], e.Path)
}
}
}
// Create a converter wrapper for skipping layer conversion. This skip occurs
// if "reuse" option is specified, the source layer is already valid estargz
// and no access occur to that layer.
var excludes []digest.Digest
layerOpts := make(map[digest.Digest][]estargz.Option, len(manifest.Layers))
for _, desc := range manifest.Layers {
if layerLog, ok := layerLogs[desc.Digest]; ok && len(layerLog) > 0 {
layerOpts[desc.Digest] = []estargz.Option{estargz.WithPrioritizedFiles(layerLog)}
} else if clicontext.Bool("reuse") && isReusableESGZLayer(ctx, desc, cs) {
excludes = append(excludes, desc.Digest) // reuse layer without conversion
}
}
return recordOut, layerOpts, excludeWrapper(excludes), nil
) except the manual creation of the record. So can you split this part to a common helper function so that it can be used for the both flags?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

scanner := bufio.NewScanner(file)
for scanner.Scan() {
line := strings.TrimSpace(scanner.Text())
if line != "" && !strings.HasPrefix(line, "#") {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The usage of this flag and the file syntax should be documented somewhere such as docs/ctr-remote.md

Copy link
Member

@ktock ktock left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks

@ktock ktock merged commit a2df5f8 into containerd:main Aug 27, 2025
44 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants