feat: add static musl binary builds for Linux (#103) (#113)

* feat: add static musl binary builds for Linux (#103)
* feat: add aarch64 static builds, clean up docs
This commit is contained in:
Marco Cadetg
2025-12-26 22:13:00 +01:00
committed by GitHub
parent a481214c62
commit 9289a0abb1
4 changed files with 149 additions and 67 deletions
+60 -1
View File
@@ -185,10 +185,69 @@ jobs:
path: rustnet-${{ github.ref_name }}-x86_64-unknown-freebsd.tar.gz
if-no-files-found: error
build-static:
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:
- 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: |
file target/release/rustnet
# Use file command to verify (ldd behaves differently inside Alpine)
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 }}-${{ matrix.target }}"
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 build artifact
uses: actions/upload-artifact@v6
with:
name: build-${{ matrix.target }}
path: rustnet-${{ github.ref_name }}-${{ matrix.target }}.tar.gz
if-no-files-found: error
create-release:
name: create-release
runs-on: ubuntu-latest
needs: [build-release, build-freebsd]
needs: [build-release, build-freebsd, build-static]
steps:
- name: Checkout repository
uses: actions/checkout@v6
+61
View File
@@ -0,0 +1,61 @@
# Dockerfile for building static musl-linked RustNet binary
#
# Usage (with eBPF - default, recommended):
# docker build -f Dockerfile.static -t rustnet-static .
# docker run --rm -v $(pwd)/dist:/dist rustnet-static cp /build/target/release/rustnet /dist/
#
# Usage (without eBPF - smaller binary, ~5.2MB vs ~6.5MB):
# docker build -f Dockerfile.static --build-arg FEATURES="--no-default-features" -t rustnet-static .
FROM rust:alpine
ARG FEATURES=""
# Install build dependencies
# - musl-dev: musl C library headers
# - libpcap-dev: libpcap headers and static library (/usr/lib/libpcap.a)
# - pkgconfig: for finding library paths
# - build-base: basic build tools (make, gcc, etc.)
# - perl: required by some build scripts (ring crate)
# - elfutils-dev: libelf for eBPF (includes static library)
# - zlib-dev/zlib-static: compression library
# - zstd-dev/zstd-static: Zstandard compression (required by elfutils 0.189+)
# - clang/llvm: for eBPF compilation
# - linux-headers: kernel headers for eBPF
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
# Add rustfmt for eBPF skeleton generation
RUN rustup component add rustfmt
WORKDIR /build
# Copy source code
COPY . .
# Configure static linking for zstd
# This fixes the elfutils 0.189+ undeclared dependency on zstd
# See: https://github.com/libbpf/bpftool/issues/152
RUN mkdir -p .cargo && printf '[target.x86_64-unknown-linux-musl]\nrustflags = ["-C", "link-arg=-l:libzstd.a"]\n' > .cargo/config.toml
# Build configuration:
# - In Alpine/musl, binaries are statically linked by default
# - FEATURES arg controls whether eBPF is included (default) or disabled
# - --release: Optimized build
RUN cargo build --release ${FEATURES}
# Verify the binary is statically linked
RUN file target/release/rustnet && \
ldd target/release/rustnet 2>&1 || echo "Binary is statically linked"
+28
View File
@@ -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.
-66
View File
@@ -1,66 +0,0 @@
# musl Static Build Challenges
This document explains why RustNet currently does not provide musl static builds and the technical challenges encountered during implementation attempts.
## Background
musl is a lightweight C standard library designed for static linking. It would allow RustNet to produce fully static binaries that work on any Linux distribution regardless of GLIBC version.
## Why We Attempted musl Builds
GitHub issue #40 reported that pre-built packages required GLIBC 2.38/2.39, which wasn't available on PopOS 22.04 (GLIBC 2.35). musl builds would theoretically solve this by creating fully static binaries.
## Challenges Encountered
### libpcap Linking Issues
The primary challenge appears to be related to **libpcap** static linking with musl:
- Installing `libpcap-dev` in Ubuntu-based cross-rs containers provides glibc-linked libraries
- Attempting to statically link these with musl resulted in linker errors
- Errors included undefined references to pthread, math (exp), and dynamic loading functions (dladdr)
It's unclear whether this is due to:
- Fundamental glibc/musl incompatibility when statically linking
- Missing library specifications in the linker flags
- Issues with how cross-rs musl images are configured
- Something specific to our build configuration
### eBPF Complications
We initially attempted to include eBPF support, which required vendoring libelf and zlib. This was abandoned to simplify the problem, but even without eBPF the libpcap linking issues persisted.
## Current Solution
**We solved the original issue by pinning builds to ubuntu-22.04** (GLIBC 2.35), which ensures compatibility with PopOS 22.04 and similar distributions.
For users on older distributions, the `cargo install` workaround is documented:
```bash
cargo install rustnet-monitor
sudo setcap 'cap_net_raw,cap_bpf,cap_perfmon=eip' ~/.cargo/bin/rustnet
```
## Potential Future Approaches
If someone wants to tackle musl builds in the future, areas to investigate:
1. **Building libpcap from source** targeting musl in the pre-build step
2. **Using Alpine Linux-based images** which have native musl packages
3. **Custom linker flags** to properly link required libraries
4. **Alternative pure-Rust packet capture** libraries (if they exist)
We're uncertain which approach would work best, or if there are other issues we haven't discovered yet.
## Why We're Not Pursuing This Now
- The ubuntu-22.04 solution already addresses the reported issue
- The complexity-to-benefit ratio seems high
- `cargo install` provides a universal fallback for edge cases
- More investigation would be needed to understand the root causes
If you have experience with musl static linking and want to contribute, we'd welcome the help!
---
*Last updated: 2025-10-09*
*Status: Not currently pursuing due to linking complexity*