From 92b9262f632a6fb91988dd6a4db8ddca1c669743 Mon Sep 17 00:00:00 2001 From: Samuel Karp Date: Fri, 24 Feb 2017 11:57:33 -0800 Subject: [PATCH] design: Update snapshots.md with current design Signed-off-by: Samuel Karp --- design/snapshot_model.png | Bin 0 -> 64760 bytes design/snapshots.md | 173 +++++++++++++++++++------------------- snapshot/snapshotter.go | 10 +-- 3 files changed, 92 insertions(+), 91 deletions(-) create mode 100644 design/snapshot_model.png diff --git a/design/snapshot_model.png b/design/snapshot_model.png new file mode 100644 index 0000000000000000000000000000000000000000..75836693d5769d1207d087632a8bc2b933bffb29 GIT binary patch literal 64760 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

mz@gezecyx0S&j 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 literal 0 HcmV?d00001 diff --git a/design/snapshots.md b/design/snapshots.md index 1a1605d..6853783 100644 --- a/design/snapshots.md +++ b/design/snapshots.md @@ -21,7 +21,7 @@ minimal API simplifies behavior without sacrificing power. This makes the surface area for driver implementations smaller, ensuring that behavior is more consistent between implementations. -These differ from the concept of the graphdriver in that the _Snapshot Manager_ +These differ from the concept of the graphdriver in that the _Snapshotter_ has no knowledge of images or containers. Users simply prepare and commit directories. We also avoid the integration between graph drivers and the tar format used to represent the changesets. @@ -35,7 +35,7 @@ In the past, the `graphdriver` component has provided quite a lot of functionality in Docker. This includes serialization, hashing, unpacking, packing, mounting. -The _Snapshot Manager_ will only provide mount-oriented snapshot +The _Snapshotter_ will only provide mount-oriented snapshot access with minimal metadata. Serialization, hashing, unpacking, packing and mounting are not included in this design, opting for common implementations between graphdrivers, rather than specialized ones. This is less of a problem @@ -44,102 +44,106 @@ interface. ## Architecture -The _Snapshot Manager_ provides an API for allocating, snapshotting and mounting +The _Snapshotter_ provides an API for allocating, snapshotting and mounting abstract, layer-based filesystems. The model works by building up sets of directories with parent-child relationships, known as _Snapshots_. -Every snapshot is represented by an opaque `diff` directory, which acts as a -handle to the snapshot. It may contain driver specific data, including changeset -data, parent information and arbitrary metadata. +A _Snapshot_ represents a filesystem state. Every snapshot has a parent, +where the empty parent is represented by the empty string. A diff can be taken +between a parent and its snapshot to create a classic layer. -The `diff` directory for a _snapshot_ is created with a transactional -operation. Each _snapshot_ may have one parent snapshot. When one starts a -transaction on an existing snapshot, the result may only be used as a parent -_after_ being committed. The empty string `diff` directory is a handle to the -empty snapshot, which is the ancestor of all snapshots. +Snapshots are best understood by their lifecycle. _Active_ snapshots are always +created with `Prepare` or `View` from a _Committed_ snapshot (including the +empty snapshot). _Committed_ snapshots are always created with +`Commit` from an _Active_ snapshot. Active snapshots never become committed +snapshots and vice versa. All snapshots may be removed. -The `target` directory represents the active snapshot location. The driver may -maintain internal metadata associated with the `target` but the contents is -generally manipulated by the client. +After mounting an _Active_ snapshot, changes can be made to the snapshot. The +act of committing creates a _Committed_ snapshot. The committed snapshot will +inherit the parent of the active snapshot. The committed snapshot can then be +used as a parent. Active snapshots can never be used as a parent. + +The following diagram demonstrates the relationships of snapshots: + +![snapshot model diagram, showing active snapshots on the left and +committed snapshots on the right](snapshot_model.png) + +In this diagram, you can see that the active snapshot _a_ is created by calling +`Prepare` with the committed snapshot _P0_. After modification, _a_ +becomes _a'_ and a committed snapshot _P1_ is created by calling +`Commit`. _a'_ can be further modified as _a''_ and a second committed snapshot +can be created as _P2_ by calling `Commit` again. Note here that +_P2_'s parent is _P0_ and not _P1_. ### Operations -The manifestation of _snapshots_ is facilitated by the _mount_ object and +The manifestation of _snapshots_ is facilitated by the `Mount` object and user-defined directories used for opaque data storage. When creating a new -snapshot, the caller provides a directory where they would like the _snapshot_ -to be mounted, called the _target_. This operation returns a list of mounts -that, if mounted, will have the fully prepared snapshot at the requested path. -We call this the _prepare_ operation. +active snapshot, the caller provides an identifier called the _key_. This +operation returns a list of mounts that, if mounted, will have the fully +prepared snapshot at the mounted path. We call this the _prepare_ operation. -Once a path is _prepared_ and mounted, the caller may write new data to the -snapshot. Depending on the application, a user may want to capture these changes or -not. +Once a snapshot is _prepared_ and mounted, the caller may write new data to the +snapshot. Depending on the application, a user may want to capture these changes +or not. + +For a read-only view of a snapshot, the _view_ operation can be used. Like +_prepare_, _view_ will return a list of mounts that, if mounted, will have the +fully prepared snapshot at the mounted path. If the user wants to keep the changes, the _commit_ operation is employed. The -_commit_ operation takes the `target` directory, which represents an open -transaction, and a `diff` directory. A successful result will provide the -difference between the parent and the snapshot in the `diff` directory, which -should be treated as opaque by the caller. This new `diff` directory can then -be used as the `parent` in calls to future _prepare_ operations. +_commit_ operation takes the _key_ identifier, which represents an active +snapshot, and a _name_ identifier. A successful result will create a _committed_ +snapshot that can be used as the parent of new _active_ snapshots when +referenced by the _name_. -If the user wants to discard the changes, the _rollback_ operation will release -any resources associated with the snapshot. While rollback may be a rare operation -in other transactional systems, this is a common operation for containers. -After removal, most containers will utilize the _rollback_ operation. +If the user wants to discard the changes in an active snapshot, the _remove_ +operation will release any resources associated with the snapshot. The mounts +provided by _prepare_ or _view_ should be unmounted before calling this method. -For both _rollback_ and _commit_ the mounts provided by _prepare_ should be -unmounted before calling these methods. +If the user wants to discard committed snapshots, the _remove_ operation can +also be used, but any children must be removed before proceeding. + +For detailed usage information, see the +[GoDoc](https://godoc.org/github.com/docker/containerd/snapshot#Snapshotter). ### Graph metadata As snapshots are imported into the container system, a "graph" of snapshots and their parents will form. Queries over this graph must be a supported operation. -Subsequently, each snapshot ends up representing - -### Path Management - -No path layout for snapshot locations is imposed on the caller. The paths used -by the snapshot drivers are largely under the control of the caller. This provides -the most flexibility in using the snapshot system but requires discipline when -deciding which paths to use and which ones to avoid. - -We may provide a helper component to manage `diff` path layout when working -with OCI and docker images. ## How snapshots work To flesh out the _Snapshots_ terminology, we are going to demonstrate the use of -the _Snapshot Manager_ from the perspective of importing layers. We'll use a Go API +the _Snapshotter_ from the perspective of importing layers. We'll use a Go API to represent the process. ### Importing a Layer -To import a layer, we simply have the _Snapshot Manager_ provide a list of +To import a layer, we simply have the _Snapshotter_ provide a list of mounts to be applied such that our destination will capture a changeset. We start out by getting a path to the layer tar file and creating a temp location to unpack it to: - layerPath, tmpLocation := getLayerPath(), mkTmpDir() // just a path to the layer tar file. + layerPath, tmpDir := getLayerPath(), mkTmpDir() // just a path to layer tar file. -Per the terminology above, `tmpLocation` is known as the `target`. `layerPath` -is simply a tar file, representing a changset. We start by using -`SnapshotManager` to prepare the temporary location as a snapshot point: +We start by using a _Snapshotter_ to _Prepare_ a new snapshot transaction, using +a _key_ and descending from the empty parent "": - sm := SnapshotManager() - mounts, err := sm.Prepare(tmpLocation, "") + mounts, err := snapshotter.Prepare(key, "") if err != nil { ... } -Note that we provide "" as the `parent`, since we are applying the diff to an -empty directory. We get back a list of mounts from `SnapshotManager.Prepare`. -Before proceeding, we perform all these mounts: +We get back a list of mounts from `Snapshotter.Prepare`, with the `key` +identifying the active snapshot. Mount this to the temporary location with the +following: - if err := MountAll(mounts); err != nil { ... } + if err := MountAll(mounts, tmpDir); err != nil { ... } Once the mounts are performed, our temporary location is ready to capture -a diff. In practice, this works similarly to a filesystem transaction. The -next step is to unpack the layer. We have a special function, `unpackLayer` +a diff. In practice, this works similar to a filesystem transaction. The +next step is to unpack the layer. We have a special function `unpackLayer` that applies the contents of the layer to target location and calculates the -DiffID of the unpacked layer (this is a requirement for the docker +`DiffID` of the unpacked layer (this is a requirement for docker implementation): layer, err := os.Open(layerPath) @@ -149,49 +153,46 @@ implementation): When the above completes, we should have a filesystem the represents the contents of the layer. Careful implementations should verify that digest -matches the expected DiffID. When completed, we unmount the mounts: +matches the expected `DiffID`. When completed, we unmount the mounts: unmount(mounts) // optional, for now -Now that we've verified and unpacked our layer, we create a location to commit -the actual diff. For this example, we are just going to use the layer `digest`, -but in practice, this will probably be the `ChainID`: +Now that we've verified and unpacked our layer, we commit the active +snapshot to a _name_. For this example, we are just going to use the layer +digest, but in practice, this will probably be the `ChainID`: - diffPath := filepath.Join("/layers", digest) // name location for the uncompressed layer digest - if err := sm.Commit(diffPath, tmpLocation); err != nil { ... } + if err := snapshotter.Commit(digest.String(), key); err != nil { ... } -The new layer has been imported as a _snapshot_ into the `SnapshotManager` -under the name `diffPath`. `diffPath`, which is a user opaque directory -location, can then be used as a parent in later snapshots. +Now, we have a layer in the _Snapshotter_ that can be accessed with the digest +provided during commit. Once you have committed the snapshot, the active +snapshot can be removed with the following: + + snapshotter.Remove(key) ### Importing the Next Layer Making a layer depend on the above is identical to the process described -above except that the parent is provided as diffPath when calling -`SnapshotManager.Prepare`: +above except that the parent is provided as `parent` when calling +`Snapshotter.Prepare`, assuming a clean `tmpLocation`: - mounts, err := sm.Prepare(tmpLocation, parentDiffPath) + mounts, err := snapshotter.Prepare(tmpLocation, parentDigest) -Because have a provided a `parent`, the resulting `tmpLocation`, after -mounting, will have the changes from above. Any new changes will be isolated to -the snapshot `target`. - -We run the same unpacking process and commit as before to get the new `diff`. +We then mount, apply and commit, as we did above. The new snapshot will be +based on the content of the previous one. ### Running a Container -To run a container, we simply provide `SnapshotManager.Prepare` the `diff` of -the image we want to start the container from. After mounting, the prepared -path can be used directly as the container's filesystem: +To run a container, we simply provide `Snapshotter.Prepare` the committed image +snapshot as the parent. After mounting, the prepared path can +be used directly as the container's filesystem: - mounts, err := sm.Prepare(containerRootFS, imageDiffPath) + mounts, err := snapshotter.Prepare(containerKey, imageRootFSChainID) The returned mounts can then be passed directly to the container runtime. If -one would like to create a new image from the filesystem, -`SnapshotManager.Commit` is called: +one would like to create a new image from the filesystem, `Snapshotter.Commit` +is called: - if err := sm.Commit(newImageDiff, containerRootFS); err != nil { ... } + if err := snapshotter.Commit(newImageSnapshot, containerKey); err != nil { ... } -Alternatively, in the majority of cases, `SnapshotManager.Rollback` will be -called to signal `SnapshotManager` to abandon the changes after a container -runtime process has completed. +Alternatively, for most container runs, `Snapshotter.Remove` will be called to +signal the Snapshotter to abandon the changes. diff --git a/snapshot/snapshotter.go b/snapshot/snapshotter.go index b8cadfc..e22c1c3 100644 --- a/snapshot/snapshotter.go +++ b/snapshot/snapshotter.go @@ -66,7 +66,7 @@ type Info struct { // // Importing a Layer // -// To import a layer, we simply have the Manager provide a list of +// To import a layer, we simply have the Snapshotter provide a list of // mounts to be applied such that our dst will capture a changeset. We start // out by getting a path to the layer tar file and creating a temp location to // unpack it to: @@ -121,7 +121,7 @@ type Info struct { // above except that the parent is provided as parent when calling // Manager.Prepare, assuming a clean tmpLocation: // -// mounts, err := sm.Prepare(tmpLocation, parentDigest) +// mounts, err := snapshotter.Prepare(tmpLocation, parentDigest) // // We then mount, apply and commit, as we did above. The new snapshot will be // based on the content of the previous one. @@ -132,15 +132,15 @@ type Info struct { // snapshot as the parent. After mounting, the prepared path can // be used directly as the container's filesystem: // -// mounts, err := sm.Prepare(containerKey, imageRootFSChainID) +// mounts, err := snapshotter.Prepare(containerKey, imageRootFSChainID) // // The returned mounts can then be passed directly to the container runtime. If // one would like to create a new image from the filesystem, Manager.Commit is // called: // -// if err := sm.Commit(newImageSnapshot, containerKey); err != nil { ... } +// if err := snapshotter.Commit(newImageSnapshot, containerKey); err != nil { ... } // -// Alternatively, for most container runs, Manager.Remove will be called to +// Alternatively, for most container runs, Snapshotter.Remove will be called to // signal the Snapshotter to abandon the changes. type Snapshotter interface { // Stat returns the info for an active or committed snapshot by name or