Skip to content

ZFS Support #3

Description

@fabianfreyer

Probably the first backing file system we want to support.

Spec

State

All calldown datasets shall be under a single base dataset, here denoted by <base>

  • <base>/storage - extract fetched layers here
  • <base>/storage/empty@extracted - the empty base dataset
  • <base>/storage/<layer_hash>@extracted - extracted dataset including all sub-datasets
  • <base>/runtime - clone images here from <base>/storage and start jails on them
  • <base>/runtime/<container_id> - root filesystem of a Jail

Operations

Extract

Extracting an image would basically be something along the lines of the following pseudocode:

let lower_snapshot = "<base>/storage/empty@extracted";
for layer in image {
    if !exists("<base>/storage/<layer_hash>@extracted") {
        let layer_dataset = lower_snapshot.clone_into("<base>/storage/<layer_hash>");
        layer.extract_over("<base>/storage/<layer_hash>");
        layer_dataset.snapshot("extracted");
    }
    let current_dataset = "<base>/storage/<layer_hash>@extracted";
}

Start a Jail

// 1. Determine the storage "image" to use as the root filesystem.
let layer_hash = runtime_config.topmost_layer;
let basefs = "<base>/storage/<layer_hash>@extracted";
// 2. Clone it into a new runtime root filesystem
basefs.clone_into("<base>/runtime/<container_id>");
// 3. Set up other mounts
// 4. Start Jail

Commit a Jail

After the Jail is stopped, committing runtime state creates a new storage layer with the current changes.

// 1. Get the runtime path and calculate the hash of the new layer
let runtime_rootfs = "<base>/runtime/<container_id>";
let hash = calculate_layer_hash(runtime_rootfs);
// 2. Snapshot the current runtime state 
let snap = runtime_rootfs.snapshot("extracted");
let storage_layer = snap.clone_into("<base>/storage/<hash>");
// 3a) Promote the cloned storage layer.
//     At the moment the dependency chain is
//         [base layer] -> [runtime]@extracted -> [new layer].
//     After promotion, this is reversed:
//         [base layer] -> [new layer]@extracted -> [runtime].
storage_layer.promote();
storage_layer.snapshot("extracted");
// 3b) If we aren't going to reuse the runtime (e.g. to build another layer), delete it:
runtime_rootfs.destroy();
// 4. Update container config to add layer <hash>

Package

This would be going through all changes between a layer and the layer immediately below it with zfs diff <base>/storage/<base_layer>@extracted <base>/storage/<layer>@extracted or similar, and collect the following in a tarball:

  • whiteout list containing deleted files
  • changed / added files

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requesthelp wantedExtra attention is neededspecSpecificationstorageStorage

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions