layers

package
v0.0.0-...-e9f7c1f Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 28, 2024 License: Apache-2.0 Imports: 8 Imported by: 1

Documentation

Overview

This package reads an export reference graph (i.e. a graph representing the runtime dependencies of a set of derivations) created by Nix and groups it in a way that is likely to match the grouping for other derivation sets with overlapping dependencies.

This is used to determine which derivations to include in which layers of a container image.

Inputs

  • a graph of Nix runtime dependencies, generated via exportReferenceGraph
  • popularity values of each package in the Nix package set (in the form of a direct reference count)
  • a maximum number of layers to allocate for the image (the "layer budget")

Algorithm

It works by first creating a (directed) dependency tree:

img (root node) │ ├───> A ─────┐ │ v ├───> B ───> E │ ^ ├───> C ─────┘ │ │ │ v └───> D ───> F

│
└────> G

Each node (i.e. package) is then visited to determine how important it is to separate this node into its own layer, specifically:

  1. Is the node within a certain threshold percentile of absolute popularity within all of nixpkgs? (e.g. `glibc`, `openssl`)

2. Is the node's runtime closure above a threshold size? (e.g. 100MB)

In either case, a bit is flipped for this node representing each condition and an edge to it is inserted directly from the image root, if it does not already exist.

For the rest of the example we assume 'G' is above the threshold size and 'E' is popular.

This tree is then transformed into a dominator tree:

img │ ├───> A ├───> B ├───> C ├───> E ├───> D ───> F └───> G

Specifically this means that the paths to A, B, C, E, G, and D always pass through the root (i.e. are dominated by it), whilst F is dominated by D (all paths go through it).

The top-level subtrees are considered as the initially selected layers.

If the list of layers fits within the layer budget, it is returned.

Otherwise, a merge rating is calculated for each layer. This is the product of the layer's total size and its root node's popularity.

Layers are then merged in ascending order of merge ratings until they fit into the layer budget.

Threshold values

Threshold values for the partitioning conditions mentioned above have not yet been determined, but we will make a good first guess based on gut feeling and proceed to measure their impact on cache hits/misses.

Example

Using the logic described above as well as the example presented in the introduction, this program would create the following layer groupings (assuming no additional partitioning):

Layer budget: 1 Layers: { A, B, C, D, E, F, G }

Layer budget: 2 Layers: { G }, { A, B, C, D, E, F }

Layer budget: 3 Layers: { G }, { E }, { A, B, C, D, F }

Layer budget: 4 Layers: { G }, { E }, { D, F }, { A, B, C }

...

Layer budget: 10 Layers: { E }, { D, F }, { A }, { B }, { C }

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func PackageFromPath

func PackageFromPath(path string) string

PackageFromPath returns the name of a Nix package based on its output store path.

Types

type Layer

type Layer struct {
	Contents    []string `json:"contents"`
	MergeRating uint64
}

Layer represents the data returned for each layer that Nix should build for the container image.

func GroupLayers

func GroupLayers(refs *RuntimeGraph, pop *Popularity, budget int) []Layer

groupLayers applies the algorithm described above the its input and returns a list of layers, each consisting of a list of Nix store paths that it should contain.

func (*Layer) Hash

func (l *Layer) Hash() string

Hash the contents of a layer to create a deterministic identifier that can be used for caching.

type Popularity

type Popularity = map[string]int

Popularity data for each Nix package that was calculated in advance.

Popularity is a number from 1-100 that represents the popularity percentile in which this package resides inside of the nixpkgs tree.

type RuntimeGraph

type RuntimeGraph struct {
	References struct {
		Graph []string `json:"graph"`
	} `json:"exportReferencesGraph"`

	Graph []struct {
		Size uint64   `json:"closureSize"`
		Path string   `json:"path"`
		Refs []string `json:"references"`
	} `json:"graph"`
}

runtimeGraph represents structured information from Nix about the runtime dependencies of a derivation.

This is generated in Nix by using the exportReferencesGraph feature.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL