owned this note
owned this note
Published
Linked with GitHub
# Distributing Wasm components using OCI registries
## Wasm components
> See the [_Component Model Explainer_](https://github.com/WebAssembly/component-model/blob/main/design/mvp/Explainer.md) from the specification repository.
> For a deep dive into the motivation and progress for the component model, see [Luke Wagner's WasmDay keynote: _The Path to Components_](https://youtu.be/phodPLY8zNE).
> Read [Dan Gohman's _What is a Wasm component_](https://blog.sunfishcode.online/what-is-a-wasm-component/) and Joel Dice's [_The Wasm component model_](https://www.fermyon.com/blog/webassembly-component-model) articles.
The core [WebAssembly specification](https://webassembly.github.io/spec/core) defines a portable binary format and compilation target for representing executable code. A core Wasm module can import functions, linear memories, or global variables from the host, or it can export them to the underlying execution environment.
However, the Wasm MVP specification does not address how core modules can be composed, how higher-level types could be shared across module or host boundaries, nor does it define the surrounding environment in which such a _unit of code_ needs to be executed.
This is what the new [Wasm component model specification](https://github.com/WebAssembly/component-model) is addressing by introducing the new concept of [_components_](https://github.com/WebAssembly/component-model/blob/main/design/mvp/Explainer.md#component-definitions).
A Wasm component is a self-contained object. Its dependencies are objects (such as nested components, core modules, or instances) that are described within the root component itself, and can be composed at development time _or_ at deployment time to create new components.
An example of a component (in its textual format) that takes a string, then logs it:
```wat
(component
(import "wasi:logging" (instance $logging ...logging interface)
(import "libc" (core module $libc ...libc interface))
(core module $main
...all the compiled wasm code for our component
)
...component-model definitions to link all these up
)
```
The example above showcases how components can contain reusable language runtime modules (in this example `libc`, but language runtimes for languages such as JavaScript or Python could be reused in similar ways) or implementations for standard interfaces (such as `wasi:logging`), as well as non-reusable modules (`main`).
(At deployment time, all dependencies should be resolved and all imports should either be present in the component definition itself or satisfied by the host execution context.)
> Read about [the relationship between WASI and the component model](https://github.com/WebAssembly/component-model/blob/main/design/high-level/FAQ.md).
## Deploying Wasm components
Depending on the intended usage of a given component, we could distinguish between two types of registries, together with two types of artifacts for components:
- development registries - similar to NPM or Crates.io, the components pulled from such a registry are primarily used in the process of developing new components. The components in this type of registry are _unlocked packages_, their dependencies being semantic version (semver) queries for other packages that can be found in the registry.
- deployment registries - similar to how OCI registries are used today in the process of deploying software. The components in this type of registry are _locked packages_ (or [bundled components](https://github.com/bytecodealliance/SIG-Registries/blob/main/glossary.md#bundled-component-and-bundling)), their dependencies being exact versions and content hashes of packages from the registry.
Regardless of the registry type, we can distinguish five main artifact types: components, interfaces, [worlds](https://blog.sunfishcode.online/what-is-a-world), core modules, and general-purpose binary objects that a component needs at runtime.
For this document, we are only interested in using OCI registries as _deployment registries_, with the _primary_ artifact type distributed being a _bundled or locked component_.
Finally, there are two ways in which such a component could be represented at distribution time:
- compact - the component is a single `.wasm` file, which has the constituent nested components, core modules, and data segments as sections in the Wasm binary, which is then distributed as a single blob
- expanded - the root component references its nested components, core modules, and data segments by their content digest. They are all distributed as individual blobs, and hosts are expected to reconstruct them at runtime. (This maximizes deduplication of artifacts and optimizes distribution.)
## Distributing Wasm packages using OCI artifacts
The [OCI Artifacts](https://github.com/opencontainers/artifacts) specification describes how to define new artifact types that can be distributed by reusing the existing OCI registry infrastructure.
The next section proposes the media types used for distributing an _expanded component_ - a root component whose nested components, core modules, and data segments are resolved and referenced by their content digest.
> See [this section](https://github.com/opencontainers/artifacts/blob/main/artifact-authors.md#defining-a-unique-artifact-type) in the Artifacts specification for more information on choosing unique media types.
### Distributing Wasm components
- media type: `application/vnd.w3c.wasm.component.v1+json` - plus _optional_ JSON file containing _metadata_ (that does not impact runtime behavior) associated with the component (authors, license, imports, exports)
- layers:
- one root component: `application/vnd.w3c.wasm.component.v1+wasm` - this is always the first layer in a component and contains the root component for the package that is fully resolved and its dependencies are all resolved and present in the subsequent layers
- any number of:
- nested components: `application/vnd.w3c.wasm.component.v1+wasm`
- core modules: `application/vnd.w3c.wasm.module.v1+wasm`
- data blobs: `application/vnd.w3c.wasm.data.v1+data` - data segment
If no additional layers are present, the root component should be a well-formed component with no external dependencies of references.
Example:
- top-level manifest for a reference pointing to a component:
```json
{
"schemaVersion": 2,
"config": {
"mediaType": "application/vnd.w3c.wasm.component.v1+json",
"digest": "sha256:e89acb10dee2fec22203f25b734510940419d8f3e4a292ed3d4d104e614551f4",
"size": 331
},
"layers": [
{
"mediaType": "application/vnd.w3c.wasm.component.v1+wasm",
"digest": "sha256:db7ca53ddfc81dc58032553ce90859e2ed2fe458febc84536a894585bfb59b1f",
"size": 2087464,
"annotations": {
"org.opencontainers.image.title": "optional-annotation-for-my-root-component"
}
},
{
"mediaType": "application/vnd.w3c.wasm.module.v1+wasm",
"digest": "sha256:8c69a84ec5adec97e47d4250410a7689046762aaa8e89f82ddbb4a89acb7388e",
"size": 96
},
{
"mediaType": "application/vnd.w3c.wasm.module.v1+wasm",
"digest": "sha256:2e5ac59e65b6c3dfe0b322c80215cd6f18c28818053ad876ec4760dfe3527dc5",
"size": 404
}
]
}
```
For the example above, the root component is now referencing the core modules by digest:
```wat
(component
(import "wasi:logging" (instance $logging ...logging interface))
(import "libc@sha256:8c69a84ec5adec" (core module $Libc ...libc interface))
(import "main@sha256:2e5ac59e65b6c3" (core module $Main ...main interface))
...component-model definitions to link all these up
)
```
### Distributing core modules
- media type: `application/vnd.w3c.wasm.module.v1+json` - _optional_ JSON file containing metadata associated with the component (authors, license, layout configuration, environment variables, files)
- layers:
- one core module: `application/vnd.w3c.wasm.module.v1+wasm`
- any number of data blobs: `application/vnd.w3c.wasm.data.v1+data` - if present, data blobs are configured according to the `files` section in the configuration object. Layers that are not present in the `files` section from the configuration object are ignored.
Example:
- top-level manifest for a core module:
```json
{
"schemaVersion": 2,
"config": {
"mediaType": "application/vnd.w3c.wasm.module.v1+json",
"digest": "sha256:f90acb10dee2fec22203f25b734510940419d8f3e4a292ed3apfio04e614551f4",
"size": 331
},
"layers": [
{
"mediaType": "application/vnd.w3c.wasm.module.v1+wasm",
"digest": "sha256:bn8gjca53ddfc81dc58032553ce90859e2ed2fe458febc84536a894585bfbsdfj",
"size": 2087464
},
{
"mediaType": "application/vnd.w3c.wasm.data.v1+data",
"digest": "sha256:8c69a84ec5adec97e47d4250410a7689046762aaa8e89f82ddbb4a89acb7388e",
"size": 46123
},
{
"mediaType": "application/vnd.w3c.wasm.data.v1+data",
"digest": "sha256:2e5ac59e65b6c3dfe0b322c80215cd6f18c28818053ad876ec4760dfe3527dc5",
"size": 9912
}
]
}
```
## Additional media types that are reserved by this proposal, but not fully specified:
### Interfaces
- media type: `application/vnd.w3c.wasm.interface.v1+json` - plus _optional_ JSON configuration file
- layers: `application/vnd.w3c.wasm.interface.v1+wasm` OR `application/vnd.w3c.wasm.interface.v1+wit`
### Worlds
- media type: `application.vnd.w3c.wasm.world.v1+json` - plus _optional_ JSON configuration file
- layers: `application/vnd.w3c.wasm.world.v1+wasm` OR `application/vnd.w3c.wasm.interface.v1+world`
### Data
- media type: `application/vnd.w3c.wasm.data.v1+json` - plus JSON configuration file
- layers: `application/vnd.w3c.wasm.data.v1+data`
TODO: define the configuration files and instances where they are required vs. optional