[FB:] ARM64 and Podman support verified + with fixes to make it work
Context
Tested on a Mono Gateway DK (NXP LS1046A, aarch64) running Armbian Debian Trixie + k3s v1.35.4. Found three issues blocking ARM64 deployment, all with proposed fixes. These findings demonstrate that both aarch64 and Podman support are relatively straightforward to implement.
Environment:
- Hardware: Mono Gateway DK (NXP LS1046A, 4-core aarch64, 8GB ECC RAM)
- OS: Armbian 26.2.3 Debian Trixie
- Kernel: 6.12.49-current-ls1046a-ask
- Architecture: arm64
- Kubernetes: k3s v1.35.4 (containerd 2.2.3-k3s1)
- Container runtime (host): Podman 5.4.2 aliased as
docker — no Docker daemon involved
Podman containers (WFM stack):
NAMES STATUS IMAGE
symphony-api-container Up 1 minute ghcr.io/margo/margo-symphony-api:latest
redis Up 4 minutes docker.io/library/redis:7-alpine
workload-fleet-management-client Up 1 minute localhost/workload-fleet-management-client:ci-test
k3s pods (Eclipse Symphony k8s control plane):
NAMESPACE NAME READY STATUS
symphony symphony-api-fcf9cdbb8-55t6t 1/1 Running
symphony symphony-cert-manager-77f8479489-ftzsg 1/1 Running
symphony symphony-cert-manager-cainjector-758cc94c44-5t4w7 1/1 Running
symphony symphony-cert-manager-webhook-6f4546df97-tclmc 1/1 Running
symphony symphony-redis-575fc56cc9-vr8rg 1/1 Running
symphony symphony-zipkin-5c47b4569-jfmtx 1/1 Running
Device agent onboarded and reporting capabilities:
INFO Device onboarding successful {"deviceClientId": "client-896fdc96df18bfa2-1778970065"}
INFO Capabilities reported successfully {"deviceClientId": "client-896fdc96df18bfa2-1778970065"}
INFO Workload Fleet Management Client started successfully
{"capabilitiesFile": "./config/capabilities.json",
"hasDeviceSignature": true,
"stateSeekingInterval": 15,
"sbiUrl": "https://symphony-service:8082/v1alpha2/margo"}
Symphony API responding:
$ curl http://localhost:32371/v1alpha2/greetings
Hello from Symphony K8s control plane (S8C)
The full Margo PR1 sandbox stack — WFM server, device agent, and Eclipse Symphony k8s control plane — is running on ARM64 hardware after applying the workarounds described below.
Issue 1 — Margo WFM client: no ARM64 image published to ghcr.io
docker manifest inspect ghcr.io/margo/margo.org/workload-fleet-management-client:latest shows only amd64. No ARM64 variant is published.
The .goreleaser.yaml correctly lists linux/arm64 as a build target, and the Dockerfile builds cleanly on ARM64 (tested and confirmed). The issue is that the GitHub Actions workflow never builds and pushes the ARM64 image to ghcr.io.
Fix: Add linux/arm64 to the Docker build and push step in the CI workflow.
Issue 2 — Margo WFM client: Docker hardcoded as runtime dependency
The WFM client has a hard dependency on Docker in two places:
shared-lib/workloads/dockerCliClient.go:
dockerBinary, err := exec.LookPath("docker")
if err != nil {
return nil, fmt.Errorf("docker binary not found in PATH: %w", err)
}
poc/device/agent/Dockerfile:
FROM docker:28.3.3-cli AS docker-source
...
COPY --from=docker-source /usr/local/bin/docker /usr/bin/docker
COPY --from=docker-source /usr/local/libexec/docker/cli-plugins/docker-compose /usr/local/libexec/docker/cli-plugins/docker-compose
This directly contradicts Margo's secure-by-design philosophy. Docker requires a persistent root daemon (dockerd) — a container escape on an OT edge node running EtherCAT/PROFINET gives an attacker root on the host. This is unacceptable for industrial deployments.
Podman is the correct default: rootless by default, daemonless, full Docker CLI compatibility (alias docker=podman or symlink), native pod support, OCI-native. The fix is trivial since exec.LookPath("docker") resolves whatever binary is named docker in PATH.
Proposed fix — dockerCliClient.go:
dockerBinary, err := exec.LookPath("podman")
if err != nil {
dockerBinary, err = exec.LookPath("docker")
if err != nil {
return nil, fmt.Errorf("neither podman nor docker binary found in PATH")
}
}
Proposed fix — Dockerfile:
FROM alpine:3.18
RUN apk add --no-cache ca-certificates tzdata podman podman-compose
RUN ln -s /usr/bin/podman /usr/bin/docker
RUN echo 'alias docker=podman' >> /etc/profile.d/docker-podman.sh
WORKDIR /
COPY --from=builder /app/device-agent .
COPY --from=builder /app/poc/device/agent/config ./config
VOLUME ["/config"]
ENTRYPOINT ["./device-agent"]
CMD ["-config", "config/config.yaml"]
Tested on Podman 5.4.2 with podman-compose 1.3.0 on aarch64. Both docker --version and docker compose version resolve correctly via symlink.
Issue 3 — Eclipse Symphony dependency: symphony-k8s:0.48.28 contains an amd64 binary in the ARM64 manifest
The Helm chart for Symphony (which the Margo sandbox depends on) pins symphony-k8s:0.48.28. This image has a multi-arch manifest that claims to include linux/arm64, but the actual binary inside the ARM64 layer is x86-64:
$ file manager
manager: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked...
This results in exec /manager: exec format error when the container starts on ARM64 — a silent wrong-binary-in-manifest bug.
The latest tag (built 2026-05-14) contains a correct ARM64 binary:
$ file manager
manager: ELF 64-bit LSB executable, ARM aarch64, version 1 (SYSV), statically linked...
Workaround used to get Symphony running on ARM64:
skopeo copy \
--override-arch arm64 --override-os linux \
docker://ghcr.io/eclipse-symphony/symphony-k8s:latest \
docker-archive:/tmp/symphony-k8s-arm64.tar:ghcr.io/eclipse-symphony/symphony-k8s:0.48.28
k3s ctr -n k8s.io images import /tmp/symphony-k8s-arm64.tar
Fix: Update the sandbox Helm chart to pin a version of symphony-k8s that has a correct ARM64 build, or switch to latest. This should also be reported upstream to the Eclipse Symphony project.
Summary
Workarounds needed to run on Podman (undocumented)
- Build WFM client image locally for ARM64 — no ARM64 image on ghcr.io
- Tag as
ci-test + set CI=true — bypasses the GHCR pull in the start script
- Mount Podman socket in docker-compose.yaml:
/var/run/podman/podman.sock:/var/run/docker.sock
- Install aardvark-dns — Podman's DNS component not installed by default
- Enable Podman socket —
systemctl enable --now podman.socket
- Add
symphony-service to /etc/hosts — TLS cert hostname matching
- Generate CA cert with
CA:TRUE — the sandbox cert generator has a bug (CA:FALSE), use OpenSSL directly
- Use
margo-symphony-api container instead of Helm Symphony — Helm-deployed Symphony has no Margo onboarding endpoint
- Run Redis separately —
margo-symphony-api needs it but doesn't bundle it
| # |
Component |
Issue |
Severity |
| 1 |
Margo WFM client |
No ARM64 image published to ghcr.io |
Blocker |
| 2 |
Margo WFM client |
Docker hardcoded 😞 — see related TWG discussion on replacing Docker with Podman for OT edge deployments |
Major |
| 3 |
Eclipse Symphony |
symphony-k8s:0.48.28 ARM64 manifest contains amd64 binary |
Blocker |
All three issues were found on first contact with real ARM64 hardware. Fixes are proposed for all three.
[FB:] ARM64 and Podman support verified + with fixes to make it work
Context
Tested on a Mono Gateway DK (NXP LS1046A, aarch64) running Armbian Debian Trixie + k3s v1.35.4. Found three issues blocking ARM64 deployment, all with proposed fixes. These findings demonstrate that both aarch64 and Podman support are relatively straightforward to implement.
Environment:
docker— no Docker daemon involvedPodman containers (WFM stack):
k3s pods (Eclipse Symphony k8s control plane):
Device agent onboarded and reporting capabilities:
Symphony API responding:
The full Margo PR1 sandbox stack — WFM server, device agent, and Eclipse Symphony k8s control plane — is running on ARM64 hardware after applying the workarounds described below.
Issue 1 — Margo WFM client: no ARM64 image published to ghcr.io
docker manifest inspect ghcr.io/margo/margo.org/workload-fleet-management-client:latestshows onlyamd64. No ARM64 variant is published.The
.goreleaser.yamlcorrectly listslinux/arm64as a build target, and the Dockerfile builds cleanly on ARM64 (tested and confirmed). The issue is that the GitHub Actions workflow never builds and pushes the ARM64 image to ghcr.io.Fix: Add
linux/arm64to the Docker build and push step in the CI workflow.Issue 2 — Margo WFM client: Docker hardcoded as runtime dependency
The WFM client has a hard dependency on Docker in two places:
shared-lib/workloads/dockerCliClient.go:poc/device/agent/Dockerfile:This directly contradicts Margo's secure-by-design philosophy. Docker requires a persistent root daemon (
dockerd) — a container escape on an OT edge node running EtherCAT/PROFINET gives an attacker root on the host. This is unacceptable for industrial deployments.Podman is the correct default: rootless by default, daemonless, full Docker CLI compatibility (
alias docker=podmanor symlink), native pod support, OCI-native. The fix is trivial sinceexec.LookPath("docker")resolves whatever binary is nameddockerin PATH.Proposed fix —
dockerCliClient.go:Proposed fix —
Dockerfile:Tested on Podman 5.4.2 with podman-compose 1.3.0 on aarch64. Both
docker --versionanddocker compose versionresolve correctly via symlink.Issue 3 — Eclipse Symphony dependency:
symphony-k8s:0.48.28contains an amd64 binary in the ARM64 manifestThe Helm chart for Symphony (which the Margo sandbox depends on) pins
symphony-k8s:0.48.28. This image has a multi-arch manifest that claims to includelinux/arm64, but the actual binary inside the ARM64 layer is x86-64:This results in
exec /manager: exec format errorwhen the container starts on ARM64 — a silent wrong-binary-in-manifest bug.The
latesttag (built 2026-05-14) contains a correct ARM64 binary:Workaround used to get Symphony running on ARM64:
Fix: Update the sandbox Helm chart to pin a version of
symphony-k8sthat has a correct ARM64 build, or switch tolatest. This should also be reported upstream to the Eclipse Symphony project.Summary
Workarounds needed to run on Podman (undocumented)
ci-test+ setCI=true— bypasses the GHCR pull in the start script/var/run/podman/podman.sock:/var/run/docker.socksystemctl enable --now podman.socketsymphony-serviceto/etc/hosts— TLS cert hostname matchingCA:TRUE— the sandbox cert generator has a bug (CA:FALSE), use OpenSSL directlymargo-symphony-apicontainer instead of Helm Symphony — Helm-deployed Symphony has no Margo onboarding endpointmargo-symphony-apineeds it but doesn't bundle itsymphony-k8s:0.48.28ARM64 manifest contains amd64 binaryAll three issues were found on first contact with real ARM64 hardware. Fixes are proposed for all three.