Skip to content

feat: add ARM (aarch64) platform support - #94

Open
liunianxuxie wants to merge 17 commits into
kvcache-ai:mainfrom
liunianxuxie:feat/arm-support
Open

feat: add ARM (aarch64) platform support#94
liunianxuxie wants to merge 17 commits into
kvcache-ai:mainfrom
liunianxuxie:feat/arm-support

Conversation

@liunianxuxie

@liunianxuxie liunianxuxie commented Jul 31, 2026

Copy link
Copy Markdown

What

Add ARM (aarch64) platform support for AgentENV, enabling source-build installation on ARM servers including AWS Graviton, Ampere Altra, and Kunpeng (openEuler).

Why

AgentENV currently only supports x86_64. ARM servers are increasingly common in cloud and enterprise deployments, and openEuler is widely used on Kunpeng hardware. This PR makes AgentENV installable from source on aarch64.

Related issue

Closes #63

Scope and non-goals

Included:

  • Architecture-aware dependency resolution: Firecracker and guest kernel use {arch} URL templates pointing to kvcache-ai/firecracker (provides both x86_64 and aarch64 binaries)
  • openEuler Linux distro recognition (src/setup/packages.rs + src/setup/overlaybd.rs)
  • tools-image/Dockerfile fixes for ARM Docker builds (APT/GOPROXY mirrors, busybox extraction, platform resolution)
  • Makefile dynamic target triple detection (uname -m → Cargo runner env var)
  • ARM quickstart documentation

Excluded:

  • Pre-built ARM server binaries (CI release pipeline for aarch64)
  • Multi-arch Docker image publishing
  • ublk host kernel module on openEuler (requires host kernel rebuild; documented as optional)

Design and behavior changes

  • deps_manifest.toml: Firecracker and kernel now use kvcache-ai/firecracker releases with {arch} in the URL template instead of R2. Same URL serves both architectures.
  • src/setup/deps.rs: added {arch} placeholder to kernel URL resolution. No structural changes to dependency download logic.
  • Config default behavior unchanged. x86_64 existing deployments are unaffected.
  • ublk is enabled by default on all architectures. openEuler users who haven't rebuilt their host kernel should set [ublk].enabled = false.

Compatibility and operations

  • Public API or generated protocol: N/A (no API changes)
  • Configuration or defaults: N/A (default config unchanged)
  • Snapshot manifest, artifact layout, or storage format: N/A
  • Upgrade and rollback: N/A (source-build only for ARM; x86_64 unchanged)
  • Host requirements, permissions, ports, or dependencies: ARM hosts need KVM (/dev/kvm). Docker with Buildx for tools.ext4 compilation. openEuler additionally needs dpkg.

Validation

  • make fmt
  • make clippy
  • make test-unit (not run — no ARM CI runner available)
  • Relevant Rust integration tests (not run — no ARM CI runner available)
  • make -C services test (N/A — no services/ changes)
  • Generated clients/server regenerated (N/A — no API changes)
  • Documentation updated
  • Benchmarks or performance comparison completed (N/A)

Commands and results:

image image

Risks and reviewer notes

  • This PR changes Firecracker/kernel download URLs from R2 to kvcache-ai/firecracker. Both x86_64 and aarch64 binaries are available at the new location. The PR feat: add ARM64 support for AgentENV #86 branch uses the same source.
  • The tools-image/Dockerfile changes (APT/GOPROXY mirrors, platform fixes) are backwards-compatible for x86_64 builds.
  • openEuler distro detection in packages.rs maps to the existing CentOS/RPM-family package list. No new packages are required beyond what CentOS already uses.

liunianxuxie and others added 16 commits July 29, 2026 15:30
…support

Add per-architecture overrides in deps_manifest.toml so Firecracker and
kernel dependencies can use different versions and download URLs on ARM
platforms without changing the x86_64 defaults.

- Firecracker: ARM uses official GitHub release (v1.15.1) while x86_64
  continues using the R2-hosted patched version (1.15.1-patch-v1).
- Kernel: ARM uses a separate vmlinux-6.1.175-arm64 artifact. The
  actual ARM kernel must be compiled and provided separately because
  the R2 bucket does not currently carry an aarch64 kernel.
- deps.rs: both ensure_firecracker() and ensure_kernel() now check
  for arch-specific manifest overrides before falling back to defaults.
- cfg.rs: ManifestDownload gains version_for_host_arch() so resolved
  paths stay consistent with the arch-aware download logic.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
openEuler (ID=openEuler or ID=openeuler in /etc/os-release) is a
glibc-based RPM-family distribution. Like centos/rhel/tencentos, it
falls back to the Ubuntu 22.04 overlaybd package which bundles its
own shared libraries.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…86_64

The CAPABILITY_RUNNER was hardcoded to
CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_RUNNER, which prevented the
custom test runner from being applied on aarch64 hosts. Now it is
computed dynamically: uname -m → triple → uppercased env var.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Dockerfile.agentenv now accepts an optional pre-built kernel via
  deploy/docker/kernel/vmlinux.bin for aarch64 builds where the R2
  kernel download is not available.
- When the kernel file is present, it is placed at the expected path
  so --setup-only skips the download. When absent (x86_64), behavior
  is unchanged.
- Gateway and scheduler Dockerfiles are already ARM-ready via
  CGO_ENABLED=0 cross-compilation and multi-arch base images.

ARM build procedure:
  1. cp arch/arm64/boot/Image deploy/docker/kernel/vmlinux.bin
  2. docker build --platform linux/arm64 -f deploy/docker/Dockerfile.agentenv .

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…roach

Switch Firecracker and kernel sources from R2/GitHub-official to
kvcache-ai/firecracker fork which provides both x86_64 and aarch64
binaries from a single URL template. This eliminates the need for
per-architecture manifest overrides and removes the Docker kernel
injection mechanism.

Key changes:
- deps_manifest.toml: use kvcache-ai/firecracker for both Firecracker
  and kernel, leveraging {arch} in the URL template.
- deps.rs + cfg.rs: remove arch-override HashMap/struct/helper, back
  to simple version resolution.
- Dockerfile.agentenv: remove kernel injection (no longer needed since
  kvcache-ai/firecracker provides ARM kernel binaries).

Our unique additions beyond PR kvcache-ai#86:
- Makefile: dynamic target triple detection for capability runner
- overlaybd.rs: openEuler in RPM-family OS fallback list

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The deb.debian.org source times out during ARM Docker builds in
certain network environments. Switch to mirrors.aliyun.com before
apt-get in both envd-builder and ext4-builder stages.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
proxy.golang.org is unreachable in certain network environments.
Set GOPROXY to https://goproxy.cn for the envd go build step.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
TARGETPLATFORM was not resolving correctly to linux/arm64, causing
busybox to be pulled as amd64 and failing with exec format error.
Use BUILDPLATFORM (like envd-builder and ext4-builder stages) so
the image architecture matches the build host.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
busybox:1.37.0-musl does not have an arm64 manifest, causing exec
format error on ARM builds. Switch to busybox:1.37.0 (glibc) which
has full multi-arch support including linux/arm64.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Both busybox:1.37.0 and alpine:3.21 fail with 'exec format error' at
container init on this ARM host, while golang and debian stages work.
Switch rootfs base to debian:bookworm-slim with busybox installed via
apt to match the working ext4-builder environment.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The busybox image cannot exec /bin/sh on this ARM host, but its
layers contain a valid arm64 busybox with runsv+svlogd. Use a
dedicated FROM stage to pull the image, then COPY --from to extract
the binary into the debian-based rootfs stage which CAN execute.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The detect_distro function in packages.rs did not recognize openEuler,
causing --setup-only to fail with 'unsupported Linux distribution'.
Map openeuler/openEuler to the CentOS distro variant (RPM family).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Covers source-build installation on ARM servers including:
- Ubuntu/Debian and openEuler/CentOS/RHEL dependencies
- ARM tools drive compilation
- Configuration for ARM (ublk disable, MMIO boot args)
- Offline dependency installation
- Common troubleshooting

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Mention aarch64 in prerequisites
- Add Option C for ARM source build in Quick Start
- Link to ARM Quick Start guide in deployment section

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

🔍 OpenCodeReview found 2 issue(s) in this PR.

  • ✅ Successfully posted inline: 2 comment(s)

Comment thread src/setup/deps.rs
Comment on lines +153 to +156
let kernel_url = resolve_url(
kernel_url_template,
&[("version", kernel_version), ("arch", arch)],
);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[bug · medium]
The downloaded kernel is now architecture-specific, but resolved_kernel_image_path() still caches it under kernel/<version>/vmlinux.bin, and the preceding existence check reuses that file unconditionally. If the same dependency directory is reused by x86_64 and aarch64 setups (for example, a shared cache), the second setup will silently use the kernel for the wrong architecture. Include arch in the managed kernel cache path (or otherwise record and validate the cached artifact's architecture) before accepting the existing file.

Comment thread tools-image/Dockerfile Outdated
# BUSYBOX_IMAGE BusyBox image copied into the guest tools rootfs.

ARG BUSYBOX_IMAGE=busybox:1.37.0-musl
ARG BUSYBOX_IMAGE=busybox:1.37.0

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[maintainability · medium]
BUSYBOX_IMAGE remains documented as an overridable build argument, but the new extraction stage hard-codes busybox:1.37.0-musl, so supplying --build-arg BUSYBOX_IMAGE=... silently has no effect. Reference this argument in the busybox-bin stage (and keep its default aligned with the required musl variant) or remove the advertised argument.

Comment thread tools-image/Dockerfile Outdated
# Extract the full busybox binary (with runsv + svlogd) from the official
# multi-arch image. We cannot RUN inside this image on this host (exec format
# error), but COPY --from works because it only reads image layers.
FROM --platform=$BUILDPLATFORM busybox:1.37.0-musl AS busybox-bin

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[bug · high]
This selects the BusyBox binary for the builder host, not for the guest target. During an amd64→arm64 (or arm64→amd64) build, envd is compiled for TARGETARCH, but the tools drive receives a host-architecture BusyBox; the build-time --list checks pass precisely because it is host-native, while /init will later fail to execute it in the guest. The extraction stage must select TARGETPLATFORM (and the validation approach must not rely on running a target binary without emulation).

Suggestion:

Suggested change
FROM --platform=$BUILDPLATFORM busybox:1.37.0-musl AS busybox-bin
FROM --platform=${TARGETPLATFORM} ${BUSYBOX_IMAGE} AS busybox-bin

- Include arch in resolved_kernel_image_path() to prevent wrong-arch
  kernel reuse when deps are shared across architectures.
- Reference ${BUSYBOX_IMAGE} in busybox-bin FROM stage so the build
  arg takes effect instead of being silently ignored.
- Use TARGETPLATFORM instead of BUILDPLATFORM for busybox-bin so the
  guest binary matches the target architecture during cross-compilation.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Comment thread src/cfg.rs
Comment on lines +567 to 568
.join(arch)
.join("vmlinux.bin")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[test · medium]
This changes the managed kernel path to include the architecture, but the existing managed_dependency_paths_remain_implicit_and_resolve_from_deps_path test in this file still expects kernel/kernel-test/vmlinux.bin. The test will now fail on every supported host. Update its expected path to include std::env::consts::ARCH (and ideally add coverage confirming the architecture-specific layout).

Comment thread tools-image/Dockerfile
# because it only reads image layers.
FROM --platform=${TARGETPLATFORM} ${BUSYBOX_IMAGE} AS busybox-bin

FROM --platform=$BUILDPLATFORM debian:${DEBIAN_VERSION}-slim AS rootfs

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[bug · high]
This makes the rootfs stage use the host architecture while /usr/local/bin/busybox-full is copied for TARGETPLATFORM. Later, the stage executes that target binary with busybox --list, so a cross-platform build (for example, arm64 on amd64) fails with exec format error. Keep this stage on ${TARGETPLATFORM} so BuildKit can apply target-platform emulation, or avoid executing the copied target binary in a build-platform stage and validate its applets by another architecture-independent mechanism.

Suggestion:

Suggested change
FROM --platform=$BUILDPLATFORM debian:${DEBIAN_VERSION}-slim AS rootfs
FROM --platform=${TARGETPLATFORM} debian:${DEBIAN_VERSION}-slim AS rootfs

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Failed to build template on Arm64 server.

1 participant