Authoring OCI Registry Artifacts – Quick Guide

If you’re looking to author new artifact types that can be pushed to OCI compliant registries, here’s a quick guide for what you need to do.

See this post for background on OCI Artifact Registries and some this announcement for working with Sylabs for Singularity High Performance Computing

As a quick reference, I’ll use a Docs in Markdown artifact type as an overly simple example. The format has a layer that provides an overview. In theory, it could be read by the registry to provide info to a user on what the other artifacts in the repo represent. And, it can be downloaded locally, for offline docs.

There’s another description layer that has the larger contents. Both these files are uncompressed, stored directly as .md (markdown) files. OCI registries store and serve these as generic blobs. The extension is really used by the artifact client to discern how to process the file.

Note, we are still using the OCI image manifests. This root mediaType is actually optional in the OCI spec, but we continue to use this schema as it minimizes the churn to registry implementations. Our artifacts are uniquely identified using the manifest.config.mediaType

OCI Artifact Manifest Example:

{
  "schemaVersion": 2,
  "mediaType": "application/vnd.oci.image.manifest.v1+json",
  "config": {
    "mediaType": "application/vnd.stevelasker.docsinmarkdown.config.v1+json",
    "digest": "sha256:44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a",
    "size": 2
  },
  "layers": [
    {
      "mediaType": "application/vnd.stevelasker.docsinmarkdown.overview.layer.v1+md",
      "digest": "sha256:d15f3b9978be09aa01e42c806d3daf95ecac58d53df1e9cd472600ae01e0f96b",
      "size": 398
    },
    {
      "mediaType": "application/vnd.stevelasker.docsinmarkdown.description.layer.v1+md",
      "digest": "sha256:767f3c907f24e463b263137827dac9ce1882213abec1e8752ce55a8c2ecec2c4",
      "size": 149
    }
  ]
}

Defining Your Artifact Type

A key element of OCI Artifact registries is uniquely identifying the type. This allows a registry to let users and other tools know what it is. Imagine all the files on your hard drive didn’t have extensions or identifiers. How would you know which is which? When you double clicked, or launched it from a cli; what would it do? How would vulnerability scanners know how to process the different files? Uniquely defining artifact types provides this same experience.

Artifact Type Format

Artifacts are defined by manifest.config.mediaType using the following format:

application/vnd.[org/company].[objectType].[optional sub type].config.[version]+json

json should be consistently used as the config object should be optionally parsed by a registry. This is currently a reserved design as config definition and parsing isn’t fully defined for non OCI Image artifacts.

Some examples are:

Artifact TypemediaType
OCI Image application/vnd.oci.image.config.v1+json
Helm Chart application/vnd.cncf.helm.chart.config.v1+json
Note helm.chart is used as the helm community is thinking of other artifact types like helm.plugin
Singularity, by Sylabs application/vnd.sylabs.sif.config.v1+json
Singularity is provided by Sylabs, providing a unique scoped definition.

Optionally, Defining Config Schema

Often, configuration info is needed for how the artifact runtime or client tools might process the artifact type. In most cases, the config contents is opaque to a registry. Registries may validate some schemas for specific artifact types. For instance, OCI images can declare their platform and architecture. This allows registries and tooling to understand if the image is a Windows or Linux image. While it’s required to specify a unique manifest.config.mediaType, the contents of the config file can be empty, or even a null file reference.

Define Layer Types

The layers are where artifacts really take shape. These are again, left to the artifact author to define. From a registry perspective, it just needs to uniquely identify the various layer types. While OCI Images use an ordinal collection of layers to make a unified file system, this is specific to OCI images. You might choose to store layers differently.

One layer might represent a collection of files, compressed with the tar format. Another layer might represent another collection of files, or a single file.

These are again defined using the mediaType with the following format:

application/vnd.[org|company].[layerType].[layerSubType].layer.[version]+[fileFormat]

Some examples:

Artifact TypemediaType

OCI Image Layer
application/vnd.oci.image.layer.v1+tar
Helm Chart Layer application/vnd.cncf.helm.chart.layer.v1+tar
Helm Chart Meta Layer
application/vnd.cncf.helm.chart.meta.layer.v1+json
Singularity SIF Layerapplication/
Singularity SIF file: application/vnd.
sylabs.sif.layer.v1+tar

Define User Bling

Once you have an artifact being pushed to registries, you’ll likely want users to know what these things are. The mediaTypes are great for uniquely defining your artifact types to computers. They’re not very helpful for the human eye.

By defining a string and logo for your artifact, registries can display this information in human readable form.

This is where we get a little more vague, and are working on more clarity, soliciting feedback.

You’ll want to provide a short string, to be listed in cli and web page listings.

The latest scalable image format is becoming svg. While not as easy for many developers to hack up, they provide a great means to scale up and down.

Ultimately, we’ll have a common json format for people to submit their information. For now, we’ll just ask for the mediaTypes, a short string for the manifest.config.mediaType and a logo in svg format.

Here’s the current place to submit requests for ACR. Although, the goal is to complete the OCI Artifacts PR to the OCI Distribution Spec.

Collections of Artifacts using the OCI Index

At this point, the only artifact type we know needs index is CNAB, which conceptually stores a collection of artifact types. However, we also expect other artifacts to use this collection format as well.

The immediate conflict here is OCI Image Index doesn’t support a config object in the image spec, and there is some resistance to adding it to the image spec, to avoid breaking clients that have implemented it. My latest proposal is the distribution spec would support an optional config object where the index can declare it’s type: application/vnd.deislabs.cnab.config.v1+json

Before we bring this back to the OCI working group, we’ll need to test and validate this a bit more. Including what happens when existing docker clients attempt to pull an OCI Index, that has a config object. Perhaps the distribution spec can understand which clients are pulling, or we simply create relevant PRs on the various OCI registry clients. Since the OCI distribution spec hasn’t hit a v1 milestone, we do have this option.

Implementing An Artifact CLI

If you’ve gotten this far, you’re either wondering how to create these manifests, or are already using the ORAS library.

Using ORAS, you can directly test your new artifacts with something like the following:

oras push demo42.azurecr.io/samples/docs-in-markdown:1 \
     --manifest-config ./config.json:application/vnd.stevelasker.docsinmarkdown.config.v1+json \
    ./readme.md:application/vnd.stevelasker.docsinmarkdown.layer.v1+md \
    ./moredetail.md:application/vnd.stevelasker.docsinmarkdown.layer.v1+md

You can include the ORAS go library directly in your CLI, creating a custom experience, as done with Helm 3, Singularity and OPAS.

For some more info, this deck has the content from the Cloud-Native Rejekts presentation.

What cloud-native artifacts do you want to author? Let us know.

Steve