Multi-Architecture Build Strategy
Problem Statement
NoETL has a Rust CLI binary (noetlctl) that needs to work across:
- Local development: Mac (arm64/amd64), Linux (amd64/arm64), Windows
- Docker containers: Linux (amd64/arm64)
- Kubernetes clusters: Any node architecture
Currently:
- Single-architecture builds only
- Mac developers can't run locally without building UI assets
- Docker images locked to build host architecture
Recommendation: YES - Implement Multi-Architecture Support
Reasons:
-
Development Flexibility
- Mac M-series developers need arm64 binaries locally
- Intel Mac/Linux developers need amd64 binaries
- Single Docker image works everywhere
-
Production Flexibility
- Deploy to any Kubernetes cluster (amd64 or arm64 nodes)
- Use cheaper arm64 cloud instances (AWS Graviton, GCP Tau T2A)
- No architecture lock-in
-
CI/CD Efficiency
- Build once, deploy anywhere
- No separate build pipelines per architecture
- Registry auto-selects correct image for host
-
Future-Proofing
- arm64 adoption growing (Apple Silicon, AWS Graviton, Azure Cobalt)
- Single image simplifies distribution
Implementation Plan
Phase 1: Quick Fix for Local Development
Issue: python -m noetl.server fails because UI assets missing locally
Solution: Run setup script
./scripts/setup_local_dev.sh
This script:
- Builds UI assets from
ui-src/→noetl/core/ui/ - Builds Rust CLI for native architecture
- Copies binary to
bin/noetlandnoetl/bin/noetl
Alternative: Disable UI for local development
export NOETL_ENABLE_UI=false
mkdir -p noetl/core/ui/assets # Create empty directory
python -m noetl.server
Phase 2: Add Buildx Support to Build Scripts
Update docker/build-noetl-images.sh:
# Add platform flag
--platforms linux/amd64,linux/arm64 # Build both
--platforms linux/arm64 # Build single arch
--use-buildx # Enable buildx
Phase 3: Multi-Stage Dockerfile Optimization
The current docker/noetl/dev/Dockerfile already uses multi-stage builds:
- UI builder (Node.js) - platform-agnostic
- Rust builder - architecture-specific compilation
- Python runtime - platform-agnostic
This structure is optimal for multi-arch builds.
Phase 4: CI/CD Pipeline
Add GitHub Actions workflow for automated multi-arch builds:
- Build on push to main
- Push to ghcr.io with manifest list
- Tag with commit SHA and
latest
Cost-Benefit Analysis
Costs:
- Build time: 2x longer for multi-arch (building twice)
- Registry storage: ~2x storage (two images per tag)
- Initial setup: ~2-4 hours to implement and test
Benefits:
- Developer productivity: No architecture hassles
- Runtime flexibility: Deploy anywhere
- Cost savings: Can use cheaper arm64 instances
- Future-proof: Ready for arm64 adoption
ROI: Positive - initial investment pays off quickly
Architecture-Specific Considerations
Rust Cross-Compilation
Current approach uses native compilation within Docker (slow under emulation).
Optimization: Use cross-rs for faster builds:
FROM rust:1.83-slim AS rust-builder
RUN cargo install cross
# Build arm64 on amd64 host (or vice versa) without emulation
RUN cross build --release --target aarch64-unknown-linux-gnu
Python Packages
Most Python packages have pre-built wheels for both architectures.
Exception: Some C extensions may need compilation - document in requirements.
UI Assets
Platform-agnostic - build once, copy to both images.
Immediate Action Items
-
✅ Fix local development (immediate)
./scripts/setup_local_dev.sh -
Add buildx support (1-2 hours)
- Update
docker/build-noetl-images.sh - Add
--platformsflag - Test on Mac and Linux
- Update
-
Update documentation (completed)
- Created
documentation/docs/development/multi_arch_builds.md - Documents local dev setup, multi-arch builds, troubleshooting
- Created
-
CI/CD integration (2-4 hours)
- Add GitHub Actions workflow
- Configure ghcr.io push
- Test automated builds
Testing Strategy
-
Local testing:
./scripts/setup_local_dev.sh
./bin/noetl server start -
Docker single-arch:
task docker-build-noetl
docker run noetl-local-dev:latest server start -
Docker multi-arch:
docker buildx build --platform linux/amd64,linux/arm64 ...
docker buildx imagetools inspect noetl-local-dev:latest -
Kubernetes deployment:
task deploy-noetl
kubectl get pods -o wide # Verify runs on any node