From 147a9dfc1a1188ded6b11af07c752c3761f03dd6 Mon Sep 17 00:00:00 2001 From: kastakhov <16296930+kastakhov@users.noreply.github.com> Date: Thu, 10 Sep 2026 10:59:32 +0000 Subject: [PATCH 1/2] feat: add urunc container runtime extension Package urunc, its containerd shim, and monitor binaries, and register the urunc runtime handler. Apply an upstream patch that uses the container DNS configuration for guests. Add usage and configuration documentation. Remove the duplicated PUSH=true build argument. Signed-off-by: kastakhov <16296930+kastakhov@users.noreply.github.com> --- Makefile | 2 +- README.md | 3 +- container-runtime/urunc/10-urunc.part | 4 + container-runtime/urunc/README.md | 54 +++ container-runtime/urunc/manifest.yaml.tmpl | 10 + .../0001-use-oci-resolver-for-unikraft.patch | 325 ++++++++++++++++++ container-runtime/urunc/pkg.yaml | 94 +++++ container-runtime/urunc/vars.yaml | 2 + container-runtime/vars.yaml | 10 + 9 files changed, 502 insertions(+), 2 deletions(-) create mode 100644 container-runtime/urunc/10-urunc.part create mode 100644 container-runtime/urunc/README.md create mode 100644 container-runtime/urunc/manifest.yaml.tmpl create mode 100644 container-runtime/urunc/patches/0001-use-oci-resolver-for-unikraft.patch create mode 100644 container-runtime/urunc/pkg.yaml create mode 100644 container-runtime/urunc/vars.yaml diff --git a/Makefile b/Makefile index 3e0670d9..1a3eb391 100644 --- a/Makefile +++ b/Makefile @@ -143,6 +143,7 @@ TARGETS += thunderbolt TARGETS += trident-iscsi-tools TARGETS += uhid TARGETS += uinput +TARGETS += urunc TARGETS += usb-modem-drivers TARGETS += usb-audio-drivers TARGETS += util-linux-tools @@ -357,4 +358,3 @@ renovate-local: ## runs renovate locally to check syntax and test configuration -e RENOVATE_PLATFORM=local \ -e RENOVATE_DRY_RUN=full \ renovate/renovate - diff --git a/README.md b/README.md index 8a20caf8..16d76701 100644 --- a/README.md +++ b/README.md @@ -71,6 +71,7 @@ tiers based on support level: | [soci-snapshotter](container-runtime/soci-snapshotter) | :yellow_square: extra | [ghcr.io/siderolabs/soci-snapshotter](https://github.com/siderolabs/extensions/pkgs/container/soci-snapshotter) | `v0.15.0` | This system extension provides AWS SOCI Snapshotter using containerd's runtime handler. | | [spin](container-runtime/spin) | :yellow_square: extra | [ghcr.io/siderolabs/spin](https://github.com/siderolabs/extensions/pkgs/container/spin) | `v0.25.1` | This system extension provides support for spin runtime (WebAssembly) containers. | | [stargz-snapshotter](container-runtime/stargz-snapshotter) | :green_square: core | [ghcr.io/siderolabs/stargz-snapshotter](https://github.com/siderolabs/extensions/pkgs/container/stargz-snapshotter) | `v0.18.2` | This system extension provides Stargz Snapshotter using containerd's runtime handler. | +| [urunc](container-runtime/urunc) | :yellow_square: extra | [ghcr.io/siderolabs/urunc](https://github.com/siderolabs/extensions/pkgs/container/urunc) | `0.8.0` | This system extension provides urunc using containerd's runtime handler. | | [wasmedge](container-runtime/wasmedge) | :yellow_square: extra | [ghcr.io/siderolabs/wasmedge](https://github.com/siderolabs/extensions/pkgs/container/wasmedge) | `v0.6.1` | This system extension provides support for WasmEdge runtime (WebAssembly) containers. | | [youki](container-runtime/youki) | :white_large_square: contrib | [ghcr.io/siderolabs/youki](https://github.com/siderolabs/extensions/pkgs/container/youki) | `0.7.0` | This system extension provides youki using containerd's runtime handler. | @@ -233,7 +234,7 @@ The rough flow should look like the following: To build and push an extension to a local registry use: ```bash -make PUSH=true REGISTRY=127.0.0.1:5005 USERNAME= PUSH=true +make PUSH=true REGISTRY=127.0.0.1:5005 USERNAME= ``` Instructions on how to set up the builder can be found [here](https://docs.siderolabs.com/talos/latest/build-and-extend-talos/custom-images-and-development/developing-talos#prepare) diff --git a/container-runtime/urunc/10-urunc.part b/container-runtime/urunc/10-urunc.part new file mode 100644 index 00000000..affbe538 --- /dev/null +++ b/container-runtime/urunc/10-urunc.part @@ -0,0 +1,4 @@ +[plugins."io.containerd.cri.v1.runtime".containerd.runtimes.urunc] + runtime_type = "io.containerd.urunc.v2" + container_annotations = ["com.urunc.unikernel.*"] + pod_annotations = ["com.urunc.unikernel.*"] diff --git a/container-runtime/urunc/README.md b/container-runtime/urunc/README.md new file mode 100644 index 00000000..b03c5d7d --- /dev/null +++ b/container-runtime/urunc/README.md @@ -0,0 +1,54 @@ +# urunc extension + +## Installation + +See [Installing Extensions](https://github.com/siderolabs/extensions#installing-extensions). + +## Usage + +This extension installs `urunc`, `containerd-shim-urunc-v2`, the monitor binaries, and a containerd runtime handler named `urunc`. + +Apply the following manifest to add the runtime class: + +```yaml +apiVersion: node.k8s.io/v1 +kind: RuntimeClass +metadata: + name: urunc +handler: urunc +``` + +## Configuration + +Create the configuration under `/var` with a Talos machine configuration patch, then set `URUNC_CONFIG_FILE` so both `urunc` and its containerd shim use it: + +```yaml +machine: + files: + - path: /var/etc/urunc/config.toml + op: create + content: | + [log] + level = "info" + syslog = false + + [extra_binaries.virtiofsd] + path = "/usr/local/bin/virtiofsd" + options = "--cache always --sandbox none" +--- +apiVersion: v1alpha1 +kind: EnvironmentConfig +variables: + URUNC_CONFIG_FILE: /var/etc/urunc/config.toml +``` + +Talos restricts user-created machine files to `/var`, while urunc defaults to `/etc/urunc/config.toml`. +The patch writes the file to the allowed location and overrides the default path; otherwise urunc logs a warning and uses defaults. + +The extension installs monitor binaries under `/usr/local/bin`; set their paths in the TOML when overriding monitor configuration. +A complete example is available in the upstream [`config.toml`](https://github.com/urunc-dev/urunc/blob/v0.8.0/deployment/urunc-deploy/config.toml). + +## Downstream patch + +The extension applies one patch to urunc v0.8.0. It reads the nameserver from the container's OCI-mounted `/etc/resolv.conf` and passes it to Unikraft. +This allows Kubernetes service DNS to work inside the guest instead of always using the hard-coded `8.8.8.8` fallback. diff --git a/container-runtime/urunc/manifest.yaml.tmpl b/container-runtime/urunc/manifest.yaml.tmpl new file mode 100644 index 00000000..bd681747 --- /dev/null +++ b/container-runtime/urunc/manifest.yaml.tmpl @@ -0,0 +1,10 @@ +version: v1alpha1 +metadata: + name: urunc + version: "{{ .VERSION }}" + author: Nubificus LTD + description: | + [{{ .TIER }}] This system extension provides urunc using containerd's runtime handler. + compatibility: + talos: + version: ">= v1.13.0" diff --git a/container-runtime/urunc/patches/0001-use-oci-resolver-for-unikraft.patch b/container-runtime/urunc/patches/0001-use-oci-resolver-for-unikraft.patch new file mode 100644 index 00000000..041a408e --- /dev/null +++ b/container-runtime/urunc/patches/0001-use-oci-resolver-for-unikraft.patch @@ -0,0 +1,325 @@ +From bd994aef47959bec3bc3290359d373cba24e548a Mon Sep 17 00:00:00 2001 +From: Ali Mohamed +Date: Thu, 3 Sep 2026 10:11:20 +0300 +Subject: [PATCH] fix(unikraft): set the guest DNS server from the container's + resolv.conf + +Unikraft guests used a hardcoded DNS server, so name resolution inside +the unikernel ignored the DNS configuration of the container. Parse the +nameserver entry from the container's resolv.conf and pass it to the +guest through the kernel command line. + +PR: https://github.com/urunc-dev/urunc/pull/966 +Signed-off-by: Ali Mohamed +Signed-off-by: Charalampos Mainas +Reviewed-by: Charalampos Mainas +Approved-by: Charalampos Mainas +--- + .github/contributors.yaml | 3 + + .github/linters/urunc-dict.txt | 3 + + pkg/unikontainers/monitor.go | 2 + + pkg/unikontainers/monitor_spec.go | 1 + + pkg/unikontainers/types/types.go | 13 ++-- + pkg/unikontainers/unikernels/unikraft.go | 12 +++- + pkg/unikontainers/unikontainers.go | 6 ++ + pkg/unikontainers/utils.go | 34 +++++++++++ + pkg/unikontainers/utils_test.go | 77 ++++++++++++++++++++++++ + tests/e2e/test_cases.go | 17 ++++++ + 10 files changed, 159 insertions(+), 9 deletions(-) + +diff --git a/.github/contributors.yaml b/.github/contributors.yaml +index 19e35c4af..95943b29e 100644 +--- a/.github/contributors.yaml ++++ b/.github/contributors.yaml +@@ -143,3 +143,6 @@ users: + r0binak: + name: Sergey Kanibor + email: r081n4k@gmail.com ++ alimx07: ++ name: Ali Mohamed ++ email: amx746@gmail.com +diff --git a/.github/linters/urunc-dict.txt b/.github/linters/urunc-dict.txt +index 12a9510e3..68b898334 100644 +--- a/.github/linters/urunc-dict.txt ++++ b/.github/linters/urunc-dict.txt +@@ -449,3 +449,6 @@ bhyve + GHSA + crxr + hmpj ++ndots ++resolv ++dupword +diff --git a/pkg/unikontainers/monitor.go b/pkg/unikontainers/monitor.go +index 5cef0fbc4..aaaa48e75 100644 +--- a/pkg/unikontainers/monitor.go ++++ b/pkg/unikontainers/monitor.go +@@ -87,6 +87,8 @@ func runMonitor(metrics m.Writer, ms monitorSpec) error { + return fmt.Errorf("failed to setup network: %w", err) + } + metrics.Capture(m.TS16) ++ // SetupNet does not resolve DNS; carry the server resolved at spec build. ++ netArgs.DNSServer = ms.DNSServer + ms.ExecArgs.Net = netArgs + ms.GuestParams.Net = netArgs + +diff --git a/pkg/unikontainers/monitor_spec.go b/pkg/unikontainers/monitor_spec.go +index 7344a59ce..d45b04264 100644 +--- a/pkg/unikontainers/monitor_spec.go ++++ b/pkg/unikontainers/monitor_spec.go +@@ -41,6 +41,7 @@ type monitorSpec struct { + ExecArgs types.ExecArgs `json:"execArgs"` + GuestParams types.UnikernelParams `json:"guestParams"` + NetworkType string `json:"networkType"` ++ DNSServer string `json:"dnsServer,omitempty"` + User specs.User `json:"user"` + PreStartCmd []string `json:"preStartCmd,omitempty"` + } +diff --git a/pkg/unikontainers/types/types.go b/pkg/unikontainers/types/types.go +index b80b1fbbe..a3d630416 100644 +--- a/pkg/unikontainers/types/types.go ++++ b/pkg/unikontainers/types/types.go +@@ -45,12 +45,13 @@ type VMM interface { + } + + type NetDevParams struct { +- IP string // The veth device IP +- Mask string // The veth device mask +- Gateway string // The veth device gateway +- MAC string // The MAC address of the guest network device +- TapDev string // The tap device name +- MTU int // The MTU value of the tap device ++ IP string // The veth device IP ++ Mask string // The veth device mask ++ Gateway string // The veth device gateway ++ MAC string // The MAC address of the guest network device ++ TapDev string // The tap device name ++ MTU int // The MTU value of the tap device ++ DNSServer string // The nameserver of the container, empty if there is none + } + + type BlockDevParams struct { +diff --git a/pkg/unikontainers/unikernels/unikraft.go b/pkg/unikontainers/unikernels/unikraft.go +index 6b3c9bdeb..00f915d93 100644 +--- a/pkg/unikontainers/unikernels/unikraft.go ++++ b/pkg/unikontainers/unikernels/unikraft.go +@@ -27,6 +27,8 @@ import ( + const UnikraftUnikernel string = "unikraft" + const UnikraftCompatVersion string = "0.16.1" + ++const defaultDNSServer string = "8.8.8.8" ++ + var ErrUndefinedVersion = errors.New("version is undefined, using default version") + var ErrVersionParsing = errors.New("failed to parse provided version, using default version") + +@@ -107,10 +109,14 @@ func (u *Unikraft) Init(data types.UnikernelParams) error { + u.Monitor = data.Monitor + u.Command = strings.Join(data.CmdLine, " ") + +- return u.configureUnikraftArgs(data.Rootfs.Type, data.Net.IP, data.Net.Gateway, data.Net.Mask) ++ return u.configureUnikraftArgs(data.Rootfs.Type, data.Net.IP, data.Net.Gateway, data.Net.Mask, data.Net.DNSServer) + } + +-func (u *Unikraft) configureUnikraftArgs(rootFsType, ethDeviceIP, ethDeviceGateway, ethDeviceMask string) error { ++func (u *Unikraft) configureUnikraftArgs(rootFsType, ethDeviceIP, ethDeviceGateway, ethDeviceMask, dnsServer string) error { ++ if dnsServer == "" { ++ dnsServer = defaultDNSServer ++ } ++ + setCompatArgs := func() { + u.Net.Address = "netdev.ipv4_addr=" + ethDeviceIP + u.Net.Gateway = "netdev.ipv4_gw_addr=" + ethDeviceGateway +@@ -125,7 +131,7 @@ func (u *Unikraft) configureUnikraftArgs(rootFsType, ethDeviceIP, ethDeviceGatew + } + + setCurrentArgs := func() { +- u.Net.Address = "netdev.ip=" + ethDeviceIP + "/24:" + ethDeviceGateway + ":8.8.8.8" ++ u.Net.Address = "netdev.ip=" + ethDeviceIP + "/24:" + ethDeviceGateway + ":" + dnsServer + switch rootFsType { + case "initrd": + // TODO: This needs better handling. We need to revisit this +diff --git a/pkg/unikontainers/unikontainers.go b/pkg/unikontainers/unikontainers.go +index 910358db3..8c101ed19 100644 +--- a/pkg/unikontainers/unikontainers.go ++++ b/pkg/unikontainers/unikontainers.go +@@ -552,6 +552,10 @@ func (u *Unikontainer) buildMonitorSpec(rootfsParams types.RootfsParams, monRes + mSpec.ExecArgs = vmmArgs + mSpec.GuestParams = guest + mSpec.PreStartCmd = monRes.PreStartCmd ++ // Resolve the guest DNS server once, here in the builder shared by both the ++ // libcontainer and non-libcontainer paths, where the container mount ++ // sources are available. ++ mSpec.DNSServer = getDNSServer(u.Spec.Mounts) + + return mSpec + } +@@ -638,6 +642,8 @@ func (u *Unikontainer) Exec(metrics m.Writer) error { + } + metrics.Capture(m.TS16) + withTUNTAP := netArgs.IP != "" ++ // SetupNet does not resolve DNS; carry the server resolved at spec build. ++ netArgs.DNSServer = ms.DNSServer + unikernelParams.Net = netArgs + vmmArgs.Net = netArgs + +diff --git a/pkg/unikontainers/utils.go b/pkg/unikontainers/utils.go +index 6fcf4b5fd..a2f1d1bb6 100644 +--- a/pkg/unikontainers/utils.go ++++ b/pkg/unikontainers/utils.go +@@ -20,6 +20,7 @@ import ( + "encoding/json" + "fmt" + "io" ++ "net" + "os" + "os/exec" + "path/filepath" +@@ -375,3 +376,36 @@ func executeHook(hook specs.Hook, state []byte) error { + + return nil + } ++ ++func getDNSServer(mounts []specs.Mount) string { ++ resolvConf := "" ++ for _, mount := range mounts { ++ if filepath.Clean(mount.Destination) == "/etc/resolv.conf" { ++ resolvConf = mount.Source ++ break ++ } ++ } ++ if resolvConf == "" { ++ return "" ++ } ++ ++ data, err := os.ReadFile(resolvConf) ++ if err != nil { ++ uniklog.Warnf("Failed to read %s: %v", resolvConf, err) ++ return "" ++ } ++ ++ for _, line := range strings.Split(string(data), "\n") { ++ fields := strings.Fields(line) ++ if len(fields) < 2 || fields[0] != "nameserver" { ++ continue ++ } ++ addr := net.ParseIP(fields[1]) ++ if addr != nil && addr.To4() != nil && !addr.IsLoopback() { ++ return addr.String() ++ } ++ } ++ ++ uniklog.Warnf("no usable IPv4 nameserver found in %s; the guest will use the default DNS server", resolvConf) ++ return "" ++} +diff --git a/pkg/unikontainers/utils_test.go b/pkg/unikontainers/utils_test.go +index c335aca4f..3e8d57c0a 100644 +--- a/pkg/unikontainers/utils_test.go ++++ b/pkg/unikontainers/utils_test.go +@@ -340,3 +340,80 @@ func TestLoadSpec(t *testing.T) { + assert.Contains(t, err.Error(), "failed to parse specification json", "Expected specific error message") + }) + } ++ ++func TestGetDNSServer(t *testing.T) { ++ tests := []struct { ++ name string ++ content string ++ expected string ++ }{ ++ { ++ name: "single nameserver", ++ content: "nameserver 10.96.0.10\n", ++ expected: "10.96.0.10", ++ }, ++ { ++ name: "first nameserver is used", ++ content: "search svc.cluster.local\nnameserver 10.96.0.10\nnameserver 8.8.4.4\noptions ndots:5\n", ++ expected: "10.96.0.10", ++ }, ++ { ++ name: "comments are ignored", ++ content: "# nameserver 1.1.1.1\n\n nameserver\t192.168.1.1 \n", ++ expected: "192.168.1.1", ++ }, ++ { ++ name: "loopback nameserver is skipped", ++ content: "nameserver 127.0.0.11\nnameserver 1.1.1.1\n", ++ expected: "1.1.1.1", ++ }, ++ { ++ name: "IPv6 nameserver is skipped", ++ content: "nameserver fd00::1\nnameserver 1.1.1.1\n", ++ expected: "1.1.1.1", ++ }, ++ { ++ name: "invalid entries are skipped", ++ content: "nameserver\nnameserver not-an-ip\nnameserver 1.1.1.1\n", //nolint:dupword ++ expected: "1.1.1.1", ++ }, ++ { ++ name: "no usable nameserver", ++ content: "search svc.cluster.local\nnameserver 127.0.0.53\n", ++ expected: "", ++ }, ++ } ++ ++ for _, tc := range tests { ++ t.Run(tc.name, func(t *testing.T) { ++ t.Parallel() ++ resolvConf := filepath.Join(t.TempDir(), "resolv.conf") ++ err := os.WriteFile(resolvConf, []byte(tc.content), 0600) ++ assert.NoError(t, err) ++ mounts := []specs.Mount{ ++ {Destination: "/etc/hostname", Source: "/dummy/hostname"}, ++ {Destination: "/etc/resolv.conf", Source: resolvConf}, ++ } ++ ++ assert.Equal(t, tc.expected, getDNSServer(mounts)) ++ }) ++ } ++ ++ t.Run("no resolv.conf mount", func(t *testing.T) { ++ t.Parallel() ++ mounts := []specs.Mount{ ++ {Destination: "/etc/hostname", Source: "/dummy/hostname"}, ++ } ++ ++ assert.Equal(t, "", getDNSServer(mounts)) ++ }) ++ ++ t.Run("missing resolv.conf file", func(t *testing.T) { ++ t.Parallel() ++ mounts := []specs.Mount{ ++ {Destination: "/etc/resolv.conf", Source: filepath.Join(t.TempDir(), "resolv.conf")}, ++ } ++ ++ assert.Equal(t, "", getDNSServer(mounts)) ++ }) ++} +diff --git a/tests/e2e/test_cases.go b/tests/e2e/test_cases.go +index 3b90a381e..e6b9dc8a7 100644 +--- a/tests/e2e/test_cases.go ++++ b/tests/e2e/test_cases.go +@@ -472,6 +472,23 @@ func nerdctlTestCases() []containerTestArgs { + Skippable: false, + TestFunc: pingTest, + }, ++ { ++ Image: "harbor.nbfc.io/nubificus/urunc/dns-test-qemu-unikraft-initrd:latest", ++ Name: "Qemu-unikraft-dns-external", ++ Devmapper: false, ++ Seccomp: true, ++ UID: 0, ++ GID: 0, ++ Groups: []int64{}, ++ Memory: "", ++ Cli: "", ++ Volumes: []containerVolume{}, ++ StaticNet: false, ++ SideContainers: []string{}, ++ Skippable: true, ++ ExpectOut: "github.com OK", ++ TestFunc: matchTest, ++ }, + } + } + diff --git a/container-runtime/urunc/pkg.yaml b/container-runtime/urunc/pkg.yaml new file mode 100644 index 00000000..1d24d006 --- /dev/null +++ b/container-runtime/urunc/pkg.yaml @@ -0,0 +1,94 @@ +name: urunc +variant: scratch +shell: /bin/bash +dependencies: + - stage: base +steps: + - sources: + - url: https://github.com/urunc-dev/urunc/archive/refs/tags/v{{ .URUNC_UPSTREAM_VERSION }}.tar.gz + destination: urunc-source.tar.gz + sha256: {{ .URUNC_SOURCE_SHA256 }} + sha512: {{ .URUNC_SOURCE_SHA512 }} + # {{ if eq .ARCH "aarch64" }} This in fact is YAML comment, but Go templating instruction is evaluated by bldr + - url: https://github.com/urunc-dev/monitors-build/releases/download/{{ .URUNC_MONITORS_VERSION }}/release-arm64-{{ .URUNC_MONITORS_VERSION }}.tar.gz + destination: urunc-monitors.tar.gz + sha256: {{ .URUNC_MONITORS_ARM64_SHA256 }} + sha512: {{ .URUNC_MONITORS_ARM64_SHA512 }} + # {{ else }} This in fact is YAML comment, but Go templating instruction is evaluated by bldr + - url: https://github.com/urunc-dev/monitors-build/releases/download/{{ .URUNC_MONITORS_VERSION }}/release-amd64-{{ .URUNC_MONITORS_VERSION }}.tar.gz + destination: urunc-monitors.tar.gz + sha256: {{ .URUNC_MONITORS_AMD64_SHA256 }} + sha512: {{ .URUNC_MONITORS_AMD64_SHA512 }} + # {{ end }} This in fact is YAML comment, but Go templating instruction is evaluated by bldr + env: + GOPATH: /tmp/go + cachePaths: + - /.cache/go-build + - /tmp/go/pkg + - network: default + prepare: + - | + mkdir -p ${GOPATH}/src/github.com/urunc-dev/urunc + tar -xzf urunc-source.tar.gz --strip-components=1 -C ${GOPATH}/src/github.com/urunc-dev/urunc + patch -d ${GOPATH}/src/github.com/urunc-dev/urunc -p1 < /pkg/patches/0001-use-oci-resolver-for-unikraft.patch + - | + cd ${GOPATH}/src/github.com/urunc-dev/urunc + make prepare VERSION="{{ .URUNC_VERSION }}" + - network: none + build: + - | + case "{{ .ARCH }}" in + x86_64) go_arch=amd64 ;; + aarch64) go_arch=arm64 ;; + *) echo "unsupported architecture: {{ .ARCH }}" >&2; exit 1 ;; + esac + make -C ${GOPATH}/src/github.com/urunc-dev/urunc static ARCH="${go_arch}" VERSION="{{ .URUNC_VERSION }}" + install: + - | + mkdir -p /rootfs/usr/local/bin + cp -av ${GOPATH}/src/github.com/urunc-dev/urunc/dist/urunc_static_* /rootfs/usr/local/bin/urunc + cp -av ${GOPATH}/src/github.com/urunc-dev/urunc/dist/containerd-shim-urunc-v2_static_* /rootfs/usr/local/bin/containerd-shim-urunc-v2 + chmod +x /rootfs/usr/local/bin/urunc /rootfs/usr/local/bin/containerd-shim-urunc-v2 + + - | + mkdir -p /tmp/urunc-monitors /rootfs/usr/local/bin /rootfs/usr/local/share + tar -xzf urunc-monitors.tar.gz -C /tmp/urunc-monitors + + cp -av /tmp/urunc-monitors/urunc/bin/firecracker /rootfs/usr/local/bin/firecracker + cp -av /tmp/urunc-monitors/urunc/bin/cloud-hypervisor /rootfs/usr/local/bin/cloud-hypervisor + cp -av /tmp/urunc-monitors/urunc/bin/solo5-hvt /rootfs/usr/local/bin/solo5-hvt + cp -av /tmp/urunc-monitors/urunc/bin/solo5-spt /rootfs/usr/local/bin/solo5-spt + cp -av /tmp/urunc-monitors/urunc/bin/virtiofsd /rootfs/usr/local/bin/virtiofsd + cp -av /tmp/urunc-monitors/urunc/share/qemu/qemu /rootfs/usr/local/share/qemu + + qemu_binary="$(basename /tmp/urunc-monitors/urunc/bin/qemu-system-*)" + cp -av "/tmp/urunc-monitors/urunc/bin/${qemu_binary}" "/rootfs/usr/local/bin/${qemu_binary}" + + chmod +x /rootfs/usr/local/bin/firecracker \ + /rootfs/usr/local/bin/cloud-hypervisor \ + /rootfs/usr/local/bin/solo5-hvt \ + /rootfs/usr/local/bin/solo5-spt \ + /rootfs/usr/local/bin/qemu-system-* \ + /rootfs/usr/local/bin/virtiofsd + + - | + mkdir -p /rootfs/etc/cri/conf.d + cp /pkg/10-urunc.part /rootfs/etc/cri/conf.d/10-urunc.part + test: + - | + mkdir -p /extensions-validator-rootfs + cp -r /rootfs/ /extensions-validator-rootfs/rootfs + cp /pkg/manifest.yaml /extensions-validator-rootfs/manifest.yaml + /extensions-validator validate --rootfs=/extensions-validator-rootfs --pkg-name="${PKG_NAME}" + sbom: + outputPath: /rootfs/usr/local/share/spdx/urunc.spdx.json + version: {{ .URUNC_VERSION }} + licenses: + - Apache-2.0 + - GPL-2.0 + - ISC +finalize: + - from: /rootfs + to: /rootfs + - from: /pkg/manifest.yaml + to: / diff --git a/container-runtime/urunc/vars.yaml b/container-runtime/urunc/vars.yaml new file mode 100644 index 00000000..f3873a84 --- /dev/null +++ b/container-runtime/urunc/vars.yaml @@ -0,0 +1,2 @@ +VERSION: "{{ .URUNC_VERSION }}" +TIER: "extra" diff --git a/container-runtime/vars.yaml b/container-runtime/vars.yaml index bb4174d1..5f6e4234 100644 --- a/container-runtime/vars.yaml +++ b/container-runtime/vars.yaml @@ -56,3 +56,13 @@ YOUKI_ARM64_SHA256: b96c05c2c82f1d20a74b611188fa120894c50a6128f73856bb371604ecb6 YOUKI_ARM64_SHA512: 99525a9ea4c071d9a8c7cc422bbf1a97140552d178a78cfa1d7e57ef27d2b518c9f6d30a20ce4ccd0b3914b97532e106b6232bd5a83fcb468c735885318e63ff YOUKI_AMD64_SHA256: a211a16b6b1a985f8ca61bba9a30b9ae40352d04dd7eca04cdecfe7b98b47038 YOUKI_AMD64_SHA512: 48d22651ca75be19793adac8cc62f8128fa634d35c2e2bb73c243f51bb634406e1b5399f6032d1fce297d44c2c7fb54b3bba6df66ecd1c8a031b0cb2b55d0fbf +# renovate: datasource=github-releases extractVersion=^v(?.*)$ depName=urunc-dev/urunc +URUNC_UPSTREAM_VERSION: 0.8.0 +URUNC_VERSION: 0.8.0-talos.1 +URUNC_SOURCE_SHA256: 6773f666f2ddfa5ec4b52b35a685d76063ad61e28234a78355a354240858685f +URUNC_SOURCE_SHA512: ac7b46047bb48d8799b347f2da654b69b3f091096cb6a0bcf4f3190fc68b37d062ab445dc71ae52000ca04d2dfe618ddfbd0df37e3a4d020a342becaa0ce5c0c +URUNC_MONITORS_VERSION: FC-v1.7.0_CLH-v50.0_S5-v0.12.1_VFS_-v1.13.0_QM-v10.1.1-9a44e +URUNC_MONITORS_ARM64_SHA256: 5386fdfd7397db8209260cc6ecb1d325052fd548d0b9e571f143aa2b33c47409 +URUNC_MONITORS_ARM64_SHA512: 92412c077077829cb863b13a0eecc6f85dc7272c3362bc864d90b5b25e24fc983416a6c8cfd63a509e5d7dde101aeadeccaec628029cb58305894f8ab270b9d5 +URUNC_MONITORS_AMD64_SHA256: 24ef6c1f9ae5821be070302b51eec6510bddc5e2268e2c3ad848c30c69cc7345 +URUNC_MONITORS_AMD64_SHA512: 35af11bffc0d7ea6bdac3f77d4fd167fcbdeea7e70518d109b58b2a4db40607cde98c0191266f2e4b07887ceb681c5bfa7991ccbdf71ad6973a95c6c26069ba9 From 81a6c4ed930771c8feabcb509483a44c1f53a919 Mon Sep 17 00:00:00 2001 From: kastakhov <16296930+kastakhov@users.noreply.github.com> Date: Fri, 18 Sep 2026 21:52:22 +0000 Subject: [PATCH 2/2] doc: replace machine.files with Talos 1.14 EtcFileConfig Signed-off-by: kastakhov <16296930+kastakhov@users.noreply.github.com> --- container-runtime/urunc/README.md | 32 +++++++++++++------------------ 1 file changed, 13 insertions(+), 19 deletions(-) diff --git a/container-runtime/urunc/README.md b/container-runtime/urunc/README.md index b03c5d7d..b6c3b435 100644 --- a/container-runtime/urunc/README.md +++ b/container-runtime/urunc/README.md @@ -20,30 +20,24 @@ handler: urunc ## Configuration -Create the configuration under `/var` with a Talos machine configuration patch, then set `URUNC_CONFIG_FILE` so both `urunc` and its containerd shim use it: +On Talos Linux 1.14 and later, provide `/etc/urunc/config.toml` with an [`EtcFileConfig`](https://docs.siderolabs.com/talos/v1.14/reference/configuration/runtime/etcfileconfig): ```yaml -machine: - files: - - path: /var/etc/urunc/config.toml - op: create - content: | - [log] - level = "info" - syslog = false - - [extra_binaries.virtiofsd] - path = "/usr/local/bin/virtiofsd" - options = "--cache always --sandbox none" ---- apiVersion: v1alpha1 -kind: EnvironmentConfig -variables: - URUNC_CONFIG_FILE: /var/etc/urunc/config.toml +kind: EtcFileConfig +name: urunc/config.toml +mode: 0o644 +contents: | + [log] + level = "info" + syslog = false + + [extra_binaries.virtiofsd] + path = "/usr/local/bin/virtiofsd" + options = "--cache always --sandbox none" ``` -Talos restricts user-created machine files to `/var`, while urunc defaults to `/etc/urunc/config.toml`. -The patch writes the file to the allowed location and overrides the default path; otherwise urunc logs a warning and uses defaults. +The `name` is relative to `/etc`, so the document writes the file to urunc's default configuration path without an environment override. The extension installs monitor binaries under `/usr/local/bin`; set their paths in the TOML when overriding monitor configuration. A complete example is available in the upstream [`config.toml`](https://github.com/urunc-dev/urunc/blob/v0.8.0/deployment/urunc-deploy/config.toml).