fix(docker): repair the Rust pin and build a real musl binary - #6
Conversation
Merging the Alpine 3.19 -> 3.24 bump meant looking at the Dockerfile, which
turned out to have two defects. Neither was caught by anything, because
`packages.yml` is the only workflow that touches `docker/Dockerfile` and it runs
only on a published release or a manual dispatch.
## The builder could no longer compile the project
`ARG RUST_VERSION=1.85` pinned the builder below the workspace's `rust-version`,
which this branch raised to 1.88. `rust:1.85-bookworm` ships rustc 1.85.1, so
`cargo build --locked` fails outright with "requires rustc 1.88 or newer".
A regression introduced by the MSRV change and merged without detection. Pin is
now 1.88, with a comment tying it to `Cargo.toml`.
## The Alpine image never worked
The alpine stage copied the **Debian-built glibc binary** into a **musl** image:
# For now, use the glibc binary (requires compatibility layer or rebuild)
COPY --from=builder /build/target/release/prtip /usr/local/bin/prtip
Alpine has no `/lib64/ld-linux-x86-64.so.2`, so the kernel refuses the exec and
reports the notoriously misleading "no such file or directory" -- about the
loader, not the binary. The image built cleanly and `prtip` could not run in it
at all; its own HEALTHCHECK would have failed on every start.
Demonstrated with a negative control before changing anything: a glibc `ls`
lifted from `debian:bookworm-slim` prints `ls (GNU coreutils) 9.1` on Debian and
fails with `exec /glibc-ls: no such file or directory` on `alpine:3.24`.
There is now a `musl-builder` stage compiling natively on `rust:1.88-alpine`.
Native rather than cross-compiled because `pcap` links libpcap and `mlua` builds
a vendored Lua, so both need a C toolchain and headers matching the target libc;
apk supplies musl builds of each, which beats assembling a musl sysroot on
Debian. Needs `openssl-dev` and `openssl-libs-static` too -- `native-tls` pulls
`openssl-sys`, whose build script fails without them.
Verified by building and running both images:
prtip:runtime-test (debian) 97 MB prtip 1.0.0 ld-linux-x86-64.so.2
prtip:alpine-test (alpine) 26.9 MB prtip 1.0.0 ld-musl-x86_64.so.1
The Alpine variant works for the first time.
## Preventing the recurrence
A new `docker` job in `ci.yml` builds both targets and runs `prtip --version` in
each, plus asserts the Alpine binary's interpreter is musl. Running the binary
is the check that matters: a libc mismatch yields an image that builds fine and
fails only when something execs it, so a build-only gate would have stayed green
through this entire bug. Path filters now include `docker/**`.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NBDCJvLbq7nuor7RtT57rD
|
Important
This repository does not receive automatic reviews because it has fewer than 10 stars. ⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Plus Run ID: Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
🤖 Hi @doublegate, I've received your request, and I'm working on it now! You can track my progress in the logs for more details. |
|
🤖 I'm sorry @doublegate, but I was unable to process your request. Please see the logs for more details. |
There was a problem hiding this comment.
🟢 Approval recommended
The functional Docker/CI changes look correct, with only minor wording accuracy nits in newly added comments/changelog text.
Pull request overview
Repairs the Docker build for ProRT-IP by aligning the Docker Rust toolchain pin with the workspace MSRV and producing a truly musl-linked Alpine image, then adds CI coverage to prevent regressions.
Changes:
- Bump
docker/DockerfileRust image pin to1.88and add an Alpine-nativemusl-builderstage. - Fix the Alpine runtime stage to copy the musl-built
prtipbinary instead of the Debian/glibc binary. - Extend CI (
ci.yml) to build both container targets and validateprtip --versionruns, plus assert the Alpine binary is musl-linked.
File summaries
| File | Description |
|---|---|
docker/Dockerfile |
Updates Rust pin to match MSRV and adds a dedicated musl build stage; fixes Alpine image to use the musl binary. |
CHANGELOG.md |
Documents the Docker/MSRV and Alpine libc mismatch fixes, plus the new CI guardrail. |
.github/workflows/ci.yml |
Adds docker/** path filters and a Docker job that builds/runs both images and verifies the Alpine binary is musl-linked. |
Review details
- Files reviewed: 3/3 changed files
- Comments generated: 3
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| # Must be >= the workspace `rust-version` in Cargo.toml (1.88). A pin below | ||
| # the MSRV fails the build with "requires rustc 1.88 or newer"; nothing in CI | ||
| # caught the drift because packages.yml only runs on releases. | ||
| ARG RUST_VERSION=1.88 |
| # Copying the Debian-built glibc binary here produced an image in which | ||
| # `prtip` could not execute at all -- musl provides no | ||
| # /lib64/ld-linux-x86-64.so.2, so the kernel fails the exec with a bare | ||
| # "no such file or directory". The HEALTHCHECK below would have caught it | ||
| # on every run of this image. |
| the kernel failed the exec with a bare "no such file or directory" — the image | ||
| built cleanly and `prtip` could not run in it, which the stage's own | ||
| `HEALTHCHECK` would have failed on every start. The comment in place | ||
| ("For now, use the glibc binary (requires compatibility layer or rebuild)") |
Merging the Alpine 3.19 → 3.24 bump (#2) meant looking at the Dockerfile, which had two defects. Neither was caught by anything:
packages.ymlis the only workflow touchingdocker/Dockerfile, and it runs solely on a published release or manual dispatch.The builder could no longer compile the project
ARG RUST_VERSION=1.85sat below the workspacerust-version, which #1 raised to 1.88.rust:1.85-bookwormships rustc 1.85.1, socargo build --lockedfails outright.This was my regression — introduced by the MSRV change and merged undetected.
The Alpine image never worked
The stage copied the Debian-built glibc binary into a musl image:
Alpine has no
/lib64/ld-linux-x86-64.so.2, so the exec fails with the notoriously misleadingno such file or directory— about the loader, not the binary. The image built cleanly andprtipcould not run in it at all; its own HEALTHCHECK would have failed on every start.Demonstrated with a negative control before changing anything — a glibc
lsfromdebian:bookworm-slim:debian:bookworm-slimls (GNU coreutils) 9.1alpine:3.24exec /glibc-ls: no such file or directoryThere is now a
musl-builderstage compiling natively onrust:1.88-alpine. Native rather than cross-compiled becausepcaplinks libpcap andmluabuilds a vendored Lua — both need a C toolchain and headers matching the target libc, and apk supplies musl builds of each.openssl-devandopenssl-libs-staticare needed too, sincenative-tlspullsopenssl-sys.Verified by building and running both images locally:
--versionprtip 1.0.0ld-linux-x86-64.so.2prtip 1.0.0ld-musl-x86_64.so.1The Alpine variant works for the first time.
Preventing recurrence
A new
dockerCI job builds both targets, runsprtip --versionin each, and asserts the Alpine binary's interpreter is musl. Running the binary is the check that matters — a libc mismatch produces an image that builds fine and fails only on exec, so a build-only gate would have stayed green through this entire bug. Path filters now includedocker/**.🤖 Generated with Claude Code
https://claude.ai/code/session_01NBDCJvLbq7nuor7RtT57rD