-
Notifications
You must be signed in to change notification settings - Fork 25
feat(wasm): add wasm runtime support [KS-44] #131
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
base: develop
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,71 @@ | ||
| //go:build linux && arm | ||
|
|
||
| package embedded | ||
|
|
||
| import ( | ||
| _ "embed" | ||
| "fmt" | ||
|
|
||
| "github.com/portainer/kubesolo/types" | ||
| "github.com/rs/zerolog/log" | ||
| ) | ||
|
|
||
| //go:embed bin/containerd/bin/containerd-shim-runc-v2 | ||
| var containerdShimBinary []byte | ||
|
|
||
| // containerd-shim-wasmtime-v1 is not available for arm32 | ||
| var wasmShimBinary []byte | ||
|
|
||
| //go:embed bin/runc | ||
| var runcBinary []byte | ||
|
|
||
| //go:embed bin/cni/bridge | ||
| var cniPluginBridge []byte | ||
|
|
||
| //go:embed bin/cni/host-local | ||
| var cniPluginHostLocal []byte | ||
|
|
||
| //go:embed bin/cni/portmap | ||
| var cniPluginPortmap []byte | ||
|
|
||
| //go:embed bin/cni/loopback | ||
| var cniPluginLoopback []byte | ||
|
|
||
| //go:embed bin/images/coredns.tar.gz | ||
| var corednsImageFile []byte | ||
|
|
||
| //go:embed bin/images/portainer-agent.tar.gz | ||
| var portainerAgentImageFile []byte | ||
|
|
||
| //go:embed bin/images/local-path-provisioner.tar.gz | ||
| var localPathProvisionerImageFile []byte | ||
|
|
||
| //go:embed bin/images/pause.tar.gz | ||
| var sandboxImageFile []byte | ||
|
|
||
| // EnsureEmbeddedDependencies ensures all required components are available | ||
| // it loads the containerd components, cni plugins, cni config, images, and kernel modules | ||
| // before the kubesolo application starts | ||
| func EnsureEmbeddedDependencies(embedded types.Embedded) error { | ||
| if err := loadContainerdComponents(embedded); err != nil { | ||
| return fmt.Errorf("failed to load containerd: %v", err) | ||
| } | ||
|
|
||
| if err := loadCNIPlugins(embedded.ContainerdCNIDir, embedded.ContainerdCNIPluginsDir); err != nil { | ||
| return fmt.Errorf("failed to load cni plugins: %v", err) | ||
| } | ||
|
|
||
| if err := loadCNIConfig(embedded.ContainerdCNIConfigDir, embedded.ContainerdCNIConfigFile); err != nil { | ||
| return fmt.Errorf("failed to load cni config: %v", err) | ||
| } | ||
|
|
||
| if err := loadImages(embedded.ContainerdImagesDir); err != nil { | ||
| return fmt.Errorf("failed to load images: %v", err) | ||
| } | ||
|
|
||
| if err := loadKernelModules(); err != nil { | ||
| log.Warn().Str("component", "embedded").Msgf("failed to load kernel modules: %v", err) | ||
| } | ||
|
|
||
| return nil | ||
| } |
| Original file line number | Diff line number | Diff line change | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,46 @@ | ||||||||||||||
| package runtimeclass | ||||||||||||||
|
|
||||||||||||||
| import ( | ||||||||||||||
| "context" | ||||||||||||||
| "fmt" | ||||||||||||||
| "time" | ||||||||||||||
|
|
||||||||||||||
| kubesolokubernetes "github.com/portainer/kubesolo/internal/kubernetes" | ||||||||||||||
| "github.com/portainer/kubesolo/types" | ||||||||||||||
| "github.com/rs/zerolog/log" | ||||||||||||||
| nodeapi "k8s.io/api/node/v1" | ||||||||||||||
| k8serrors "k8s.io/apimachinery/pkg/api/errors" | ||||||||||||||
| metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||||||||||||||
| ) | ||||||||||||||
|
|
||||||||||||||
| // Deploy creates the wasmtime RuntimeClass resource in the cluster | ||||||||||||||
| func Deploy(ctx context.Context, adminKubeconfig string) error { | ||||||||||||||
| time.Sleep(types.DefaultComponentSleep) | ||||||||||||||
|
||||||||||||||
| time.Sleep(types.DefaultComponentSleep) | |
| select { | |
| case <-ctx.Done(): | |
| return ctx.Err() | |
| case <-time.After(types.DefaultComponentSleep): | |
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -41,6 +41,41 @@ func (s *service) writeContainerdConfigFile() error { | |
| return nil | ||
| } | ||
|
|
||
| // generateContainerdRuntimes builds the runtimes map for the CRI runtime plugin. | ||
| // The runc runtime is always present; wasmtime is added only when WASM support | ||
| // is enabled via s.enableWasm. | ||
| func (s *service) generateContainerdRuntimes() map[string]any { | ||
| runtimes := map[string]any{ | ||
| "runc": map[string]any{ | ||
| "runtime_type": "io.containerd.runc.v2", | ||
| "runtime_path": s.containerdShimBinaryFile, | ||
| "pod_annotations": []string{}, | ||
| "container_annotations": []string{}, | ||
| "privileged_without_host_devices": false, | ||
| "privileged_without_host_devices_all_devices_allowed": false, | ||
| "base_runtime_spec": "", | ||
| "cni_conf_dir": "", | ||
| "cni_max_conf_num": 0, | ||
| "snapshotter": "", | ||
| "sandboxer": "podsandbox", | ||
| "io_type": "", | ||
| "options": map[string]any{ | ||
| "BinaryName": s.runcBinaryFile, | ||
| "SystemdCgroup": isCgroupV2(), | ||
| }, | ||
| }, | ||
| } | ||
|
|
||
| if s.enableWasm { | ||
| runtimes["wasmtime"] = map[string]any{ | ||
| "runtime_type": "io.containerd.wasmtime.v1", | ||
| "runtime_path": s.wasmShimBinaryFile, | ||
| } | ||
| } | ||
|
Comment on lines
+69
to
+74
|
||
|
|
||
| return runtimes | ||
| } | ||
|
|
||
| // generateConfig generates the containerd config | ||
| func (s *service) generateContainerdConfig() map[string]any { | ||
| return map[string]any{ | ||
|
|
@@ -101,26 +136,7 @@ func (s *service) generateContainerdConfig() map[string]any { | |
| "default_runtime_name": "runc", | ||
| "ignore_blockio_not_enabled_errors": false, | ||
| "ignore_rdt_not_enabled_errors": false, | ||
| "runtimes": map[string]any{ | ||
| "runc": map[string]any{ | ||
| "runtime_type": "io.containerd.runc.v2", | ||
| "runtime_path": s.containerdShimBinaryFile, | ||
| "pod_annotations": []string{}, | ||
| "container_annotations": []string{}, | ||
| "privileged_without_host_devices": false, | ||
| "privileged_without_host_devices_all_devices_allowed": false, | ||
| "base_runtime_spec": "", | ||
| "cni_conf_dir": "", | ||
| "cni_max_conf_num": 0, | ||
| "snapshotter": "", | ||
| "sandboxer": "podsandbox", | ||
| "io_type": "", | ||
| "options": map[string]any{ | ||
| "BinaryName": s.runcBinaryFile, | ||
| "SystemdCgroup": isCgroupV2(), | ||
| }, | ||
| }, | ||
| }, | ||
| "runtimes": s.generateContainerdRuntimes(), | ||
| }, | ||
| "cni": map[string]any{ | ||
| "bin_dir": s.containerdCNIPluginsDir, | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When
embedded.EnableWasmis true butwasmShimBinaryis empty (e.g. on riscv64 where it’s intentionally unavailable), this silently skips extraction and continues. Containerd will still be configured with the wasmtime runtime, leading to a missing-binary failure later. Consider returning an explicit error whenEnableWasmis requested but the shim binary isn’t available, or force-disable WASM support in this case so the system boots predictably.