Skip to content

fix(docker): repair the Rust pin and build a real musl binary - #6

Merged
doublegate merged 1 commit into
mainfrom
fix/docker-msrv-and-musl
Aug 28, 2026
Merged

fix(docker): repair the Rust pin and build a real musl binary#6
doublegate merged 1 commit into
mainfrom
fix/docker-msrv-and-musl

Conversation

@doublegate

Copy link
Copy Markdown
Owner

Merging the Alpine 3.19 → 3.24 bump (#2) meant looking at the Dockerfile, which had two defects. Neither was caught by anything: packages.yml is the only workflow touching docker/Dockerfile, and it runs solely on a published release or manual dispatch.

The builder could no longer compile the project

ARG RUST_VERSION=1.85 sat below the workspace rust-version, which #1 raised to 1.88. rust:1.85-bookworm ships rustc 1.85.1, so cargo build --locked fails 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:

# 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 exec fails with 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 from debian:bookworm-slim:

result
on debian:bookworm-slim ls (GNU coreutils) 9.1
on alpine:3.24 exec /glibc-ls: no such file or directory

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 — both need a C toolchain and headers matching the target libc, and apk supplies musl builds of each. openssl-dev and openssl-libs-static are needed too, since native-tls pulls openssl-sys.

Verified by building and running both images locally:

image size --version interpreter
debian runtime 97 MB prtip 1.0.0 ld-linux-x86-64.so.2
alpine 26.9 MB prtip 1.0.0 ld-musl-x86_64.so.1

The Alpine variant works for the first time.

Preventing recurrence

A new docker CI job builds both targets, runs prtip --version in 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 include docker/**.

🤖 Generated with Claude Code

https://claude.ai/code/session_01NBDCJvLbq7nuor7RtT57rD

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
Copilot AI lite review requested due to automatic review settings August 28, 2026 22:10
@coderabbitai

coderabbitai Bot commented Aug 28, 2026

Copy link
Copy Markdown

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 036ded95-345c-4d65-bda9-c8b07c7fb252


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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions

Copy link
Copy Markdown

🤖 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.

@github-actions

Copy link
Copy Markdown

🤖 I'm sorry @doublegate, but I was unable to process your request. Please see the logs for more details.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 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/Dockerfile Rust image pin to 1.88 and add an Alpine-native musl-builder stage.
  • Fix the Alpine runtime stage to copy the musl-built prtip binary instead of the Debian/glibc binary.
  • Extend CI (ci.yml) to build both container targets and validate prtip --version runs, 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.

Comment thread docker/Dockerfile
Comment on lines +12 to +15
# 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
Comment thread docker/Dockerfile
Comment on lines +158 to +162
# 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.
Comment thread CHANGELOG.md
Comment on lines +271 to +274
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)")
@doublegate
doublegate merged commit 900da81 into main Aug 28, 2026
18 of 19 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants