mirror of
https://github.com/domcyrus/rustnet.git
synced 2026-01-04 04:49:53 -06:00
feat: add aarch64 static builds, clean up docs
This commit is contained in:
21
.github/workflows/release.yml
vendored
21
.github/workflows/release.yml
vendored
@@ -186,8 +186,17 @@ jobs:
|
||||
if-no-files-found: error
|
||||
|
||||
build-static:
|
||||
name: build-static-musl
|
||||
runs-on: ubuntu-latest
|
||||
name: build-static-${{ matrix.arch }}
|
||||
runs-on: ${{ matrix.runner }}
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- arch: x86_64
|
||||
runner: ubuntu-latest
|
||||
target: x86_64-unknown-linux-musl
|
||||
- arch: aarch64
|
||||
runner: ubuntu-24.04-arm
|
||||
target: aarch64-unknown-linux-musl
|
||||
container:
|
||||
image: rust:alpine
|
||||
steps:
|
||||
@@ -213,12 +222,12 @@ jobs:
|
||||
run: |
|
||||
file target/release/rustnet
|
||||
# Use file command to verify (ldd behaves differently inside Alpine)
|
||||
file target/release/rustnet | grep -q "static-pie linked" || \
|
||||
file target/release/rustnet | grep -q "static.* linked" || \
|
||||
(echo "ERROR: Binary is not statically linked" && exit 1)
|
||||
|
||||
- name: Create release archive
|
||||
run: |
|
||||
staging="rustnet-${{ github.ref_name }}-x86_64-unknown-linux-musl"
|
||||
staging="rustnet-${{ github.ref_name }}-${{ matrix.target }}"
|
||||
mkdir -p "$staging/assets"
|
||||
|
||||
cp target/release/rustnet "$staging/"
|
||||
@@ -231,8 +240,8 @@ jobs:
|
||||
- name: Upload static build artifact
|
||||
uses: actions/upload-artifact@v6
|
||||
with:
|
||||
name: build-x86_64-unknown-linux-musl
|
||||
path: rustnet-${{ github.ref_name }}-x86_64-unknown-linux-musl.tar.gz
|
||||
name: build-${{ matrix.target }}
|
||||
path: rustnet-${{ github.ref_name }}-${{ matrix.target }}.tar.gz
|
||||
if-no-files-found: error
|
||||
|
||||
create-release:
|
||||
|
||||
82
.github/workflows/test-static-build.yml
vendored
82
.github/workflows/test-static-build.yml
vendored
@@ -1,82 +0,0 @@
|
||||
name: Test Static Build
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
paths:
|
||||
- 'Dockerfile.static'
|
||||
- '.github/workflows/test-static-build.yml'
|
||||
- '.github/workflows/release.yml'
|
||||
- 'MUSL_BUILD.md'
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
build-static:
|
||||
name: build-static-musl
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: rust:alpine
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
apk add --no-cache \
|
||||
musl-dev libpcap-dev pkgconfig build-base perl \
|
||||
elfutils-dev zlib-dev zlib-static zstd-dev zstd-static \
|
||||
clang llvm linux-headers git
|
||||
rustup component add rustfmt
|
||||
|
||||
- name: Build static binary
|
||||
env:
|
||||
# -C strip=symbols: Strip debug symbols for smaller binary
|
||||
# -C link-arg=-l:libzstd.a: Fix elfutils 0.189+ zstd dependency (libbpf/bpftool#152)
|
||||
RUSTFLAGS: "-C strip=symbols -C link-arg=-l:libzstd.a"
|
||||
run: cargo build --release
|
||||
|
||||
- name: Verify static linking
|
||||
run: |
|
||||
echo "=== File info ==="
|
||||
file target/release/rustnet
|
||||
echo ""
|
||||
echo "=== ldd output ==="
|
||||
ldd target/release/rustnet 2>&1 || true
|
||||
echo ""
|
||||
echo "=== Size ==="
|
||||
ls -lh target/release/rustnet
|
||||
echo ""
|
||||
# Verify it's actually static using file command
|
||||
# (ldd behaves differently inside Alpine vs glibc systems)
|
||||
if file target/release/rustnet | grep -q "static-pie linked"; then
|
||||
echo "✅ Binary is statically linked!"
|
||||
else
|
||||
echo "❌ ERROR: Binary is NOT statically linked"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Test binary runs
|
||||
run: |
|
||||
./target/release/rustnet --version
|
||||
./target/release/rustnet --help | head -20
|
||||
|
||||
- name: Create release archive
|
||||
run: |
|
||||
staging="rustnet-static-x86_64-unknown-linux-musl"
|
||||
mkdir -p "$staging/assets"
|
||||
|
||||
cp target/release/rustnet "$staging/"
|
||||
cp assets/services "$staging/assets/" 2>/dev/null || true
|
||||
cp README.md "$staging/"
|
||||
cp LICENSE "$staging/" 2>/dev/null || true
|
||||
|
||||
tar czf "$staging.tar.gz" "$staging"
|
||||
|
||||
- name: Upload static binary
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: rustnet-static-musl
|
||||
path: rustnet-static-x86_64-unknown-linux-musl.tar.gz
|
||||
retention-days: 7
|
||||
28
INSTALL.md
28
INSTALL.md
@@ -216,6 +216,34 @@ sudo setcap 'cap_net_raw,cap_bpf,cap_perfmon=eip' $(brew --prefix)/bin/rustnet
|
||||
rustnet
|
||||
```
|
||||
|
||||
#### Static Binary (Portable - Any Linux Distribution)
|
||||
|
||||
For maximum portability, static binaries are available that work on **any Linux distribution** regardless of GLIBC version. These are fully self-contained and require no system dependencies.
|
||||
|
||||
```bash
|
||||
# Download the static binary for your architecture:
|
||||
# - rustnet-vX.Y.Z-x86_64-unknown-linux-musl.tar.gz (x86_64)
|
||||
# - rustnet-vX.Y.Z-aarch64-unknown-linux-musl.tar.gz (ARM64)
|
||||
|
||||
# Extract the archive
|
||||
tar xzf rustnet-vX.Y.Z-x86_64-unknown-linux-musl.tar.gz
|
||||
|
||||
# Move binary to PATH
|
||||
sudo mv rustnet-vX.Y.Z-x86_64-unknown-linux-musl/rustnet /usr/local/bin/
|
||||
|
||||
# Grant capabilities (modern kernel 5.8+)
|
||||
sudo setcap 'cap_net_raw,cap_bpf,cap_perfmon=eip' /usr/local/bin/rustnet
|
||||
|
||||
# Run without sudo
|
||||
rustnet
|
||||
```
|
||||
|
||||
**When to use static binaries:**
|
||||
- Older distributions with outdated GLIBC (e.g., CentOS 7, older Ubuntu)
|
||||
- Minimal/containerized environments
|
||||
- Air-gapped systems where installing dependencies is difficult
|
||||
- When you want a single portable binary
|
||||
|
||||
### FreeBSD Installation
|
||||
|
||||
FreeBSD support is available starting from version 0.15.0.
|
||||
|
||||
133
MUSL_BUILD.md
133
MUSL_BUILD.md
@@ -1,133 +0,0 @@
|
||||
# musl Static Build Guide
|
||||
|
||||
This document explains how to build fully static RustNet binaries using musl.
|
||||
|
||||
## Quick Start
|
||||
|
||||
```bash
|
||||
# Build static binary with eBPF support (default, ~6.5MB)
|
||||
docker build -f Dockerfile.static -t rustnet-static .
|
||||
|
||||
# Or build without eBPF (smaller, ~5.2MB)
|
||||
docker build -f Dockerfile.static --build-arg FEATURES="--no-default-features" -t rustnet-static .
|
||||
|
||||
# Extract the binary
|
||||
mkdir -p dist
|
||||
docker run --rm -v $(pwd)/dist:/out rustnet-static cp /build/target/release/rustnet /out/
|
||||
|
||||
# Verify it's static
|
||||
file dist/rustnet
|
||||
# Output: ELF 64-bit LSB pie executable, x86-64, ..., static-pie linked
|
||||
|
||||
ldd dist/rustnet
|
||||
# Output: statically linked
|
||||
```
|
||||
|
||||
## Binary Characteristics
|
||||
|
||||
| Build | Size | eBPF | Process Detection | Compatibility |
|
||||
|-------|------|------|-------------------|---------------|
|
||||
| With eBPF | ~6.5MB | Yes | eBPF + procfs fallback | Any Linux |
|
||||
| Without eBPF | ~5.2MB | No | procfs only | Any Linux |
|
||||
|
||||
## How It Works
|
||||
|
||||
The `Dockerfile.static` uses `rust:alpine` which provides:
|
||||
- Native musl toolchain (no glibc/musl mixing issues)
|
||||
- `libpcap-dev` package with static library (`/usr/lib/libpcap.a`)
|
||||
- `elfutils-dev` with static libelf for eBPF
|
||||
- All dependencies compiled against musl
|
||||
|
||||
### The zstd Fix
|
||||
|
||||
Alpine's elfutils 0.189+ has an undeclared dependency on zstd for ELF section compression. The Dockerfile includes a workaround:
|
||||
|
||||
```toml
|
||||
# .cargo/config.toml
|
||||
[target.x86_64-unknown-linux-musl]
|
||||
rustflags = ["-C", "link-arg=-l:libzstd.a"]
|
||||
```
|
||||
|
||||
This explicitly links the static zstd library, fixing the link order issue. See [libbpf/bpftool#152](https://github.com/libbpf/bpftool/issues/152) for details.
|
||||
|
||||
## Running the Static Binary
|
||||
|
||||
```bash
|
||||
# Set capabilities for packet capture
|
||||
sudo setcap 'cap_net_raw=eip' dist/rustnet
|
||||
|
||||
# For eBPF support (Linux 5.8+)
|
||||
sudo setcap 'cap_net_raw,cap_bpf,cap_perfmon=eip' dist/rustnet
|
||||
|
||||
# Run
|
||||
./dist/rustnet
|
||||
```
|
||||
|
||||
## CI Integration
|
||||
|
||||
For GitHub Actions, use the native container approach (faster than Docker build):
|
||||
|
||||
```yaml
|
||||
build-static:
|
||||
name: build-static-musl
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: rust:alpine
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
apk add --no-cache \
|
||||
musl-dev libpcap-dev pkgconfig build-base perl \
|
||||
elfutils-dev zlib-dev zlib-static zstd-dev zstd-static \
|
||||
clang llvm linux-headers git
|
||||
rustup component add rustfmt
|
||||
|
||||
- name: Configure static zstd linking
|
||||
run: |
|
||||
mkdir -p .cargo
|
||||
printf '[target.x86_64-unknown-linux-musl]\nrustflags = ["-C", "link-arg=-l:libzstd.a"]\n' > .cargo/config.toml
|
||||
|
||||
- name: Build
|
||||
run: cargo build --release
|
||||
|
||||
- name: Verify static linking
|
||||
run: |
|
||||
file target/release/rustnet
|
||||
ldd target/release/rustnet 2>&1 | grep -q "statically linked"
|
||||
```
|
||||
|
||||
## Historical Context
|
||||
|
||||
### Previous Challenges (Resolved)
|
||||
|
||||
Earlier attempts using cross-rs with Ubuntu-based containers failed:
|
||||
- Installing `libpcap-dev` in Ubuntu provides glibc-linked libraries
|
||||
- Mixing glibc libraries with musl linking caused undefined references
|
||||
- Errors included pthread, math (exp), and dladdr symbols
|
||||
|
||||
### Why Alpine Works
|
||||
|
||||
Alpine Linux uses musl as its system C library:
|
||||
- All packages are compiled against musl
|
||||
- Static libraries (`*.a`) are musl-compatible
|
||||
- No glibc/musl mixing occurs
|
||||
|
||||
### The eBPF Challenge (Resolved)
|
||||
|
||||
Static eBPF builds initially failed due to elfutils → zstd dependency chain:
|
||||
- elfutils 0.189+ added ZSTD compression for ELF sections
|
||||
- libbpf-sys didn't propagate the zstd link dependency
|
||||
- Fixed by explicitly linking `-l:libzstd.a` via cargo config
|
||||
|
||||
## References
|
||||
|
||||
- [libbpf/bpftool#152](https://github.com/libbpf/bpftool/issues/152) - zstd link fix
|
||||
- [arachsys/libelf](https://github.com/arachsys/libelf) - Standalone libelf (alternative)
|
||||
- [Alpine Static Linking](https://build-your-own.org/blog/20221229_alpine/) - General guidance
|
||||
|
||||
---
|
||||
|
||||
*Last updated: 2025-12-26*
|
||||
*Status: Fully working with eBPF support*
|
||||
Reference in New Issue
Block a user