Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Avoid applying SOURCE_DATE_EPOCH to base images #4663

Merged
merged 2 commits into from
Feb 24, 2024

Conversation

AkihiroSuda
Copy link
Member

@AkihiroSuda AkihiroSuda commented Feb 19, 2024

The exporter fetches the base image config via the ExporterImageBaseConfigKey metadata to detect the immutable layer diffIDs and the history objects.

Fix #4614

NOTE: For a multi-stage Dockerfile like below, the base image refers to busybox, not to foo:

FROM busybox AS foo
FROM foo AS bar

@@ -31,6 +32,7 @@ func xmain() error {
var opt buildOpt
flag.StringVar(&opt.target, "target", "", "target stage")
flag.StringVar(&opt.partialImageConfigFile, "partial-image-config-file", "", "Output partial image config as a JSON file")
flag.StringVar(&opt.sourceImageConfigFile, "source-image-config-file", "", "Output source image config as a JSON file")
Copy link
Member

Choose a reason for hiding this comment

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

I think it should be called base image, not source image here and everywhere else.

Copy link
Member Author

Choose a reason for hiding this comment

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

Isn't "base image" confusing in this case?

FROM busybox AS foo

# the "base image" of bar is busybox, not foo
FROM foo AS bar

Copy link
Member

Choose a reason for hiding this comment

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

But isn't the point of this feature to keep the timestamps from "busybox" in this case? So yes it is the base image.

In here I think it makes sense to look at the base image based on the layers from the result artifact, not as a structure of Dockerfile stages. This is also how it works in provenance when we export layers or how Docker Scout detects if the base image should be updated (as opposed to materials that is an array and not a single image).

Copy link
Member Author

Choose a reason for hiding this comment

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

Renamed to "base" images

In here I think it makes sense to look at the base image based on the layers from the result artifact, not as a structure of Dockerfile stages.

I'm not sure about this. Can this be discussed in a separate PR?

exporter/containerimage/writer.go Outdated Show resolved Hide resolved
exporter/containerimage/writer.go Outdated Show resolved Hide resolved
exporter/containerimage/writer.go Outdated Show resolved Hide resolved
@AkihiroSuda AkihiroSuda force-pushed the fix-4614 branch 2 times, most recently from 586a136 to acaafbf Compare February 23, 2024 20:13
The base image config will be used later for avoiding applying
`SOURCE_DATE_EPOCH` to the base image layers (issue 4614).

The exporter stores this as the `ExporterImageBaseConfigKey` metadata.

NOTE: For a multi-stage Dockerfile like below, the base image refers to
`busybox`, not to `foo`:
```dockerfile
FROM busybox AS foo
FROM foo AS bar
```

Signed-off-by: Akihiro Suda <akihiro.suda.cz@hco.ntt.co.jp>
@AkihiroSuda AkihiroSuda changed the title Avoid applying SOURCE_DATE_EPOCH to source images Avoid applying SOURCE_DATE_EPOCH to base images Feb 23, 2024
var immDiffID digest.Digest
if baseImg != nil && i < len(baseImg.RootFS.DiffIDs) {
immDiffID = baseImg.RootFS.DiffIDs[i]
if immDiffID == diffID {
Copy link
Member

Choose a reason for hiding this comment

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

iiuc this looks for the index match for individual layers. But it should check that full baseImg roofs is a subset in the beginning of the exported image.

Copy link
Member Author

Choose a reason for hiding this comment

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

Added var divergedFromBase bool to check this

Copy link
Member

Choose a reason for hiding this comment

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

This should be a check before processing. Atm some layers can already be processed before the validation fails.

The exporter fetches the base image config via the `ExporterImageBaseConfigKey`
metadata to detect the immutable layer diffIDs and the history objects.

Fix issue 4614

Signed-off-by: Akihiro Suda <akihiro.suda.cz@hco.ntt.co.jp>
func rewriteImageLayerWithEpoch(ctx context.Context, cs content.Store, desc ocispecs.Descriptor, comp compression.Config, epoch *time.Time) (*ocispecs.Descriptor, error) {
converterFn, err := converter.NewWithRewriteTimestamp(ctx, cs, desc, comp, epoch)
func rewriteImageLayerWithEpoch(ctx context.Context, cs content.Store, desc ocispecs.Descriptor, comp compression.Config, epoch *time.Time, immDiffID digest.Digest) (*ocispecs.Descriptor, error) {
var immDiffIDs map[digest.Digest]struct{}
Copy link
Member

Choose a reason for hiding this comment

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

I don't understand this construction in here. Why is a map with a single item passed? Instead of for example just setting epoch nil?

Copy link
Member Author

Choose a reason for hiding this comment

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

Why is a map with a single item passed?

The converter pkg is designed to cover wider usecases that are not needed by exporter/containerimage.

Instead of for example just setting epoch nil?

Because the converter may not make the final decision until computing the diff ID (not always available in the label)

Copy link
Member

@tonistiigi tonistiigi left a comment

Choose a reason for hiding this comment

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

Going to merge for RC testing but needs follow-up fixes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
2 participants