ko-build / ko

Build and deploy Go applications
https://ko.build
Apache License 2.0
7.47k stars 389 forks source link

Compile to WASM #675

Open imjasonh opened 2 years ago

imjasonh commented 2 years ago

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:

imjasonh commented 2 years ago
  • 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 commented 2 years ago

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:

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:

Some limitations:

imjasonh commented 2 years ago

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

imjasonh commented 2 years ago

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

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

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 commented 2 years ago

ref: Similar discussion in buildpacks, to allow buildpacks to run and produce a wasm image instead of the standard OCI image: https://github.com/buildpacks/lifecycle/issues/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 commented 2 years ago

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[bot] commented 1 year ago

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.