Implement destination inference for sync of dockerfile artifacts [2/3]#2084
Implement destination inference for sync of dockerfile artifacts [2/3]#2084dgageot merged 12 commits intoGoogleContainerTools:masterfrom
Conversation
cd79f32 to
a24c70f
Compare
|
@balopat rebase is done |
Codecov Report
@@ Coverage Diff @@
## master #2084 +/- ##
==========================================
- Coverage 58.7% 58.69% -0.01%
==========================================
Files 188 191 +3
Lines 7849 8012 +163
==========================================
+ Hits 4608 4703 +95
- Misses 2873 2900 +27
- Partials 368 409 +41
Continue to review full report at Codecov.
|
dgageot
left a comment
There was a problem hiding this comment.
I'm ok with the design.
Because some functions are both moved and modified, I find it hard to review the code changes.
Is there a way to break this PR in two pieces. One that moves the code and one that actually adds the new feature?
pkg/skaffold/build/local/local.go
Outdated
| if err != nil { | ||
| // if the context was cancelled act as if all is well | ||
| // TODO(dgageot): this should be even higher in the call chain. | ||
| if ctx.Err() == context.Canceled { |
There was a problem hiding this comment.
Can we fix that first to simplify the code here?
There was a problem hiding this comment.
I moved the checks to the outermost call site. Please check carefully :)
| func (t *TestBench) Cleanup(ctx context.Context, out io.Writer) error { return nil } | ||
| func (t *TestBench) Prune(ctx context.Context, out io.Writer) error { return nil } | ||
|
|
||
| func (t *TestBench) SyncMap(ctx context.Context, artifact *latest.Artifact) (map[string][]string, error) { |
There was a problem hiding this comment.
goimports won't let me. I can only remove the blank lines
|
|
||
| // ADDED | ||
| SyncMap() (map[string][]string, error) | ||
| SyncMap(ctx context.Context, artifact *latest.Artifact) (map[string][]string, error) |
There was a problem hiding this comment.
should this return a syncMap? (Not sure it's better)
There was a problem hiding this comment.
@balopat had the same idea in pkg/skaffold/sync/sync.go. I'm also very unsure what is better. My main issue is that a type alias binds the using sites tighter to the place where type SyncMap is defined (probably builder.go?). Besides, I don't particularly like that there will be two SyncMap symbols in builder.go: 1 the function, 2 its return type.
Overall me feeling is slightly towards keeping it as is. On the other hand, the local type alias in sync.go makes somewhat sense, even though it cannot substitute all usages of map[string][]string due to visibility.
pkg/skaffold/docker/parse.go
Outdated
| return false | ||
| } | ||
|
|
||
| func changeDir(cur, to string) string { |
There was a problem hiding this comment.
It's hard to understand what this function is doing. It doesn't change the directory.
There was a problem hiding this comment.
I renamed it to resolveDir and added some godoc.
pkg/skaffold/docker/parse.go
Outdated
|
|
||
| func processCopy(value *parser.Node, envs map[string]string) ([]string, error) { | ||
| var copied []string | ||
| func retrieveWorkingDir(tagged string, insecureRegistries map[string]bool) (string, error) { |
There was a problem hiding this comment.
There's a copy of this code in sync.go
There was a problem hiding this comment.
😓 I shamelessly copied from there. I think the best place for this will be in the docker package.
a24c70f to
610ff7a
Compare
|
@dgageot Thanks for taking this up so quickly after bringing it to your attention!
This is an artifact of a humongous rebase/squash of the original PR. Sorry for that 🙇♂️ . As suggested, I squeezed in a pure move commit. This should make reviewing possible. |
pkg/skaffold/build/local/local.go
Outdated
| return nil, build.ErrSyncMapNotSupported{} | ||
| } | ||
|
|
||
| syncMap, err := docker.SyncMap(ctx, a.Workspace, a.DockerArtifact.DockerfilePath, a.DockerArtifact.BuildArgs, b.insecureRegistries) |
There was a problem hiding this comment.
can we not just return docker.SyncMap(....) here? I think it's more idiomatic to check if err != nil in the caller and then conditionally use the returned syncMap.
There was a problem hiding this comment.
oh yeah, sure! David made me pull other code out from there, but I missed that this can be further simplified..
pkg/skaffold/docker/image_util.go
Outdated
| // No local Docker is available | ||
| cf, err = RetrieveRemoteConfig(tagged, insecureRegistries) | ||
| } else { | ||
| cf, err = localDocker.ConfigFile(context.Background(), tagged) |
There was a problem hiding this comment.
I realized after making this comment you didn't write this code, but going to leave it here in case anyone has opinions on it:
do we not want to try and retrieve the image config from remote if we were able to get a local docker client, but couldn't find the image in the local daemon?
There was a problem hiding this comment.
good catch. Please have another look.
| ) | ||
|
|
||
| // NormalizeDockerfilePath returns the absolute path to the dockerfile. | ||
| func NormalizeDockerfilePath(context, dockerfile string) (string, error) { |
There was a problem hiding this comment.
this was copied from pkg/skaffold/docker/parse.go right? can we not move it to a common location (pkg/skaffold/docker/util/util.go?) and reuse it?
There was a problem hiding this comment.
@nkubala So the function was not copied but moved. It is therefore already reused.
I'm not so happy with moving it to util. Such packages/files quickly attract completely unrelated code. But if you feel strongly about it, I won't start to argue.
| return nil | ||
| } | ||
|
|
||
| func alwaysSucceedWhenCancelled(ctx context.Context, err error) error { |
There was a problem hiding this comment.
is this related to sync destination inference?
There was a problem hiding this comment.
Only indirectly. @dgageot recommended to resolve an earlier todo item in order to simplify the code (#2084 (comment)).
Would you prefer if this change was submitted as a separate PR?
| fmt.Fprintln(out, " - Dependencies:", len(deps), "files") | ||
| fmt.Fprintf(out, " - Time to list dependencies: %v (2nd time: %v)\n", timeDeps1, timeDeps2) | ||
|
|
||
| timeSyncMap1, err := timeToConstructSyncMap(ctx, r.Builder, artifact) |
There was a problem hiding this comment.
why do we do this 2 times?
Also, is there a way to add tests for the L63 to L65?
There was a problem hiding this comment.
I think it's run twice so that the OS can warm the inode cache. The second run should normally be more representative.
Since there was no test for diagnose at all, I didn't bother adding one. Since this is creating (random) timings, the best we can achieve here is a smoke test. Do you feel strongly about it?
There was a problem hiding this comment.
i think the runtime object inspection could refactored and unit tested to make sure we dont' break this in future. But i dont feel strongly regarding it.
if _, isNotSupported := err.(build.ErrSyncMapNotSupported); !isNotSupported {
return errors.Wrap(err, "construct artifact dependencies")
}
There was a problem hiding this comment.
953744c to
a4e8318
Compare
|
@dgageot At you convenience could you take another look? |
|
@corneliusweig Could you rebase this PR? I'll then take a look at it to make sure it's merged quickly |
2bf304b to
232d119
Compare
|
@dgageot Thanks! Rebase is done. |
|
@corneliusweig sorry, I LGTMed but it needs rebase again |
Signed-off-by: Cornelius Weig <22861411+corneliusweig@users.noreply.github.com>
Before, ONBUILD instructions were collected over the whole Dockerfile and prepended to all instructions. This has drawbacks when the sequence of commands matters, for example onbuild WORKDIR instructions. This prepares for extracting the workdir during parsing. Signed-off-by: Cornelius Weig <22861411+corneliusweig@users.noreply.github.com>
Signed-off-by: Cornelius Weig <22861411+corneliusweig@users.noreply.github.com>
Signed-off-by: Cornelius Weig <22861411+corneliusweig@users.noreply.github.com>
Ignore when the context was cancelled Signed-off-by: Cornelius Weig <22861411+corneliusweig@users.noreply.github.com>
Preserve order of copy commands Refactor to preserve order of copy commands Add godoc, improve naming Do not forcibly include the Dockerfile Do not forcibly exclude `.dockerignore` Disambiguate overwrites of the same destination location Only COPY/ADD into the latest image are syncable Reduce code duplication and reorganize code - rely on a single implementation to extract the COPY/ADD commands from the Dockerfile - introduce more helper functions to reduce code duplication Signed-off-by: Cornelius Weig <22861411+corneliusweig@users.noreply.github.com>
Signed-off-by: Cornelius Weig <22861411+corneliusweig@users.noreply.github.com>
Note: not all occurrences of map[string][]string can replaced, because syncMap's visibility is restricted Signed-off-by: Cornelius Weig <22861411+corneliusweig@users.noreply.github.com>
Signed-off-by: Cornelius Weig <22861411+corneliusweig@users.noreply.github.com>
Before, this was done on a much smaller scope in GetDependencies. Now this check is performed in the outermost call site, so that more places are covered. Signed-off-by: Cornelius Weig <22861411+corneliusweig@users.noreply.github.com>
Signed-off-by: Cornelius Weig <22861411+corneliusweig@users.noreply.github.com>
232d119 to
5d95a01
Compare
|
@dgageot no problem, the rebase is done already. Thanks for seeing this through! |
The sync feature is getting refurbished, see design proposal #1844 .
This PR implements step 2 of the implementation plan for the sync improvements. Notable changes include:
SyncMapto the builder interface. This new method should provide sync destinations for all relevant source files.SyncMapfor docker artifacts.Note that
SyncMapis intentionally not wired up yet. The only way to test it is withskaffold diagnose. The speed ofGetDependenciesvsSyncMap(which do similar things) is almost the same. In a sample project with 4.7k filesGetDependenciesandSyncMaptook ~30ms and ~32ms, respectively.I tried to (reasonably) avoid code duplication. Yet, the directory walking code (
pkg/skaffold/docker/dependencies.goandpkg/skaffold/docker/syncmap.go) is almost twice the same. Nevertheless, I think this is the right approach, because CustomArtifact also relies ondocker.WalkWorkspaceand this one is a little faster thandocker.walkWorkspaceWithDestinations.Possible issues
Overlapping copies to the same destination are now resolved correctly. This was not the case in the original PR WIP Sync: infer destination from Dockerfile #1812. For example:
In that case
/foowill have the content frombar/foo, as it is expected.Transitive copies across stages of multi-stage dockerfiles are not resolved. For example:
The current implementation will resolve
foo -> fooand notfoo -> bar. As discussed in the designproposal Design proposal for sync improvements #1844, this edge case will be ignored for now.
based-on #1847
Supersedes #1812
CC design shepherd @tejal29