AkihiroSuda / filegrain

transport-agnostic, fine-grained content-addressable container image layout
https://github.com/opencontainers/image-spec/issues/577
Apache License 2.0
23 stars 4 forks source link
container content-addressed oci oci-image

:warning: FILEgrain is abandoned in favor of stargz/CRFS. See containerd#3731 and https://github.com/ktock/remote-snapshotter


FILEgrain: transport-agnostic, fine-grained content-addressable container image layout

Build Status GoDoc

FILEgrain is a (long-term) proposal to extend OCI Image Format to support CAS in the granularity of file, in a transport-agnostic way.

Your feedback is welcome.

Talks

Pros and Cons

Pros:

Cons:

Format

FILEgrain defines the image manifest which is almost identical to the OCI image manifest, but different in the following points:

It is possible and recommended to put both a FILEgrain manifest file and an OCI manifest file in a single image.

Example

image index: (The second entry is a FILEgrain manifest)

{
    "schemaVersion": 2,
    "manifests": [
    {
        "mediaType": "application/vnd.oci.image.manifest.v1+json",
        ...
    },
    {
        "mediaType": "application/vnd.oci.image.manifest.v1+json",
        ...,
        "annotations": {
        "filegrain.version": "20170501"
        }
    }
    ]
}

image manifest: (a continuity layer on top of a tar layer)

{
    "schemaVersion": 2,
    "layers": [
    {
        "mediaType": "application/vnd.continuity.manifest.v0+json",
        ...
    },
    {
        "mediaType": "application/vnd.oci.image.layer.v1.tar+gzip",
        ..,
    }
    ],
    "annotations": {
    "filegrain.version": "20170501"
    }
}

Distribution

FILEgrain is designed agnostic to transportation and hence can be distribeted in any way.

My personal recommendation is to just put the image directory to IPFS. However, I intentionally designed FILEgrain not to use IPFS multiaddr/multihash.

Future support for IPFS blob store

So as to avoid putting a lot file into a single OCI blob directory, it might be good to consider using IPFS as an additional blob store.

IPFS store support is not yet undertaken, but it would be like this:

{
    "schemaVersion": 2,
    "layers": [
    {
        "mediaType": "application/vnd.continuity.manifest.v0+json",
        ...,
        "annotations": {
            "filegrain.ipfs": "QmFooBar"
        }
    }
    ],
    "annotations": {
    "filegrain.version": "2017XXXX"
    }
}

In this case, the layer SHOULD be fetch via IPFS multihash, rather than the digest values specified in the continuity manifest. Also, the continuity manifest MAY omit digest values, since IPFS provides them redundantly.

Note that this is different from just putting the blobs directory onto IPFS, which would still create a lot of files on a single directory, when pulled from non-FILEgrain implementation.

POC

Builder:

Lazy Puller:

Mounter:

Writable mount is not planned at the moment, as FILEgrain is optimized for "cattles" rather than "pets". Users should use bind-mount or some union filesystems for /tmp, /run, and /home.

POC Usage

Install FILEgrain binary:

$ go get github.com/AkihiroSuda/filegrain

Convert a Docker image (e.g. java:8) to a FILEgrain image /tmp/filegrain-image:

# filegrain build -o /tmp/filegrain-image --source-type docker-image java:8

Prepare an OCI bundle /tmp/bundle.shfrom ./oci-runtime-bundle.template:

# cp -r ./oci-runtime-bundle.template /tmp/bundle
# cd /tmp/bundle
# ./prepare.sh

Mount the local FILEgrain image /tmp/filegrain-image on /tmp/bundle/rootfs:

# filegrain mount /tmp/filegrain-image /tmp/bundle/rootfs

In future, filegrain mount should support mounting remote images over Docker Registry HTTP API as well.

Open another terminal, and start runC with the bundle /tmp/bundle:

# cd /tmp/bundle
# runc run foo

Instead of runc, you will be able to use docker run as well when Docker supports running an arbitrary OCI runtime bundle.

The container starts without pulling all the blobs. Pulled blobs can be found on /tmp/filegrain-blobcacheXXXXX:

# du -hs /tmp/filegrain-blobcache*

This directory grows as you read(2) files within the container rootfs.

POC Benchmark

Please refer to #17.

e.g. Pulling 352MB of blobs is enough for using NLTK with 8.3GB kaggle/python image.

Similar work

Lazy distribution

FAQ

Q. Why not just use IPFS directory? It is CAS in the granularity of file.

A. Because IPFS does not support metadata of files. Also, this way is not transport-agnostic.

Q. Usecases for lazy-pulling?

A. Here are some examples I can come up with:

Please also refer to the list of similar work about lazy distribution.

Q. Isn't it a bad idea to put a lot of file into a single blobs directory?

A. This could be mitigated by avoid putting file into the OCI blob store, and use an external blob store instead e.g. IPFS. (go-ipfs supports sharding), although not transport-agnostic. See also an idea about future support for IPFS blob store.

Also, there is an idea to implement sharding to the OCI native blob store: opencontainers/image-spec#449.