Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Compile to WASM #675

Open
imjasonh opened this issue Mar 29, 2022 · 7 comments
Open

Compile to WASM #675

imjasonh opened this issue Mar 29, 2022 · 7 comments
Labels
lifecycle/frozen question Further information is requested

Comments

@imjasonh
Copy link
Member

Go can compile to WASM (GOOS=js GOARCH=wasm), and WASM can be packaged into images and executed on K8s clusters using krustlet: https://developer.okta.com/blog/2022/01/28/webassembly-on-kubernetes-with-rust

So, maybe ko can build a WASM executable, and put it in a multiarch image, alongside the other ko-built archs.

This wouldn't work for Go executables that need to call into their base images (I don't think WASM images have multiple layers, and the environment isn't very linux-ey...yet?), but it should mostly maybe kinda work if they're just static binaries, which is exactly ko's sweet spot.

An example WASM image that kruslet can apparently run: https://explore.ggcr.dev/?image=webassembly.azurecr.io%2Fhello-wasm%3Av1 -- note media types and the annotation.

Questions:

  • What OCI platform does kruslet expect when it's given a multiplatform image? js/wasm?

  • How should users express this? ko build ./ --wasm to additionally produce a WASM image in the index?

@imjasonh imjasonh added the question Further information is requested label Mar 29, 2022
@imjasonh
Copy link
Member Author

  • What OCI platform does kruslet expect when it's given a multiplatform image? js/wasm?

Kruslet doesn't appear to support pulling from indexes at all, only OCI artifacts with the WASM media types. So this is probably not going to be something worth shoehorning into ko.

This might still make sense as a separate Go-specific pipeline for building WASM images, a la wasm-to-oci with fewer steps, but it won't coexist alongside regular OCI images.

@imjasonh
Copy link
Member Author

imjasonh commented Apr 28, 2022

A braindump after thinking about this a bit more:

So in order for this to work, I think we need to agree on a few things with whatever run-this-OCI-image-as-wasm runtime we're working with:

If the runtime:

  • looks for an image in a multiarch index with platform js/wasm, and
  • looks at that image's entrypoint to find the wasm file in the image that it should run when it starts
    (these seem like reasonable expectations to me 🤷‍♂️)

Then ko can build with that expectation, and produce an image that the runtime can pull and run.

What this would enable is, a ko-built app that can run on linux/amd64, or linux/amd64, or our magical wasm runtime platform. We really benefit from ko's assumption that all this image business is just a formality to let us package and distribute a Go binary that can be pulled and run.

Advantages:

  • a user can build for standard K8s or some K8s-compatible-ish wasm runtime (like krustlet), and even migrate an app between the two without much change to their build/push process 🤞
  • this helps adoption of our magical wasm runtime platform, since it doesn't require a new custom build process targeting the runtime platform
  • OCI signing and SBOMing tools (including ko) should "just work" here more or less the same as for non-WASM

Some limitations:

  • kodata probably won't work, or at least won't work for now. That's probably fine for now
  • the ✨ magical wasm runtime ✨ that adheres to the contract doesn't exist ...yet

@imjasonh
Copy link
Member Author

Reopening as I still think this is an idea worth pulling on.

@imjasonh imjasonh reopened this Apr 28, 2022
@imjasonh
Copy link
Member Author

cf: Istio's WASM plugins are also packaged as OCI images (building tutorial, spec)

TL;DR: In this case, the format seems to be:

  • the image must be a single-arch OCI image (not index)
  • the image must contain one layer
  • the layer must contain a file named plugin.wasm (entrypoint is ignored)
  • and optionally a runtime-config.json

This seems fine for Istio, there's not a lot of use cases for multi-platform WASM and non-WASM plugins there I think, but it's something to consider as folks have gone down this path before and made certain decisions.

@imjasonh
Copy link
Member Author

ref: Similar discussion in buildpacks, to allow buildpacks to run and produce a wasm image instead of the standard OCI image: buildpacks/lifecycle#820

In this case, it would be either-or, and buildpacks wouldn't create a single multi-platform index containing the wasm image and the standard linux/amd64 (e.g.) image. But maybe if that was supported somewhere, they could.

@hown3d
Copy link

hown3d commented Jun 2, 2022

This is indeed very interesting!
I think that if we target wasm, we should focus on WASI first.
WASI implements a way to run WASM binaries on a runtime, e.g. WasmEdge.

crun has implementations for handling WASI Images already, but is toggled via a feature flag which needs to bet set during crun compile time: https://github.com/second-state/wasmedge-containers-examples/blob/fb049e4d9884699622ffea0963a77f9d7f0b1f39/containerd/install.sh#L38
Here's an example how to create a suitable image: https://github.com/containers/crun/blob/main/docs/wasm-wasi-example.md.
A container Image is considered to be run by a WASI runtime, if the ENTRYPOINT is set to a .wasm binary and an annotation module.wasm.image/variant=compat exists.
See https://github.com/containers/crun/blob/main/src/libcrun/handlers/handler-utils.c for the exact check.

Kubernetes pods, if containerd, cri-o etc. don't use the rebuilt crun binary by default, include a runtimeClass in their spec.

But all of that has some issues: std go doesn't yet provide a way to generate binaries for target WASI. We would need to use tinygo to target wasi, so the options would be:
a) use tinygo's build package in ko (already tried that a bit here, but tinygo uses wasi-libc via cgo bindings and it's a pain to handle)
b) wrap around the tinygo binary with exec.Cmd. This is currently done with the go binary too: https://github.com/google/ko/blob/e4a01f683fdc0ed2b8f4d6729b9149b56ac716be/pkg/build/gobuild.go#L284

If this is something to look forward to, I'd be happy to try and provide an experimental PR.

@github-actions
Copy link

github-actions bot commented Sep 1, 2022

This issue is stale because it has been open for 90 days with no
activity. It will automatically close after 30 more days of
inactivity. Keep fresh with the 'lifecycle/frozen' label.

@github-actions github-actions bot closed this as not planned Won't fix, can't repro, duplicate, stale Oct 2, 2022
@imjasonh imjasonh reopened this Oct 3, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
lifecycle/frozen question Further information is requested
Projects
None yet
Development

No branches or pull requests

2 participants