Install oci-spec
mainAdd oci-spec to your Cargo.toml dependencies to use the Open Container Initiative (OCI) specifications in your Rust project.
Requirements:
rustcversion 1.54 or higher.
[dependencies]
oci-spec = "0.10.0"repository·main·Indexed 43 days ago
https://github.com/youki-dev/oci-spec-rsA Rust library providing programmatic access to Open Container Initiative (OCI) specifications, including Image Format, Runtime, and Distribution specs. Version 0.10.0 provides tools for managing OCI image manifests, configurations, artifact manifests, and descriptors using builder patterns and serialization/deserialization methods.
Add oci-spec to your Cargo.toml dependencies to use the Open Container Initiative (OCI) specifications in your Rust project.
Requirements:
rustc version 1.54 or higher.[dependencies]
oci-spec = "0.10.0"To become a Maintainer, you must demonstrate commitment, technical ability, and collaboration. The process involves meeting specific contribution thresholds and receiving approval via a simple majority vote from existing Maintainers.
The oci-spec crate provides structured Rust representations of the Open Container Initiative (OCI) specifications. Depending on the enabled features, you can access the following modules:
image: Types and structures for the OCI Image Format specification (requires image feature).runtime: Types and structures for the OCI Runtime specification (requires runtime feature).distribution: Types and structures for the OCI Distribution specification (requires distribution feature).The Hooks struct allows you to specify commands that run at specific events during a container's lifecycle. These hooks are used for setup and teardown operations, such as configuring network namespaces or cleaning up resources.
| Hook Type | Timing | Namespace |
|---|---|---|
create_runtime | After container creation, before pivot_root | Runtime Namespace |
create_container | After container creation, before pivot_root | Container Namespace |
start_container | After the start operation, before the container process starts | Container Namespace |
poststart | After the container process has started | Runtime Namespace |
poststop | After the container process exits | Runtime Namespace |
prestart (Deprecated) | After start is called, before the user program executes | Runtime Namespace |
Note: prestart is deprecated in favor of create_runtime, create_container, and start_container hooks.
// Example of building a Hooks configuration
let hooks = Hooks::builder()
.create_runtime(vec![Hook::builder().path("/usr/bin/setup-net").build().unwrap()])
.poststop(vec![Hook::builder().path("/usr/bin/cleanup").build().unwrap()])
.build()
.unwrap();The Capability enum represents Linux kernel capabilities used to divide superuser privileges into distinct units. This allows for fine-grained permission control in OCI runtimes.
When deserializing Capability values (e.g., from JSON or configuration files), the implementation is highly flexible. It is case-insensitive and automatically strips any number of CAP_ prefixes. This makes it compatible with various input formats, such as those used in Kubernetes or standard Linux tooling.
Supported Formats:
CAP_SYS_ADMIN (Standard)SYS_ADMIN (Stripped prefix)cap_sys_admin (Lowercase)CAP_CAP_SYS_ADMIN (Multiple prefixes)// Example of flexible deserialization
let cap: Capability = serde_json::from_str("\"syslog\"").unwrap();
let cap: Capability = serde_json::from_str("\"CAP_SYSLOG\"").unwrap();
let cap: Capability = serde_json::from_str("\"cap_SYSLOG\"").unwrap();The ImageIndex struct is a high-level OCI manifest that points to specific image manifests, typically used to support multiple platforms (e.g., different architectures or operating systems) within a single index.
schema_version: Required. Must be 2 for compatibility with older Docker versions. The constant SCHEMA_VERSION is provided for this purpose.manifests: Required. A list of Descriptor objects pointing to specific platform manifests.media_type: Optional. The media type of the document.artifact_type: Optional. Used when the manifest is used for an artifact (must comply with RFC 6838).subject: Optional. A descriptor of another manifest, used by the referrers API to indicate a relationship.annotations: Optional. Arbitrary metadata following annotation rules.ImageIndex supports the builder pattern via ImageIndexBuilder.
use oci_spec::image::{ImageIndex, ImageIndexBuilder, MediaType, DescriptorBuilder};
// Example of building an ImageIndex
let index = ImageIndexBuilder::default()
.schema_version(2)
.manifests(vec![/* list of Descriptors */])
.build()
.expect("failed to build index");The OciLayout struct represents the JSON object that serves as a marker for the base of an Open Container Image Layout. It provides the version of the image layout in use, which aligns with the OCI Image Specification version.
Key properties:
image_layout_version: A required string specifying the layout version.You can use the OciLayoutBuilder to construct new instances and the provided methods to serialize/deserialize the layout to files, readers, writers, or strings.
use oci_spec::image::OciLayout;
let oci_layout = OciLayoutBuilder::default()
.image_layout_version("1.0.0")
.build()
.unwrap();An ImageManifest provides a configuration and a set of layers for a single container image for a specific architecture and operating system. It is distinct from an ImageIndex, which describes a set of images spanning multiple architectures.
schema_version: REQUIRED. Must be 2 for backward compatibility.config: REQUIRED. A Descriptor referencing the image configuration object by digest.layers: REQUIRED. An array of Descriptor objects. The base layer must be at index 0, with subsequent layers following in stack order.media_type: OPTIONAL. The media type of the document.artifact_type: OPTIONAL. Used when the manifest is used for an artifact; must comply with RFC 6838.subject: OPTIONAL. A Descriptor of another manifest, used by the referrers API to indicate a relationship.annotations: OPTIONAL. A HashMap<String, String> containing arbitrary metadata.use oci_spec::image::ImageManifest;
use oci_spec::image::DescriptorBuilder;
// Example of building a manifest (conceptual structure)
let manifest = ImageManifestBuilder::default()
.schema_version(2)
.config(config_descriptor)
.layers(vec![layer_descriptor_1, layer_descriptor_2])
.build()
.expect("build image manifest");The Spec struct is the root object representing the OCI Runtime Specification (typically found in a config.json file). It defines the entire configuration for a container, including its version, root filesystem, mounts, process details, hostname, hooks, and platform-specific configurations (Linux, Windows, Solaris, etc.).
Key fields include:
version: A SemVer v2.0.0 string specifying the OCI Runtime Spec version.root: Specifies the container's root filesystem.mounts: Additional mounts beyond the root.process: The container process configuration (required for start).hostname / domainname: Network identity within the container.hooks: Programs to run during container lifecycle events.annotations: A key-value map for arbitrary metadata.linux / windows / solaris / vm / zos: Platform-specific configuration objects.use oci_spec::runtime::Spec;
let spec = Spec::default();
// Access fields via getters provided by getset macro
let version = spec.version();
let hostname = spec.hostname();
// Use setters to modify
spec.set_hostname("new-host".to_string());
// Use mut getters for mutable access
spec.get_mut_annotations();Use ImageManifest::from_file to load an existing OCI image manifest from the filesystem. This returns an ImageManifest instance which you can then inspect, for example, by checking the number of layers.
use oci_spec::image::ImageManifest;
let image_manifest = ImageManifest::from_file("manifest.json").unwrap();
assert_eq!(image_manifest.layers().len(), 5);Use RepositoryListBuilder from the oci_spec::distribution module to construct a list of repository names as defined by the OCI Distribution Specification.
use oci_spec::distribution::RepositoryListBuilder;
let list = RepositoryListBuilder::default()
.repositories(vec!["busybox".to_owned()])
.build().unwrap();You can construct complex OCI Image Manifests using the ImageManifestBuilder and DescriptorBuilder. This involves defining a configuration descriptor and a list of layer descriptors, then assembling them into the manifest.
Key components:
DescriptorBuilder: Used to create descriptors for the image config and individual layers (specifying media_type, size, and digest).ImageManifestBuilder: Used to assemble the schema_version, the config descriptor, and the collection of layer descriptors.MediaType: Provides standard OCI media types like ImageConfig and ImageLayerGzip.Sha256Digest: Used to parse and hold SHA256 digests.to_file_pretty: Saves the constructed manifest to a file in a human-readable JSON format.use std::str::FromStr;
use oci_spec::image::{
Descriptor,
DescriptorBuilder,
ImageManifest,
ImageManifestBuilder,
MediaType,
Sha256Digest,
SCHEMA_VERSION
};
let config = DescriptorBuilder::default()
.media_type(MediaType::ImageConfig)
.size(7023u64)
.digest(Sha256Digest::from_str("b5b2b2c507a0944348e0303114d8d93aaaa081732b86451d9bce1f432a537bc7").unwrap())
.build()
.expect("build config descriptor");
let layers: Vec<Descriptor> = [
(
32654u64,
"9834876dcfb05cb167a5c24953eba58c4ac89b1adf57f28f2f9d09af107ee8f0",
),
(16724, "3c3a4604a545cdc127456d94e421cd355bca5b528f4a9c1905b15da2eb4a4c6b"),
(73109, "ec4b8955958665577945c89419d1af06b5f7636b4ac3da7f12184802ad867736",),
]
.iter()
.map(|l| {
DescriptorBuilder::default()
.media_type(MediaType::ImageLayerGzip)
.size(l.0)
.digest(Sha256Digest::from_str(l.1).unwrap())
.build()
.expect("build layer")
})
.collect();
let image_manifest = ImageManifestBuilder::default()
.schema_version(SCHEMA_VERSION)
.config(config)
.layers(layers)
.build()
.expect("build image manifest");
image_manifest.to_file_pretty("my-manifest.json").unwrap();