github.com/containerd/Containerd@v1.4.13/docs/content-flow.md (about)

     1  # Content Flow
     2  
     3  A major goal of containerd is to create a system wherein content can be used for executing containers.
     4  In order to execute on that flow, containerd requires content and to manage it.
     5  
     6  This document describes how content flows into containerd, how it is managed, and where it exists
     7  at each stage in the process. We use an example of going from a known image
     8  [docker.io/library/redis:5.0.9](https://hub.docker.com/layers/redis/library/redis/5.0.9/images/sha256-4ff8940144391ecd5e1632d0c427d95f4a8d2bb4a72b7e3898733352350d9ab3?context=explore) to explore the
     9  flow of content.
    10  
    11  ## Content Areas
    12  
    13  Content exists in several areas in the containerd lifecycle:
    14  
    15  * OCI registry, for example [hub.docker.com](https://hub.docker.com) or [quay.io](https://quay.io)
    16  * containerd content store, under containerd's local storage space, for example, on a standard Linux installation at `/var/lib/containerd/io.containerd.content.v1.content`
    17  * snapshots, under containerd's local storage space, for example, on a standard Linux installation at `/var/lib/containerd/io.containerd.snapshotter.v1.<type>`. For an overlayfs snapshotter, that would be at `/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs`
    18  
    19  In order to create a container, the following must occur:
    20  
    21  1. The image and all its content must be loaded into the content store. This normally happens via download from the OCI registry, but you can load content in directly as well.
    22  1. Committed snapshots must be created from each layer of content for the image.
    23  1. An active snapshot must be created on top of the final layer of content for the image.
    24  
    25  A container now can be created, with its root filesystem as the active snapshot.
    26  
    27  The rest of this document looks at the content in each area in detail, and how they relate to one another.
    28  
    29  ### Image Format
    30  
    31  Images in a registry normally are stored in the following format. An "image" is comprised of a JSON document
    32  known as a descriptor. A descriptor always contains an element, `mediaType`, which tells us which type it is. It is one of two options:
    33  
    34  * a "manifest", which lists the hashes of the config file for running the image as a container, and the binary data layers that create the filesystem for the image
    35  * an "index", which lists the hashes of manifests, one per platform, where a platform is a combination of architecture (e.g. amd64 or arm64) and operating system (e.g. linux)
    36  
    37  The purpose of an index is to allow us to pick which manifest matches our target platform.
    38  
    39  To convert an image reference, such as `redis:5.0.9`, from a registry to actual on-disk storage, we:
    40  
    41  1. Retrieve the descriptor (JSON document) for the image
    42  1. Determine from the `mediaType` if the descriptor is a manifest or an index:
    43     * If the descriptor is an index, find in it the platform (architecture+os) that represents the platform on which we want to run the container, use that hash to retrieve the manifest
    44     * If the descriptor already is a manifest, continue
    45  1. For each element in the manifest - the config and one or more layers - use the hash listed to retrieve the components and save them
    46  
    47  We use our example image, `redis:5.0.9`, to clarify the process.
    48  
    49  When we first resolve `redis:5.0.9`, we get the following JSON document:
    50  
    51  ```json
    52  {
    53    "manifests": [
    54      {
    55        "digest": "sha256:a5aae2581826d13e906ff5c961d4c2817a9b96c334fd97b072d976990384156a",
    56        "mediaType": "application/vnd.docker.distribution.manifest.v2+json",
    57        "platform": {
    58          "architecture": "amd64",
    59          "os": "linux"
    60        },
    61        "size": 1572
    62      },
    63      {
    64        "digest": "sha256:4ff8940144391ecd5e1632d0c427d95f4a8d2bb4a72b7e3898733352350d9ab3",
    65        "mediaType": "application/vnd.docker.distribution.manifest.v2+json",
    66        "platform": {
    67          "architecture": "arm",
    68          "os": "linux",
    69          "variant": "v5"
    70        },
    71        "size": 1573
    72      },
    73      {
    74        "digest": "sha256:ce541c3e2570b5a05d40e7fc01f87fc1222a701c81f95e7e6f2ef6df1c6e25e7",
    75        "mediaType": "application/vnd.docker.distribution.manifest.v2+json",
    76        "platform": {
    77          "architecture": "arm",
    78          "os": "linux",
    79          "variant": "v7"
    80        },
    81        "size": 1573
    82      },
    83      {
    84        "digest": "sha256:535ee258100feeeb525d4793c16c7e58147c105231d7d05ffc9c84b56750f233",
    85        "mediaType": "application/vnd.docker.distribution.manifest.v2+json",
    86        "platform": {
    87          "architecture": "arm64",
    88          "os": "linux",
    89          "variant": "v8"
    90        },
    91        "size": 1573
    92      },
    93      {
    94        "digest": "sha256:0f3b047f2789547c58634ce88d71c7856999b2afc8b859b7adb5657043984b26",
    95        "mediaType": "application/vnd.docker.distribution.manifest.v2+json",
    96        "platform": {
    97          "architecture": "386",
    98          "os": "linux"
    99        },
   100        "size": 1572
   101      },
   102      {
   103        "digest": "sha256:bfc45f499a9393aef091057f3d067ff7129ae9fb30d9f31054bafe96ca30b8d6",
   104        "mediaType": "application/vnd.docker.distribution.manifest.v2+json",
   105        "platform": {
   106          "architecture": "mips64le",
   107          "os": "linux"
   108        },
   109        "size": 1572
   110      },
   111      {
   112        "digest": "sha256:3198e1f1707d977939154a57918d360a172c575bddeac875cb26ca6f4d30dc1c",
   113        "mediaType": "application/vnd.docker.distribution.manifest.v2+json",
   114        "platform": {
   115          "architecture": "ppc64le",
   116          "os": "linux"
   117        },
   118        "size": 1573
   119      },
   120      {
   121        "digest": "sha256:24a15cc9366e1557db079a987e63b98a5abf4dee4356a096442f53ddc8b9c7e9",
   122        "mediaType": "application/vnd.docker.distribution.manifest.v2+json",
   123        "platform": {
   124          "architecture": "s390x",
   125          "os": "linux"
   126        },
   127        "size": 1573
   128      }
   129    ],
   130    "mediaType": "application/vnd.docker.distribution.manifest.list.v2+json",
   131    "schemaVersion": 2
   132  }
   133  ```
   134  
   135  The descriptor above, towards the end, shows that the `mediaType` is a "manifest.list", or in OCI parlance, an index.
   136  It has an array field called `manifests`, each element of which lists one platform and the hash of the manifest for that platform.
   137  The "platform" is a combination of "architecture" and "os". Since we will be running on the common
   138  linux on amd64, we look for an entry in `manifests` that has a `platform` entry as follows:
   139  
   140  ```json
   141  "platform": {
   142    "architecture": "amd64",
   143    "os": "linux"
   144  }
   145  ```
   146  
   147  This is the first one in the list, and it has the hash of `sha256:a5aae2581826d13e906ff5c961d4c2817a9b96c334fd97b072d976990384156a`.
   148  
   149  We then retrieve the item with that hash, specifically `docker.io/library/redis@sha256:a5aae2581826d13e906ff5c961d4c2817a9b96c334fd97b072d976990384156a`
   150  This gives us the manifest for the image on linux/amd64:
   151  
   152  ```json
   153  {
   154     "schemaVersion": 2,
   155     "mediaType": "application/vnd.docker.distribution.manifest.v2+json",
   156     "config": {
   157        "mediaType": "application/vnd.docker.container.image.v1+json",
   158        "size": 6836,
   159        "digest": "sha256:df57482065789980ee9445b1dd79ab1b7b3d1dc26b6867d94470af969a64c8e6"
   160     },
   161     "layers": [
   162        {
   163           "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
   164           "size": 27098147,
   165           "digest": "sha256:123275d6e508d282237a22fefa5aef822b719a06496444ea89efa65da523fc4b"
   166        },
   167        {
   168           "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
   169           "size": 1730,
   170           "digest": "sha256:f2edbd6a658e04d559c1bec36d838006bbdcb39d8fb9033ed43d2014ac497774"
   171        },
   172        {
   173           "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
   174           "size": 1417708,
   175           "digest": "sha256:66960bede47c1a193710cf8bfa7bf5f50bc46374260923df1db1c423b52153ac"
   176        },
   177        {
   178           "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
   179           "size": 7345094,
   180           "digest": "sha256:79dc0b596c9027416a627a6237bd080ac9d87f92b60f1ce145c566632839bce7"
   181        },
   182        {
   183           "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
   184           "size": 99,
   185           "digest": "sha256:de36df38e0b6c0e7f29913c68884a0323207c07cd7c1eba71d5618f525ac2ba6"
   186        },
   187        {
   188           "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
   189           "size": 410,
   190           "digest": "sha256:602cd484ff92015489f7b9cf9cbd77ac392997374b1cc42937773f5bac1ff43b"
   191        }
   192     ]
   193  }
   194  ```
   195  
   196  The `mediaType` tell us that this is a "manifest", and it fits the correct format:
   197  
   198  * one `config`, whose hash is `sha256:df57482065789980ee9445b1dd79ab1b7b3d1dc26b6867d94470af969a64c8e6`
   199  * one or more `layers`; in this example, there are 6 layers
   200  
   201  Each of these elements - the index, the manifests, the config file and each of the layers - is stored
   202  separately in the registry, and is downloaded independently.
   203  
   204  ### Content Store
   205  
   206  When content is loaded into containerd's content store, it stores them very similarly to how the registry does.
   207  Each component is stored in a file whose name is the hash of it.
   208  
   209  Continuing our redis example, if we do `client.Pull()` or `ctr pull`, we will get the following in our
   210  content store:
   211  
   212  * `sha256:1d0b903e3770c2c3c79961b73a53e963f4fd4b2674c2c4911472e8a054cb5728` - the index
   213  * `sha256:a5aae2581826d13e906ff5c961d4c2817a9b96c334fd97b072d976990384156a` - the manifest for `linux/amd64`
   214  * `sha256:df57482065789980ee9445b1dd79ab1b7b3d1dc26b6867d94470af969a64c8e6` - the config
   215  * `sha256:123275d6e508d282237a22fefa5aef822b719a06496444ea89efa65da523fc4b` - layer 0
   216  * `sha256:f2edbd6a658e04d559c1bec36d838006bbdcb39d8fb9033ed43d2014ac497774` - layer 1
   217  * `sha256:66960bede47c1a193710cf8bfa7bf5f50bc46374260923df1db1c423b52153ac` - layer 2
   218  * `sha256:79dc0b596c9027416a627a6237bd080ac9d87f92b60f1ce145c566632839bce7` - layer 3
   219  * `sha256:de36df38e0b6c0e7f29913c68884a0323207c07cd7c1eba71d5618f525ac2ba6` - layer 4
   220  * `sha256:602cd484ff92015489f7b9cf9cbd77ac392997374b1cc42937773f5bac1ff43b` - layer 5
   221  
   222  If we look in our content store, we see exactly these (I filtered and sorted to make it easier to read):
   223  
   224  ```console
   225  $ tree /var/lib/containerd/io.containerd.content.v1.content/blobs
   226  /var/lib/containerd/io.containerd.content.v1.content/blobs
   227  └── sha256
   228      ├── 1d0b903e3770c2c3c79961b73a53e963f4fd4b2674c2c4911472e8a054cb5728
   229      ├── a5aae2581826d13e906ff5c961d4c2817a9b96c334fd97b072d976990384156a
   230      ├── df57482065789980ee9445b1dd79ab1b7b3d1dc26b6867d94470af969a64c8e6
   231      ├── 123275d6e508d282237a22fefa5aef822b719a06496444ea89efa65da523fc4b
   232      ├── f2edbd6a658e04d559c1bec36d838006bbdcb39d8fb9033ed43d2014ac497774
   233      ├── 66960bede47c1a193710cf8bfa7bf5f50bc46374260923df1db1c423b52153ac
   234      ├── 79dc0b596c9027416a627a6237bd080ac9d87f92b60f1ce145c566632839bce7
   235      ├── de36df38e0b6c0e7f29913c68884a0323207c07cd7c1eba71d5618f525ac2ba6
   236      └── 602cd484ff92015489f7b9cf9cbd77ac392997374b1cc42937773f5bac1ff43b
   237  ```
   238  
   239  We can see the same thing if we use the containerd interface. Again, we sorted it for consistent easier viewing.
   240  
   241  ```console
   242  ctr content ls
   243  DIGEST									SIZE		AGE		LABELS
   244  sha256:1d0b903e3770c2c3c79961b73a53e963f4fd4b2674c2c4911472e8a054cb5728	1.862 kB	6 minutes	containerd.io/gc.ref.content.0=sha256:a5aae2581826d13e906ff5c961d4c2817a9b96c334fd97b072d976990384156a,containerd.io/gc.ref.content.1=sha256:4ff8940144391ecd5e1632d0c427d95f4a8d2bb4a72b7e3898733352350d9ab3,containerd.io/gc.ref.content.2=sha256:ce541c3e2570b5a05d40e7fc01f87fc1222a701c81f95e7e6f2ef6df1c6e25e7,containerd.io/gc.ref.content.3=sha256:535ee258100feeeb525d4793c16c7e58147c105231d7d05ffc9c84b56750f233,containerd.io/gc.ref.content.4=sha256:0f3b047f2789547c58634ce88d71c7856999b2afc8b859b7adb5657043984b26,containerd.io/gc.ref.content.5=sha256:bfc45f499a9393aef091057f3d067ff7129ae9fb30d9f31054bafe96ca30b8d6,containerd.io/gc.ref.content.6=sha256:3198e1f1707d977939154a57918d360a172c575bddeac875cb26ca6f4d30dc1c,containerd.io/gc.ref.content.7=sha256:24a15cc9366e1557db079a987e63b98a5abf4dee4356a096442f53ddc8b9c7e9
   245  sha256:a5aae2581826d13e906ff5c961d4c2817a9b96c334fd97b072d976990384156a	1.572 kB	6 minutes	containerd.io/gc.ref.content.2=sha256:f2edbd6a658e04d559c1bec36d838006bbdcb39d8fb9033ed43d2014ac497774,containerd.io/gc.ref.content.3=sha256:66960bede47c1a193710cf8bfa7bf5f50bc46374260923df1db1c423b52153ac,containerd.io/gc.ref.content.4=sha256:79dc0b596c9027416a627a6237bd080ac9d87f92b60f1ce145c566632839bce7,containerd.io/gc.ref.content.5=sha256:de36df38e0b6c0e7f29913c68884a0323207c07cd7c1eba71d5618f525ac2ba6,containerd.io/gc.ref.content.6=sha256:602cd484ff92015489f7b9cf9cbd77ac392997374b1cc42937773f5bac1ff43b,containerd.io/gc.ref.content.0=sha256:df57482065789980ee9445b1dd79ab1b7b3d1dc26b6867d94470af969a64c8e6,containerd.io/gc.ref.content.1=sha256:123275d6e508d282237a22fefa5aef822b719a06496444ea89efa65da523fc4b
   246  sha256:df57482065789980ee9445b1dd79ab1b7b3d1dc26b6867d94470af969a64c8e6	6.836 kB	6 minutes	containerd.io/gc.ref.snapshot.overlayfs=sha256:87806a591ce894ff5c699c28fe02093d6cdadd6b1ad86819acea05ccb212ff3d
   247  sha256:123275d6e508d282237a22fefa5aef822b719a06496444ea89efa65da523fc4b	27.1 MB		6 minutes	containerd.io/uncompressed=sha256:b60e5c3bcef2f42ec42648b3acf7baf6de1fa780ca16d9180f3b4a3f266fe7bc
   248  sha256:f2edbd6a658e04d559c1bec36d838006bbdcb39d8fb9033ed43d2014ac497774	1.73 kB		6 minutes	containerd.io/uncompressed=sha256:b5a8df342567aa93d568b263b25c1eaf52655f0952e1911742ffb4f7a521e044
   249  sha256:66960bede47c1a193710cf8bfa7bf5f50bc46374260923df1db1c423b52153ac	1.418 MB	6 minutes	containerd.io/uncompressed=sha256:c03c7e9701eb61f1e2232f6d19faa699cd9d346207aaf4f50d84b1e37bbad3e2
   250  sha256:79dc0b596c9027416a627a6237bd080ac9d87f92b60f1ce145c566632839bce7	7.345 MB	6 minutes	containerd.io/uncompressed=sha256:367024e4e00618a9ada3203b5922d3186a0aa6136a1c4cbf5ed380171e1afe48
   251  sha256:de36df38e0b6c0e7f29913c68884a0323207c07cd7c1eba71d5618f525ac2ba6	99 B		6 minutes	containerd.io/uncompressed=sha256:60ef3ee42de712ef7748cc8e92192e926180b1be6fec9580933f1347fb6b2747
   252  sha256:602cd484ff92015489f7b9cf9cbd77ac392997374b1cc42937773f5bac1ff43b	410 B		6 minutes	containerd.io/uncompressed=sha256:bab68e5155b7010010964bf3aadc30e4a9c625701314ff6fa3c143c72f0aeb9c
   253  ```
   254  
   255  #### Labels
   256  
   257  Note that each chunk of content has several labels on it. This sub-section describes the labels.
   258  This is not intended to be a comprehensive overview of labels.
   259  
   260  ##### Layer Labels
   261  
   262  We start with the layers themselves. These have only one label: `containerd.io/uncompressed`. These files are
   263  gzipped tar files; the value of the label gives the hash of them when uncompressed. You can get the same value
   264  by doing:
   265  
   266  ```console
   267  $ cat <file> | gunzip - | sha256sum -
   268  ```
   269  
   270  For example:
   271  
   272  ```console
   273  $ cat /var/lib/containerd/io.containerd.content.v1.content/blobs/sha256/602cd484ff92015489f7b9cf9cbd77ac392997374b1cc42937773f5bac1ff43b | gunzip - | sha256sum -
   274  bab68e5155b7010010964bf3aadc30e4a9c625701314ff6fa3c143c72f0aeb9c
   275  ```
   276  
   277  That aligns precisely with the last layer:
   278  
   279  ```
   280  sha256:602cd484ff92015489f7b9cf9cbd77ac392997374b1cc42937773f5bac1ff43b	410 B		6 minutes	containerd.io/uncompressed=sha256:bab68e5155b7010010964bf3aadc30e4a9c625701314ff6fa3c143c72f0aeb9c
   281  ```
   282  
   283  ##### Config Labels
   284  
   285  We have a single config layer, `sha256:df57482065789980ee9445b1dd79ab1b7b3d1dc26b6867d94470af969a64c8e6`. It has a label prefixed with `containerd.io/gc.ref.` indicating
   286  that it is a label that impacts garbage collection.
   287  
   288  In this case, the label is `containerd.io/gc.ref.snapshot.overlayfs` and has a value of `sha256:87806a591ce894ff5c699c28fe02093d6cdadd6b1ad86819acea05ccb212ff3d`.
   289  
   290  This is used to connect this config to a snapshot. We will look at that shortly when we discuss snapshots.
   291  
   292  ##### Manifest Labels
   293  
   294  The labels on the manifest also begin with `containerd.io/gc.ref`, indicating that they are used to control
   295  garbage collection. A manifest has several "children". These normally are the config and the layers. We want
   296  to ensure that as long as the image remains around, i.e. the manifest, the children do not get garbage collected.
   297  Thus, we have labels referencing each child, `containerd.io/gc.ref.content.<index>`.
   298  
   299  In our example, the manifest is `sha256:a5aae2581826d13e906ff5c961d4c2817a9b96c334fd97b072d976990384156a`, and the labels are as follows.
   300  
   301  ```
   302  containerd.io/gc.ref.content.0=sha256:df57482065789980ee9445b1dd79ab1b7b3d1dc26b6867d94470af969a64c8e6
   303  containerd.io/gc.ref.content.1=sha256:123275d6e508d282237a22fefa5aef822b719a06496444ea89efa65da523fc4b
   304  containerd.io/gc.ref.content.2=sha256:f2edbd6a658e04d559c1bec36d838006bbdcb39d8fb9033ed43d2014ac497774
   305  containerd.io/gc.ref.content.3=sha256:66960bede47c1a193710cf8bfa7bf5f50bc46374260923df1db1c423b52153ac
   306  containerd.io/gc.ref.content.4=sha256:79dc0b596c9027416a627a6237bd080ac9d87f92b60f1ce145c566632839bce7
   307  containerd.io/gc.ref.content.5=sha256:de36df38e0b6c0e7f29913c68884a0323207c07cd7c1eba71d5618f525ac2ba6
   308  containerd.io/gc.ref.content.6=sha256:602cd484ff92015489f7b9cf9cbd77ac392997374b1cc42937773f5bac1ff43b
   309  ```
   310  
   311  These are precisely those children of the manifest - the config and layers - that are stored in our content store.
   312  
   313  ##### Index Labels
   314  
   315  The labels on the index also begin with `containerd.io/gc.ref`, indicating that they are used to control
   316  garbage collection. An index has several "children", i.e. the manifests, one for each platform, as discussed above.
   317  We want to ensure that as long as the index remains around, the children do not get garbage collected.
   318  Thus, we have labels referencing each child, `containerd.io/gc.ref.content.<index>`.
   319  
   320  In our example, the index is `sha256:1d0b903e3770c2c3c79961b73a53e963f4fd4b2674c2c4911472e8a054cb5728`, and the labels are as follows:
   321  
   322  ```
   323  containerd.io/gc.ref.content.0=sha256:a5aae2581826d13e906ff5c961d4c2817a9b96c334fd97b072d976990384156a
   324  containerd.io/gc.ref.content.1=sha256:4ff8940144391ecd5e1632d0c427d95f4a8d2bb4a72b7e3898733352350d9ab3
   325  containerd.io/gc.ref.content.2=sha256:ce541c3e2570b5a05d40e7fc01f87fc1222a701c81f95e7e6f2ef6df1c6e25e7
   326  containerd.io/gc.ref.content.3=sha256:535ee258100feeeb525d4793c16c7e58147c105231d7d05ffc9c84b56750f233
   327  containerd.io/gc.ref.content.4=sha256:0f3b047f2789547c58634ce88d71c7856999b2afc8b859b7adb5657043984b26
   328  containerd.io/gc.ref.content.5=sha256:bfc45f499a9393aef091057f3d067ff7129ae9fb30d9f31054bafe96ca30b8d6
   329  containerd.io/gc.ref.content.6=sha256:3198e1f1707d977939154a57918d360a172c575bddeac875cb26ca6f4d30dc1c
   330  containerd.io/gc.ref.content.7=sha256:24a15cc9366e1557db079a987e63b98a5abf4dee4356a096442f53ddc8b9c7e9
   331  ```
   332  
   333  Notice that there are 8 children to the index, but all of them are for platforms other than ours, `linux/amd64`,
   334  and thus only one of them, `sha256:a5aae2581826d13e906ff5c961d4c2817a9b96c334fd97b072d976990384156a` actually is
   335  in our content store. That doesn't hurt; it just means that the others will not be garbage collected either. Since
   336  they aren't there, they won't be removed.
   337  
   338  ### Snapshots
   339  
   340  The content in the content store is immutable, but also in formats that often are unusable. For example,
   341  most container layers are in a tar-gzip format. One cannot simply mount a tar-gzip file. Even if one could,
   342  we want to leave our immutable content not only unchanged, but unchangeable, even by accident, i.e. immutable.
   343  
   344  In order to use it, we create snapshots of the content.
   345  
   346  The process is as follows:
   347  
   348  1. The snapshotter creates a snapshot from the parent. In the case of the first layer, that is blank. This is now an "active" snapshot.
   349  1. The diff applier, which has knowledge of the internal format of the layer blob, applies the layer blob to the active snapshot.
   350  1. The snapshotter commits the snapshot after the diff has been applied. This is now a "committed" snapshot.
   351  1. The committed snapshot is used as the parent for the next layer.
   352  
   353  Returning to our example, each layer will have a corresponding immutable snapshot layer. Recalling that
   354  our example has 6 layers, we expect to see 6 committed snapshots. The output has been sorted to make viewing
   355  easier; it matches the layers from the content store and manifest itself.
   356  
   357  ```
   358  # ctr snapshot ls
   359  KEY                                                                     PARENT                                                                  KIND
   360  sha256:b60e5c3bcef2f42ec42648b3acf7baf6de1fa780ca16d9180f3b4a3f266fe7bc                                                                         Committed
   361  sha256:c2cba74b5b43db78068241279a3225ca4f9639c17a5f0ce019489ee71b4382a5 sha256:b60e5c3bcef2f42ec42648b3acf7baf6de1fa780ca16d9180f3b4a3f266fe7bc Committed
   362  sha256:315768cd0d297e3cb707360f8dde646419940b42e055845a160880cf98b5a242 sha256:c2cba74b5b43db78068241279a3225ca4f9639c17a5f0ce019489ee71b4382a5 Committed
   363  sha256:13aa829f25ce405c1c5f40e0449b9270ce162ac7e4c2a81359df6fe09f939afd sha256:315768cd0d297e3cb707360f8dde646419940b42e055845a160880cf98b5a242 Committed
   364  sha256:814ff1c8753c9cd3942089a2401f1806a1133f27b6875bcad7b7e68846e205e4 sha256:13aa829f25ce405c1c5f40e0449b9270ce162ac7e4c2a81359df6fe09f939afd Committed
   365  sha256:87806a591ce894ff5c699c28fe02093d6cdadd6b1ad86819acea05ccb212ff3d sha256:814ff1c8753c9cd3942089a2401f1806a1133f27b6875bcad7b7e68846e205e4 Committed
   366  ```
   367  
   368  #### Parents
   369  
   370  Each snapshot has a parent, except for the root. It is a tree, or a stacked cake, starting with the first layer.
   371  This matches how the layers are built, as layers.
   372  
   373  #### Name
   374  
   375  The key, or name, for the snapshot does not match the hash from the content store. This is because the hash from the
   376  content store is the hash of the _original_ content, in this case tar-gzipped. The snapshot expands it out into the
   377  filesystem to make it useful. It also does not match the uncompressed content, i.e. the tar file without gzip, and as
   378  given on the label `containerd.io/uncompressed`.
   379  
   380  Rather the name is the result of applying the layer to the previous one and hashing it. By that logic, the very root
   381  of the tree, the first layer, should have the same hash and name as the uncompressed value of the first layer blob.
   382  Indeed, it does. The root layer is `sha256:123275d6e508d282237a22fefa5aef822b719a06496444ea89efa65da523fc4b`
   383  which, when uncompressed, has the value `sha256:b60e5c3bcef2f42ec42648b3acf7baf6de1fa780ca16d9180f3b4a3f266fe7bc`,
   384  which is the first layer in the snapshot, and also the label on that layer in the content store:
   385  
   386  ```
   387  sha256:123275d6e508d282237a22fefa5aef822b719a06496444ea89efa65da523fc4b	27.1 MB		6 minutes	containerd.io/uncompressed=sha256:b60e5c3bcef2f42ec42648b3acf7baf6de1fa780ca16d9180f3b4a3f266fe7bc
   388  ```
   389  
   390  #### Final Layer
   391  
   392  The final, or top, layer, is the point at which you would want to create an active snapshot to start a container.
   393  Thus, we would need to track it. This is exactly the label that is placed on the config. In our example, the
   394  config is at `sha256:df57482065789980ee9445b1dd79ab1b7b3d1dc26b6867d94470af969a64c8e6` and had the label
   395  `containerd.io/gc.ref.snapshot.overlayfs=sha256:87806a591ce894ff5c699c28fe02093d6cdadd6b1ad86819acea05ccb212ff3d`.
   396  
   397  Looking at our snapshots, the value of the final layer of the stack is, indeed, that:
   398  
   399  ```
   400  sha256:87806a591ce894ff5c699c28fe02093d6cdadd6b1ad86819acea05ccb212ff3d sha256:814ff1c8753c9cd3942089a2401f1806a1133f27b6875bcad7b7e68846e205e4 Committed
   401  ```
   402  
   403  Note as well, that the label on the config in the content store starts with `containerd.io/gc.ref`. This is
   404  a garbage collection label. It is this label that keeps the garbage collector from removing the snapshot.
   405  Because the config has a reference to it, the top layer is "protected" from garbage collection. This layer,
   406  in turn, depends on the next layer down, so it is protected from collection, and so on until the root or base layer.
   407  
   408  ### Container
   409  
   410  With the above in place, we know how to create an active snapshot that is useful for the container. We simply
   411  need to [https://godoc.org/github.com/containerd/containerd/snapshots#Snapshotter](Prepare()) the active snapshot,
   412  passing it an ID and the parent, in this case the top layer of committed snapshots.
   413  
   414  Thus, the steps are:
   415  
   416  1. Get the content into the content store, either via [Pull()](https://godoc.org/github.com/containerd/containerd#Client.Pull), or via loading it in the [content.Store API](https://godoc.org/github.com/containerd/containerd/content#Store)
   417  1. Unpack the image to create committed snapshots for each layer, using [image.Unpack()](https://godoc.org/github.com/containerd/containerd#Image). Alternatively, if you use [Pull()](https://godoc.org/github.com/containerd/containerd#Client.Pull), you can pass it an option to unpack when pulling, using [WithPullUnpack()](https://godoc.org/github.com/containerd/containerd#WithPullUnpack)
   418  1. Create an active snapshot using [Prepare()](https://godoc.org/github.com/containerd/containerd/snapshots#Snapshotter). You can skip this step if you plan on creating a container, as you can pass it as an option to the next step.
   419  1. Create a container using [NewContainer()](https://godoc.org/github.com/containerd/containerd#Client.NewContainer), optionally telling it to create a snapshot with [WithNewSnapshot()](https://godoc.org/github.com/containerd/containerd#WithNewSnapshot)