Skip to content

Commit 7389be1

Browse files
mathetakeSodman
andauthored
Add a variant of Wasm image spec based on standard media types. (#265)
* Add OCI-compatible Wasm Spec. Signed-off-by: Takeshi Yoneda <[email protected]> * Review: add annotation instruction Signed-off-by: Takeshi Yoneda <[email protected]> * Rename filter.wasm to plugin.wasm to line with API. Signed-off-by: Takeshi Yoneda <[email protected]> * review: Add docker variant. Signed-off-by: Takeshi Yoneda <[email protected]> * style Signed-off-by: Takeshi Yoneda <[email protected]> * clear Signed-off-by: Takeshi Yoneda <[email protected]> * Update spec/README-compat.md Co-authored-by: Shane O'Donnell <[email protected]> * Update spec/README-compat.md Co-authored-by: Shane O'Donnell <[email protected]> * Restrcture spec/ dir, add general info. Signed-off-by: Takeshi Yoneda <[email protected]> * fix typo Signed-off-by: Takeshi Yoneda <[email protected]> * Not necessarily Istio. Signed-off-by: Takeshi Yoneda <[email protected]> * Put common terminology in README Signed-off-by: Takeshi Yoneda <[email protected]> * Update spec/README.md Co-authored-by: Shane O'Donnell <[email protected]> * Fix typo, add more sentences. Signed-off-by: Takeshi Yoneda <[email protected]> * Make annotations optional. Signed-off-by: Takeshi Yoneda <[email protected]> Co-authored-by: Shane O'Donnell <[email protected]>
1 parent ea64e9f commit 7389be1

File tree

3 files changed

+293
-107
lines changed

3 files changed

+293
-107
lines changed

spec/README.md

+37-107
Original file line numberDiff line numberDiff line change
@@ -1,133 +1,63 @@
1+
# Wasm Image specifications
12

2-
## WASM Artifact Image Specification v0.0.0
3+
## Introduction
34

4-
- [Introduction](#introduction)
5-
- [Terminology](#terminology)
6-
- [Description](#description)
7-
- [Overview](#overview)
8-
- [Layers](#layers)
9-
- [Running OCI Images with Envoy](#running-oci-images-with-envoy)
10-
- [Format](#format)
11-
- [Envoy WASM Filter Specification](#envoy-wasm-filter-specification)
12-
- [Example](#example)
5+
The Wasm Image specification defines how to bundle Wasm modules as container images. A compatible Wasm image consists of a Wasm binary file, and runtime metadata for the target Wasm runtime. We primarily consider the use case of [Envoy] as Wasm runtime and its Wasm filter/plugins, although the spec is intended to be generic and to provide a standard mechanism to manage the building and running of Wasm modules on any Wasm runtime.
136

14-
15-
### Introduction:
16-
17-
The WASM Artifact Image Specification defines how to bundle WASM modules as OCI images. WASM Artifact Images consist of a WASM binary file, configuration file, and metadata for the target WASM runtime.
18-
19-
The spec is intended to be generic, allowing for any type of WASM module whether it is used to extend any Envoy, OPA, or the browser.
20-
21-
The spec can be considered an extension of the OCI Artifact Spec designed specifically for use by applications which produce and consume WASM modules (as opposed to application containers). It is intended to provide a standard mechanism to manage the building and running of WASM modules.
22-
23-
This document considers primarily the use case of storing WASM Envoy Filters as OCI Images.
24-
25-
### Terminology:
7+
## Terminology:
268

279
| Term | Definition |
2810
|------------------------------------|--------------------------------------------------|
29-
| WASM Module | The distributable, loadable, and executable unit of code in WebAssembly.
30-
| WASM OCI Image Specification | The specification for storing WASM modules as OCI Images.
31-
| WASM Runtime | The execution environment into which a WASM Module may be loaded. This refers to the application itself which loads and executes a wasm module. Examples include web browsers, the Open Policy Agent, the Envoy Proxy, or any other application which supports extension via WASM modules.
32-
| Runtime Configuration | Configuration specific to the runtime which consumes a module. This configuration is stored as JSON and bundled with the module in the image in the specification.
33-
| Envoy WASM Filter | Custom Filters for the Envoy Proxy built as a WASM module.
34-
| Envoy WASM OCI Image | Envoy Filters stored as OCI images according to the specification.
35-
| Envoy WASM OCI Artifact Specification | An extension of the WASM OCI Artifact Spec which describes how to bundle and ship Envoy WASM filters as OCI Images. |
36-
37-
### Description:
38-
39-
#### Overview:
40-
41-
The WASM OCI Artifact Specification defines a method of storing WASM modules which makes them easy to build, pull, publish, and execute.
42-
43-
Because each execution environment (runtime) for a WASM module may have runtime-specific configuration parameters, a WASM image is composed of both a content layer, for the WASM module itself, as well as a config layer, with metadata describing the module which is relevant to the target runtime.
44-
45-
#### Layers:
46-
47-
The content layer always consists of the WASM module binary.
48-
49-
The config layer consists of a JSON-formatted string, which contains metadata for the target runtime. The runtime and ABI (Application Binary Interface) versions of an image can be deduced by parsing the config layer.
50-
51-
The config layer may also contain additional data, depending on the target runtime. For example, the config for a WASM Envoy Filter contains root_ids available on the filter.
52-
53-
For the sake of simplicity, the specification only supports a single module per image.
54-
55-
#### Running OCI Images with Envoy:
11+
| Wasm Module | The distributable, loadable, and executable unit of code in WebAssembly.
12+
| Wasm Image Specification | The specification for storing Wasm modules as container images.
13+
| Wasm Runtime | The execution environment into which a Wasm Module may be loaded. This refers to the application itself which loads and executes a wasm module. Examples include web browsers, the Open Policy Agent, the Envoy Proxy, or any other application which supports extension via Wasm modules.
14+
| Runtime Configuation | Configuration or metadata specific to the runtime which consumes a module.
5615

57-
Envoy supports loading and running WASM modules via a file on local disk or an “Http datasource”.
16+
## Specifications
5817

59-
Envoy WASM Filters can be stored according to the spec and run with Istio and Gloo, with the help of a local cache which pulls images from remote registries.
18+
Here we have several specifications for how to bundle Wasm modules as container images.
6019

61-
Control planes then configure the Envoy instances to load the filter via the local cache, using the required root_id parameter supplied in the image config if it is available.
20+
There are two variants of the specification:
21+
- [spec.md](spec.md)
22+
- [spec-compat.md](spec-compat.md)
6223

24+
Developers and Wasm module consumers can leverage both of these specifications.
6325

64-
### Format:
26+
For clarity, we call the variant in [spec.md](spec.md) *oci*, and the one in [spec-compat.md](spec-compat.md) *compat*.
6527

66-
The WASM OCI Artifact Spec consists of two layers bundled together:
67-
- A layer specifying configuration for the target runtime
68-
- A layer containing the compiled WASM module itself
28+
## Difference between variants
6929

70-
Each layer is associated with its own Media Type, which is stored in the OCI Descriptor for that layer:
30+
Our goal is to make the *oci* variant the default format for shipping Wasm modules in container images, we acknowledge however that there are toolchains and registries deployed and in use that do not support our custom media types yet. To accomodate those exisiting toolchains, there is the semantically equivalent *compat* variant, which provides the same feature set, but is compatible with existing tooling because it 'looks' very much like a normal container image. Implementations of this spec should support both variants.
7131

72-
| Media Type | Type | Description |
73-
|------------|------|-------------|
74-
| application/vnd.module.wasm.config.v1+json | JSON Object | Configuration for the Target WASM runtime.
75-
| application/vnd.module.wasm.content.layer.v1+wasm | binary data (byte array) | The compiled module data |
32+
With that said, the key difference between these two variants is that, the *oci* variant makes use of the custom media types on [OCI Artifact] for image layers while the *compat* variant leverages the standard media types.
7633

77-
`application/vnd.module.wasm.config.v1+json` Property Descriptions:
34+
As a consequence, that introduces the difference in tools available for building and pushing images.
35+
For example, the only way to build and push *oci* variant images is to use [`wasme`] cli while you can use [`buildah`] or [`docker`] for *compat* variant images.
7836

79-
| Property | Type | Description |
80-
|------------|------|-------------|
81-
| type | string | Name of the target runtime. Required. Specifies the intended runtime of the bundled module. The content of the Opaque JSON Config is specific to the type of WASM runtime.
82-
| abiVersions | string array | List of ABI Versions for the target runtime with which the image is compatible. The format for the version is dependent upon the runtime itself.
83-
| config | JSON Object | This field stores any configuration parameters required by the target runtime. Its structure depends on the specified runtime. |
37+
Not only that, the usage of custom media types on top of [OCI Artifact] requires registries to support arbitrary custom media types. Therefore, you might not be able to push *oci* variants to your registry while [WebAssemblyHub] is designed for accepting them.
8438

39+
## Wasm image support in [Istio]
8540

86-
### Envoy WASM Filter Specification
41+
Istio's Wasm Plugin API has support for **both of these variants** to deploy your Wasm plugins into Envoy sidecars.
8742

88-
The runtime config for Envoy WASM Filter OCI Images has the following format:
43+
### Which variant should I use in [Istio]?
8944

90-
- *type* is set to `envoy_proxy`
91-
- *abiVersion* is set to a recognized version of the Envoy Proxy WASM Filter ABI
92-
- *config* is a JSON Object containing a list of Filter root_ids that can be used with the provided filter
45+
Given that Istio supports both of variants, you can choose whichever variant depending on your needs. For example, if you want to use [`docker`] cli, then choose *compat* variant and push them to your container registries. You might want to use [`wasme`] cli and [WebAssemblyHub] then choose the *oci* variant.
9346

94-
The `root_ids` key in the *config* JSON Object will have a list of strings as a value. Each string in the list corresponds to the name of a registered Root Context Helper defined in the module.
47+
## How can I build images?
9548

96-
#### Example:
49+
For *oci* variant, see the guideline by [`wasme`].
9750

98-
The following descriptors provide an example of the OCI Image descriptors for an Envoy WASM Filter stored according to the specification:
99-
```
100-
[
101-
{
102-
"mediaType": "application/vnd.module.wasm.config.v1+json",
103-
"digest": "sha256:d0a165298ae270c5644be8e9938036a3a7a5191f6be03286c40874d761c18abf",
104-
"size": 125,
105-
"annotations": {
106-
"org.opencontainers.image.title": "runtime-config.json"
107-
}
108-
},
109-
{
110-
"mediaType": "application/vnd.module.wasm.content.layer.v1+wasm",
111-
"digest": "sha256:5e82b945b59d03620fb360193753cbd08955e30a658dc51735a0fcbc2163d41c",
112-
"size": 1043056,
113-
"annotations": {
114-
"org.opencontainers.image.title": "filter.wasm"
115-
}
116-
}
117-
]
118-
```
51+
For *compat* variant, follow the instructions in
52+
- [build a compat image with buildah](spec-compat.md#appendix-1-build-a-compat-image-with-buildah) if you want to use [`buildah`].
53+
- [build a compat image with docker](spec-compat.md#appendix-2-build-a-compat-image-with-docker-cli) if you want to use [`docker`].
11954

120-
The following is the runtime config stored as the `application/vnd.module.wasm.config.v1+json` layer:
12155

122-
```{
123-
"type": "envoy_proxy",
124-
"abi_version": "v0-541b2c1155fffb15ccde92b8324f3e38f7339ba6",
125-
"config": {
126-
"root_ids": [
127-
"add_header_root_id"
128-
]
129-
}
130-
}
131-
```
56+
[Envoy]: https://github.com/envoyproxy/envoy
57+
[Istio]: https://github.com/istio/istio
58+
[OCI Artifact]: https://github.com/opencontainers/artifacts
59+
[WebAssemblyHub]: https://webassemblyhub.io/
13260

133-
You can use the `wasme` tool to take new or existing module code and package it according to the WASM OCI Spec.
61+
[`docker`]: https://docs.docker.com/engine/reference/commandline/cli/
62+
[`buildah`]: https://github.com/containers/buildah
63+
[`wasme`]: https://docs.solo.io/web-assembly-hub/latest/installation/

spec/spec-compat.md

+142
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
2+
# Wasm Image Specification v0.0.0
3+
4+
## Introduction:
5+
6+
This document describes a variant of [Wasm Artifact Image Specification](spec.md), which leverages the compatible layer media types. Here, we omit definition and terminology explained in [Wasm Artifact Image Specification](spec.md).
7+
8+
We call this variant "compat", and the spec in [Wasm Artifact Image Specification](spec.md) "oci".
9+
10+
## Description
11+
12+
This *compat* variant makes use of compatible media type for layers, and is not based on custom OCI Artifact media types. This way users can operate with standard tools such as docker, podman, buildah, and standard container registries which don't yet support custom media types as used in [*oci* variant](spec.md).
13+
14+
## Specification
15+
16+
### Layer
17+
18+
The *compat* variant must consist of exactly one layer whose media type is one of the followings:
19+
- `application/vnd.oci.image.layer.v1.tar+gzip`
20+
- `application/vnd.docker.image.rootfs.diff.tar.gzip`
21+
22+
In addition, the layer must consist of the following two files:
23+
- `plugin.wasm` - (**Required**) A Wasm binary to be loaded by the runtime.
24+
- `runtime-config.json` - (**Optional**) A runtime configuration specified in [Wasm Artifact Image Specification](spec.md#Format). This is mainly used as metadata for the image, depending on the runtime.
25+
26+
### Annotation
27+
28+
If the media type equals `application/vnd.oci.image.layer.v1.tar+gzip`, then a *compat* variant image *should* add the annotation `module.wasm.image/variant=compat` in the manifest to make it easy to distinguish this *compat* variant from the *oci* variant. Note that this is **optional**.
29+
30+
### Example with `application/vnd.oci.image.layer.v1.tar+gzip` media type
31+
32+
The following is an example OCI manifest of images with `application/vnd.oci.image.layer.v1.tar+gzip` layer media type:
33+
34+
```
35+
{
36+
"schemaVersion": 2,
37+
"config": {
38+
"mediaType": "application/vnd.oci.image.config.v1+json",
39+
"digest": "sha256:933594cea89247a78932eb9d74fae998e6fc3d1d114a7ff7705aaf702dbf7edb",
40+
"size": 326
41+
},
42+
"layers": [
43+
{
44+
"mediaType": "application/vnd.oci.image.layer.v1.tar+gzip",
45+
"digest": "sha256:e05c6f7d59f4c5976d9c1be8e12c34f64c49e5541967581e7f052070705191ac",
46+
"size": 151
47+
}
48+
],
49+
"annotations": {
50+
"module.wasm.image/variant": "compat"
51+
}
52+
}
53+
```
54+
55+
### Example with `application/vnd.docker.image.rootfs.diff.tar.gzip` media type
56+
57+
The following is an example Docker manifest of images with `application/vnd.docker.image.rootfs.diff.tar.gzip` layer media type:
58+
59+
```
60+
{
61+
"schemaVersion": 2,
62+
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
63+
"config": {
64+
"mediaType": "application/vnd.docker.container.image.v1+json",
65+
"size": 1182,
66+
"digest": "sha256:500c5c9b0755790c440f6d24a8926e399913bda2d599dcac24edb99a72b66de7"
67+
},
68+
"layers": [
69+
{
70+
"mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
71+
"size": 161,
72+
"digest": "sha256:cf72304d01ead8fe014ed9f09e4132678ee4f29030ec46e6242c457071435ec3"
73+
}
74+
]
75+
}
76+
```
77+
78+
## Appendix 1: build a *compat* image with Buildah
79+
80+
We demonstrate how to build a *compat* image with Buildah, a standard cli for building OCI images. We use v1.21.0 of Buildah here. Produced images have `application/vnd.oci.image.layer.v1.tar+gzip` layer media type
81+
82+
We assume that you have a valid Wasm binary named `plugin.wasm` and `runtime-config.json` (optional) that you want to package as an image.
83+
84+
1. First, we create a working container from `scratch` base image with `buildah from` command.
85+
86+
```
87+
$ buildah --name mywasm from scratch
88+
mywasm
89+
```
90+
91+
2. Next, add the annotation described above via `buildah config` command
92+
93+
```
94+
$ buildah config --annotation "module.wasm.image/variant=compat" mywasm
95+
```
96+
97+
**Note this step is optional. See [Annotation](#annotation) section.**
98+
99+
100+
3. Then copy the files into that base image by `buildah copy` command to create the layer.
101+
102+
```
103+
$ buildah copy mywasm plugin.wasm runtime-config.json ./
104+
af82a227630327c24026d7c6d3057c3d5478b14426b74c547df011ca5f23d271
105+
```
106+
107+
**Note: you must execute `buildah copy` exactly once in order to end up having only one layer in produced images**
108+
109+
4. Now, you can build a *compat* image and push it to your registry via `buildah commit` command
110+
111+
```
112+
$ buildah commit mywasm docker://my-remote-registry/mywasm:0.1.0
113+
```
114+
115+
## Appendix 2: build a *compat* image with Docker CLI
116+
117+
We demonstrate how to build a *compat* image with Docker CLI. Produced images have `application/vnd.docker.image.rootfs.diff.tar.gzip` layer media type.
118+
119+
We assume that you have a valid Wasm binary named `plugin.wasm` and `runtime-config.json` (optional) that you want to package as an image.
120+
121+
1. First, we prepare the following Dockerfile:
122+
123+
```
124+
$ cat Dockerfile
125+
FROM scratch
126+
127+
COPY runtime-config.json plugin.wasm ./
128+
```
129+
130+
**Note: you must have exactly one `COPY` instruction in the Dockerfile in order to end up having only one layer in produced images**
131+
132+
2. Then, build your image via `docker build` command
133+
134+
```
135+
$ docker build . -t my-registry/mywasm:0.1.0
136+
```
137+
138+
3. Finally, push the image to your registry via `docker push` command
139+
140+
```
141+
$ docker push my-registry/mywasm:0.1.0
142+
```

0 commit comments

Comments
 (0)