150 lines
		
	
	
		
			5.2 KiB
		
	
	
	
		
			Markdown
		
	
	
	
			
		
		
	
	
			150 lines
		
	
	
		
			5.2 KiB
		
	
	
	
		
			Markdown
		
	
	
	
| # Filesystem Resolution 01
 | |
| 
 | |
| * Author(s): cgwippern@google.com
 | |
| * Reviewers: Tejal Desai
 | |
| * Date: 2020-02-12
 | |
| * Status: Reviewed
 | |
| 
 | |
| ## Background
 | |
| 
 | |
| Kaniko builds Docker image layers as overlay filesystem layers; specifically it
 | |
| creates a tar file which contains the entire content of a given layer in the
 | |
| overlay filesystem. Each overlay layer corresponds to one image layer.
 | |
| 
 | |
| Overlay filesystems should only contain the objects changed in each layer;
 | |
| meaning that if only one file changes between some layer A and some B, layer B
 | |
| would only contain a single file (the one that changed).
 | |
| 
 | |
| To accomplish this, Kaniko walks the entire filesystem to discover every object.
 | |
| Some of these objects may actually be a symlink to another object in the
 | |
| filesystem; in these cases we must consider both the link and the target object.
 | |
| 
 | |
| Kaniko also maintains a set of ignored (aka ignored) filepaths. Any object
 | |
| which matches one of these filepaths should be ignored by kaniko.
 | |
| 
 | |
| This results in a 3 dimensional search space
 | |
| 
 | |
| * changed relative to previous layer
 | |
| * symlink
 | |
| * whitelisted
 | |
| 
 | |
| Kaniko must also track which objects are referred to by multiple stages; this
 | |
| functionality is out of scope for this proposal.
 | |
| 
 | |
| This search space is currently managed in an inconsistent and somewhat ad-hoc
 | |
| way; code that manages the various search dimensions is spread out and
 | |
| duplicated. There are also a number of edge cases which continue
 | |
| to cause bugs.
 | |
| 
 | |
| The search space dimensions cannot be reduced or substituted.
 | |
| 
 | |
| Currently there are a number of bugs around symlinks incorrectly resolved,
 | |
| whitelists not respected, and unchanged files added to layers.
 | |
| 
 | |
| ## Design
 | |
| 
 | |
| During snapshotting, filepaths should be resolved using a consitent API which
 | |
| takes into account both symlinks and whitelist.
 | |
| 
 | |
| * Callers of this API should not be concerned with the type of object at a given filepath (e.g. symlink or not).
 | |
| * Callers of this API should not be concerned with whether a given path is whitelisted.
 | |
| * This API should return a set of filepaths which can be checked for changes
 | |
|   without further link resolution or whitelist checking.
 | |
| 
 | |
| The API should take a limited set of arguments
 | |
| * A list of absolute filepaths to scan
 | |
| * The whitelist
 | |
| 
 | |
| The API should return only two arguments
 | |
| * A set of filepaths
 | |
| * error or nil
 | |
| 
 | |
| The signature of the API should look similar to
 | |
| ```
 | |
|   ResolveFilePaths(inputPaths []string, whitelist []WhitelistEntry) (resolvedPaths []string, err error)
 | |
| ```
 | |
| 
 | |
| The API will iterate over the set of filepaths and for each item
 | |
| * check whether it is whitelisted; if it is, skip it
 | |
| * check whether it is a symlink
 | |
|   * if it is a symlink
 | |
|     * resolve the link ancestor (nearest ancestor which is a symlink) and the
 | |
|       target
 | |
|     * add the link ancestor to the output
 | |
|     * check whether the target is whitelisted and if
 | |
|       not add the target to the output
 | |
| 
 | |
| All ancestors of each filepath will also be added to the list, but the previous
 | |
| checks will not be applied to the ancestors. This maintains the current behavior
 | |
| which we believe is needed to maintain correct permissions on the ancestor
 | |
| directories.
 | |
| 
 | |
| ### Open Issues/Questions
 | |
| 
 | |
| \<Ignore symlinks targeting whitelisted paths?\>
 | |
| 
 | |
| Given some link `/foo/link/bar` whose target is a whitelisted path such as
 | |
| `/var/run`, should `/foo/link/bar` be added to the layer?
 | |
| 
 | |
| Resolution: Resolved
 | |
| 
 | |
| Yes, it should be added.
 | |
| 
 | |
| \<Adding ancestor directories\>
 | |
| 
 | |
| According to [this comment](https://github.com/GoogleContainerTools/kaniko/blob/1e9f525509d4e6a066a6e07ab9afbef69b3a3b2c/pkg/snapshot/snapshot.go#L193)
 | |
| the ancestor directories (parent, grandparent, etc) must also be added to the
 | |
| layer to preserve the permissions on those directories. This brings into
 | |
| question whether any filtering needs to happen on these ancestors. IIUC the
 | |
| current whitelist logic it is possible for `/some/dir` to be whitelisted but not
 | |
| `/some/dir/containing-a-file.txt`. If filtering needs to be applied to these
 | |
| ancestors does it make most sense to handle this within the proposed filtering
 | |
| API?
 | |
| 
 | |
| Resolution: Resolved
 | |
| 
 | |
| Yes, this should be handled in the API
 | |
| 
 | |
| \<Should the API handle diff'ing files?\>
 | |
| 
 | |
| The proposal currently states that the list of files returned from the API
 | |
| should be immediately added to the layer, but this would imply that diff'ing
 | |
| existing files, finding newly created files, and handling deleted files would
 | |
| have already been done. It may be advantageous to handle these outside of the
 | |
| API in order to reduce scope and complexity. If these are handled outside of the
 | |
| API how can we decouple and encapsulate these two functions?
 | |
| 
 | |
| Resolution: Resolved
 | |
| 
 | |
| The API will not handle file diffing or whiteouts.
 | |
| 
 | |
| ## Implementation plan
 | |
| 
 | |
| * Write the new API
 | |
| * Write tests for the new API
 | |
| * Integrate the new API into existing code
 | |
| 
 | |
| ## Integration test plan
 | |
| 
 | |
| Add integration tests to the existing suite which cover the known bugs
 | |
| 
 | |
| ## Notes
 | |
| 
 | |
| Given some path `/usr/lib/foo` which is a link to `/etc/foo/`
 | |
| 
 | |
| And `/etc/foo` contains `/etc/foo/bar.txt`
 | |
| 
 | |
| Adding a link `/usr/lib/foo/bar.txt` => `/etc/foo/bar.txt` will break the image
 | |
| 
 | |
| In a linux shell this raises an error
 | |
| ```
 | |
| $ ls /usr/lib/bar
 | |
| => /usr/lib/bar/foo.txt
 | |
| $ ln -s /usr/lib/bar barlink
 | |
| $ ln -s /usr/lib/bar/foo.txt barlink/foo.txt
 | |
| => ERROR
 | |
| ```
 | |
| 
 | |
| Given some path `/usr/foo/bar` which is a link to `/dev/null`, and `/dev` is
 | |
| whitelisted `/dev/null` should not be added to the image.
 |