-
Notifications
You must be signed in to change notification settings - Fork 1
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
Add support for fake, and speed up reproducible builds #12
Add support for fake, and speed up reproducible builds #12
Conversation
549420b
to
68a0b67
Compare
68a0b67
to
696ae8d
Compare
pkg/executor/build.go
Outdated
@@ -444,6 +449,92 @@ func (s *stageBuilder) build() error { | |||
return nil | |||
} | |||
|
|||
// fakeBuild is like build(), but does not actually execute the commands or | |||
// extract files. | |||
func (s *stageBuilder) fakeBuild() error { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
AFAICS this aligns with the implementation of build()
. I'm concerned that this will drift; how do you plan to keep these two in lock-step?
As an aside: I think the term "fake" is a problematic one.
This PR adds support for fake builds, essentially a way to detect if a build is cached and what the final image hash should be.
Perhaps renaming it to something (admittedly less pithy) like "cacheProbeBuild" or "preemptiveBuild" might be more clear?
The term "fake" is quite overloaded and I don't think it expresses the intent well here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's a fair concern, one I have as well. I don't really have a plan for ensuring they're kept in sync other than adding tests to verify a build and "fakeBuild" produce the same (or not) hash in the end.
I also agree with you on "fake", and "cacheProbe" is actually a pretty good one, thanks for the suggestions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM so far, but I think this needs some more unit tests before merging.
// PAX and GNU Format support additional timestamps in the header | ||
if hdr.Format == tar.FormatPAX || hdr.Format == tar.FormatGNU { | ||
hdr.AccessTime = ct | ||
hdr.ChangeTime = ct | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If canonical
is set and we encounter other formats (such as formatSTAR
or formatMax
), should we throw an error?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure, I don't know how we'd encounter that, actually 🤔. This was borrowed from:
kaniko/vendor/github.com/google/go-containerregistry/pkg/v1/mutate/mutate.go
Lines 471 to 475 in a8afc79
//PAX and GNU Format support additional timestamps in the header | |
if header.Format == tar.FormatPAX || header.Format == tar.FormatGNU { | |
header.AccessTime = t | |
header.ChangeTime = t | |
} |
pkg/util/tar_util.go
Outdated
func NewCanonicalTar(f io.Writer) Tar { | ||
w := tar.NewWriter(f) | ||
return Tar{ | ||
w: w, | ||
hardlinks: map[uint64]string{}, | ||
canonical: true, | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This may require extra tests in tar_util_test.go
pkg/executor/build.go
Outdated
@@ -444,6 +449,92 @@ func (s *stageBuilder) build() error { | |||
return nil | |||
} | |||
|
|||
// fakeBuild is like build(), but does not actually execute the commands or | |||
// extract files. | |||
func (s *stageBuilder) fakeBuild() error { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What would you think about making a separate fakeBuilder
that embeds *stageBuilder
but overrides the build()
method?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are you also thinking we'd merge the logic in Build
and FakeBuild
into one, just swap out the stageBuilder
? (My main reason to keep them separate was to remove anything that could accidentally cause changes to the fs.)
I'll think about it, definitely doable.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
non-blocking, just a suggestion
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think what could solve both my concern (about lock-step with build()
) and Cian's is an adapter that can be passed in which would effect the changes. For your "fake" case, this adapter would not interact with the FS even though it satisfies the implementation.
I haven't looked too closely at the implementation so maybe this is im{practical,possible}, but thought I'd mention it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
non-blocking, just a suggestion
Ditto 👍
I've renamed the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code looks good and tested. 👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great work, the new names are very clear as well 👍
} | ||
mFile := filepath.Join(testDir, "proc/mountinfo") | ||
mountInfo := fmt.Sprintf( | ||
`36 35 98:0 /kaniko %s/kaniko rw,noatime master:1 - ext3 /dev/root rw,errors=continue |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Slick
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's just someone else's slick code I copy-pasted 🙃
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
post-merge approval 👍
I'm curious if this modification works with multi-stage Dockerfiles.
Good call. I added a separate test and it doesn't appear to work. Will raise a separate PR. |
I don't mind adding support for multi-stage Dockerfiles as a separate issue 👍 |
See this in use here: coder/envbuilder#213
This PR adds support for fake builds, essentially a way to detect if a build is cached and what the final image hash should be.
The final image hash requires reproducible builds.
Anothe option to using reproducible builds is to instead tag the final image with the final build step hash.
Part of coder/envbuilder#186
Example output from cache hit (
DoFakeBuild
):DoBuild
:Example output from cache miss: