Skip to content

feat(builder): Add rootfs implementation for reading OCI images - #413

Open
craciunoiuc wants to merge 1 commit into
prod-stagingfrom
craciunoiuc/handle-oci-type
Open

feat(builder): Add rootfs implementation for reading OCI images#413
craciunoiuc wants to merge 1 commit into
prod-stagingfrom
craciunoiuc/handle-oci-type

Conversation

@craciunoiuc

@craciunoiuc craciunoiuc commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Tested work and it seemed fine. Pasting again uses:
Case 1:

rootfs:
  format: erofs
  type: oci
  source: index.unikraft.io/test/check-pr:latest

Case 2:

rootfs:
  format: erofs
  type: oci
  source: index.docker.io/hello-world:latest

You can use these prefixes: oci://, oci-layout://, oci-archive:// taken from image-spec:

case imagespec.URISchemeOCI, imagespec.URISchemeOCILayout, imagespec.URISchemeOCIArchive:

We decided to use only the oci type variable.

Also needs another bump to the gomod.

Closes: TOOL-1073

@craciunoiuc

Copy link
Copy Markdown
Contributor Author

let me know if these single use functions you want to inline

I found them significant enough to keep separate for now

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds support in the builder to treat OCI image references (registry, OCI layout, OCI archive) as rootfs sources, including logic to unpack regular OCI layers into a rootfs and to use a Unikraft-specific initrd component when present.

Changes:

  • Detect OCI rootfs sources via URI schemes and route BuildRootfs to a new OCI implementation.
  • Implement buildRootfsOCI to load OCI images per requested platform, flatten layers into a directory, and package into CPIO/EROFS.
  • Update kraftfile-to-buildopts translation and expand unit/integration-style tests for OCI sources.

Reviewed changes

Copilot reviewed 6 out of 7 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
internal/builder/rootfs.go Adds OCI source detection + buildRootfsOCI (load, platform match, layer flatten, repack).
internal/builder/rootfs_test.go Adds DetectSourceType tests for OCI schemes and integration-style rootfs OCI tests.
internal/builder/rootfs_oci_test.go Adds helpers to generate local OCI archives used by tests.
internal/builder/kraftfile.go Avoids filepath-joining when rootfs/ROM source is an OCI reference or explicitly typed OCI.
internal/builder/kraftfile_test.go Adds coverage for OCI paths/types in kraftfile-to-buildopts conversion.
go.mod Pulls in new (indirect) deps required by containerd/v2 usage.
go.sum Updates sums for newly introduced transitive dependencies.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread internal/builder/rootfs_oci_test.go Outdated
Comment thread internal/builder/rootfs.go Outdated
Comment thread internal/builder/kraftfile.go Outdated
Comment thread internal/builder/rootfs.go Outdated
Comment thread internal/builder/rootfs.go Outdated
@craciunoiuc
craciunoiuc force-pushed the craciunoiuc/handle-oci-type branch from 90f96a2 to ae59715 Compare July 30, 2026 14:34
Comment thread internal/builder/rootfs.go Outdated
@craciunoiuc
craciunoiuc marked this pull request as draft July 30, 2026 14:59
@craciunoiuc
craciunoiuc force-pushed the craciunoiuc/handle-oci-type branch 3 times, most recently from c3ae0df to fe4bd3f Compare July 30, 2026 18:59
Comment thread internal/builder/rootfs.go Outdated
Comment thread internal/builder/rootfs.go Outdated
return nil, fmt.Errorf("could not open flattened rootfs image as filesystem: %w", err)
}

f, err := os.CreateTemp("", "unikraft-rootfs-*."+string(opts.Rootfs.Format))

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to start to think if we want to start moving these image build operations into the local directory

Tmpfs gets really crowded when we chuck so many image artifacts into it

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated 1 comment.

Suppressed comments (2)

internal/builder/rootfs.go:57

  • cfg.Labels = opts.Labels overwrites any labels coming from the base image config even when opts.Labels is nil/unset, which loses inherited labels for OCI-rootfs builds (and any other path that uses applyConfigOverrides). Consider only overriding labels when the caller actually provided them (e.g., if opts.Labels != nil { ... }), or merge maps so explicitly-provided keys override while preserving the rest.
func applyConfigOverrides(base ocispec.ImageConfig, opts BuildOpts) ocispec.ImageConfig {
	cfg := base
	if opts.Cmd != nil {
		cfg.Cmd = opts.Cmd
	}
	if opts.Env != nil {
		env := make([]string, 0, len(opts.Env)+len(cfg.Env))
		for _, kv := range opts.Env {
			env = append(env, fmt.Sprintf("%s=%s", kv.Key, kv.Value))
		}
		cfg.Env = append(env, cfg.Env...)
	}
	cfg.Labels = opts.Labels
	return cfg
}

internal/builder/rootfs_oci_test.go:90

  • In OCI image config, RootFS.DiffIDs are expected to be the digests of the uncompressed layer tar streams (diffIDs), while the manifest layer descriptors typically use the digest of the (often compressed) blob. Here diffIDs are derived from desc.Digest (from tarGzipLayer), which makes the fixture OCI config non-spec-compliant and could break consumers that validate diffIDs. Consider computing diffIDs from the uncompressed tar bytes (or streaming hasher before gzip) while keeping desc.Digest for the compressed blob.
	diffIDs := make([]digest.Digest, 0, len(layerDescs))
	for _, desc := range layerDescs {
		diffIDs = append(diffIDs, desc.Digest)
	}

	config := ocispec.Image{
		Platform: ocispec.Platform{
			Architecture: "amd64",
			OS:           "linux",
		},
		Config: ocispec.ImageConfig{
			Cmd: []string{"/bin/sh"},
		},
		RootFS: ocispec.RootFS{
			Type:    "layers",
			DiffIDs: diffIDs,
		},
	}

Comment thread internal/builder/rootfs.go
Uses buildkit to download and use OCI images.
Works with both regular images, and Unikraft images.
Unikraft images have their rootfs already packaged so we fast forward.

Signed-off-by: Cezar Craciunoiu <cezar@unikraft.io>
@craciunoiuc
craciunoiuc force-pushed the craciunoiuc/handle-oci-type branch from e7d40aa to 5efd1e1 Compare July 31, 2026 09:32
@craciunoiuc
craciunoiuc marked this pull request as ready for review July 31, 2026 15:21
@jedevc
jedevc self-requested a review July 31, 2026 15:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants