Repository navigation
Open
Description
Certain domains (for me it's github.com) always fail to resolve in rootless Docker when the image is built with muslrust:
main.rs
use std::net::ToSocketAddrs;
fn main() {
let domains = ["google.com", "github.com"];
for domain in domains
{
println!("Trying to resolve {domain} with to_socket_addrs()");
format!("{domain}:443").to_socket_addrs().unwrap();
println!("it worked");
}
}There are no dependencies installed.
Dockerfile
# syntax=docker/dockerfile:1
FROM clux/muslrust:1.71.0 as musl
#USER root
WORKDIR /app
COPY . .
ARG CARGO_INCREMENTAL=0
# trying to resolve URLs, just show errors, don't abort
# this *works* in rootless Docker in musl
RUN curl -sS -o /dev/null https://google.com; exit 0
# this *fails* in rootless Docker in musl
RUN curl -sS -o /dev/null https://github.com; exit 0
RUN cargo build --release --target x86_64-unknown-linux-musl
CMD ["/app/target/x86_64-unknown-linux-musl/release/mwedns"]
FROM rust:1.71.0-slim
WORKDIR /app
COPY . .
ARG CARGO_INCREMENTAL=0
# this *works* in rootless Docker with the official Rust image
RUN curl -sS -o /dev/null https://google.com; exit 0
# this *works* in rootless Docker with the official Rust image
RUN curl -sS -o /dev/null https://github.com; exit 0
RUN cargo build --release
COPY --link --from=musl /app/target/x86_64-unknown-linux-musl/release/mwedns /app/musl
# run the one compiled with the official Rust image first
CMD echo "official Rust" && /app/target/release/mwedns && echo "musl Rust" && /app/muslYou can test this MWE at https://github.com/KonradHoeffner/mwedns:
$ git clone [email protected]:KonradHoeffner/mwedns.git
$ cd mwedns
$ docker build . -t mwedns
[...]
$ docker run --rm mwedns
Output
official Rust
Trying to resolve google.com with to_socket_addrs()
it worked
Trying to resolve github.com with to_socket_addrs()
it worked
musl Rust
Trying to resolve google.com with to_socket_addrs()
it worked
Trying to resolve github.com with to_socket_addrs()
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: Custom { kind: Uncategorized, error: "failed to lookup address information: Name does not resolve" }', src/main.rs:8:51
I reported this first at algesten/ureq#645 but then found out it has nothing to do with ureq.
You can also verify that DNS lookup fails in rootless Docker with:
$ docker run --rm --entrypoint "/bin/bash" clux/muslrust:1.71.0 -c "curl -sS -o /dev/null https://github.com"
curl: (6) Could not resolve host: github.com
Relation to Alpine?
There is a known bug with the Alpine image reported at alpinelinux/docker-alpine#155.
However the things that differ here:
- looking at the muslrust Dockerfile, it is based on Ubuntu Jammy, not on Alpine
- the error occurs inside a muslrust container
- inside an official Rust container, the errors occurs with a binary built within a muslrust container but not with a binary built within an official Rust container
Metadata
Metadata
Assignees
Labels
No labels
Activity
clux commentedon Aug 4, 2023
This is almost certainly down to how musl does dns and not something we can solve here.
You are putting a musl built static binary inside of a rust container which is a debian based (glibc) distro, with dns resolution settings (resolv.conf / dnsmasq.conf) that is probably not ideal for what it was built for.
I would recommend following this post and seeing where that takes you. There's also a more kubernetes focused issue that may be useful at k3s-io/k3s#6132.
jhaand commentedon Feb 3, 2025
This issue is one of the few answers when searching for answers on this error.
error: "failed to lookup address information: Name does not resolve"It seems that MUSL does DNS different. I had several DNS servers in my resolv.conf file and it would arbitrarily check the public DNS servers. By limiting the list of servers in resolv.conf to only the local DNS server, everything worked again.
See also this discussion. https://musl.openwall.narkive.com/i7kiCD4c/resolv-conf-ordering
polarathene commentedon Apr 28, 2025
TL;DR:
A static musl build should generally be portable even to a distro that is using glibc. Dynamic linking not so much.
A static glibc build however isn't fully static in comparison. It has some calls for networking that still rely on glibc IIRC? An alternative to glibc for static builds when musl is not desired is Eyra (rust-based that hijacks the glibc target), but it's a bit spotty if you need native deps IIRC as not all of glibc ABI(?) is implemented.
FWIW regarding the DNS over TCP concern at that issue, that was resolved a couple months after the blog post was published. With Alpine 3.18 / musl 1.2.4.
muslrust:1.85.0-stable(March 2025) is the first stable tag that upgraded from musl1.2.2to1.2.4. The previous1.84.0-stabletag was from Jan 2025, so it took a while to land in this image vs the Alpine 3.18 release (May 2023).You can check the musl version like this:
That said, I'm not familiar with this
muslrustproject, but at a glance it's using Ubuntu with musl provided viamusl-gccpackage to support building native deps for the musl target.With Fedora, there's the
musl-libcpackage (implicit viamusl-gccpackage), but they also release updates to packages until the release is EOL (approx 12 months, may be a little bit of lag between packages updating to newer releases):@KonradHoeffner I attempted your other (
ureq) reproduction example, which needed to bump themuslrustimage to1.78.0-stablefor the installation ofcargo-chef v0.1.71. As shown above though, it should still reproduce that musl error? Yet I was not able to reproduce with Docker rootless 🤷♂Even without
chefinvolved, fails to reproduce:Alternatively, here's a Fedora based equivalent of your smaller reproduction that you provided in this issue (single
Dockerfileto build, nothing else needed):Likewise though, since I cannot reproduce the failure on my end, I am not sure how accurately that would reproduce the failure (it should based on the info provided). If it does simply switching from
fedora:38tofedora:39should resolve it, like with the other images mentioned that upgrade to newer musl release(EDIT: Actually, that'll happily build withoutmusl-gcc, just replace that package withgccsince there is no native deps to build with this smaller reproduction example, so system musl may not actually be used).For the musl target, Rust will static link by default (unless using Alpine's
cargopackage which is patched to dynamic link by default) and provide it's own musl runtime to embed IIRC (due toRUSTFLAGS="-C link-self-contained=yes"default applied for the musl target).1.2.3which should trigger the bug? 🤷♂rustcdocs cite musl target as using musl 1.2.31.1.24to1.2.3.RUSTFLAGS="-C target-feature=-crt-static"), that'll imply-lcthat on a glibc distro will be resolved to glibc instead of musl, henceldd(glibc) will reveal that despite the musl target, you did not link what you expected 😅 (I'm not sure how to go about that, might be better to build on alpine base instead)UPDATE: Nothing to do with pre-built rust std lib either, no musl needed, only
gccfor building that with the musl target on a glibc host:My test environment details:
I am running with Docker Rootless on a linux host.
After creating a new VPS on Vultr with Fedora 42, there is a default
linuxuser(1000:1000) provisioned and I shell into the VPS via SSH to the root account:polarathene commentedon Apr 28, 2025
Focusing on
curldifference insteadThis is an obvious one with difference of glibc vs the static musl. If you did install
musl-gccinto this image the version is 1.2.2, so it should also produce the same problem asmuslrust:1.71.0did for you (also musl 1.2.2).However if you had built with
rust:1.71.0-alpinetag instead of therust:1.71.0-slim(Debian), this shipped musl1.2.4(you can check/etc/os-release, that image is based on Alpine 3.18.2).EDIT: As per my last comment, I'm probably mistaken. I think all AMD64 + ARM64 musl target builds since Rust 1.71.0 to present (1.88.0) are using musl 1.2.3? So it just might not be possible to resolve that.
Let's instead focus on the simpler
curlexample (although I'm also not able to reproduce this 😕)Looking at that containers
curlcommand:So this
curlis built with musl and we can see it's linked dynamically to use the musl 1.2.2 version available.Since
curlwon't fail for me either, there must be something else different with my environment vs what you had to reproduce. Unless since your original report something externally has changed? 🤔github.comis still not serving IPv6 /AAAADNS records:I am running much newer Docker, kernel, etc for the host. So perhaps the issue is affected by that somewhat, or even networking environment.
I have experienced DNS issues in the past even with glibc on a system where the default DNS (old router) did not support TCP queries either (like musl prior to 1.2.4), a good example of where that'd fail would be
dig TXT github.com. Since that was caused by the router lacking support rather than the client, it'd fail either even when querying TCP was supported by the client 😅That was a bit more complicated network wise (Docker running via WSL2 on Windows, where the containers
127.0.0.11:53provided the default DNS, which Docker managed internally, that'd proxy to the WSL2 or Docker Desktop managed DNS I think (or your custom DNS if--dnswas set), followed by whatever was configured/inferred on the Windows host itself.KonradHoeffner commentedon Apr 29, 2025
Thank you for the detailed investigation! After years of this not being fixed I had already given up and switched from Alpine/BusyBox to one of the new "distroless" glibc images where the overhead is not that large anymore but I will check if the problem still persists using the MWE from https://github.com/KonradHoeffner/mwedns/ on a server with the newest current rootless Docker version 28.1.1 installed after upgrading to the currently newest stable Rust/muslrust version of 1.86:
MWE Dockerfile
Still failing with rootless Docker 28.1.1 and muslrust 1.86
Also failing with Fedora 38 and 39
The same also happens with Fedora 39.
Good point, I used BusyBox in the past in the real world case, however I am using the Rust slim image to execute both the dynamic and the static MWE for simplicity.
dig/doggo
On the server itself
dig TXT github.comworks, but inside an Alpine container I get:Unfortunately I am a bit out of time right now but I really appreciate all the information, I will follow up and add the rest later.
polarathene commentedon Apr 29, 2025
No worries, thanks for the response! ❤
The fedora builds presumably would still have that problem if the
musl-gccpackage is swapped forgcc, so that there is no musl provided by Fedora. It'd purely be from Rust bundling musl 1.2.3 I think.If you can find the time to confirm with the
curldifference that would be good too:Although your last bit with
doggomight suggest Alpine 3.18 fails too. You didn't provide much context for the Alpine container.digon the host but showdoggoas the command, was that installed fromapk?cat /etc/os-releasewill show the version).If the curl test fails on Alpine 3.18 or newer, then that is a bit interesting. I have no idea how to reproduce the failure on my end, while yours appears to not be DNS-over-TCP related at all (or if it is your network environment is doing something incompatible, but only with musl involved 🤔)
polarathene commentedon Apr 29, 2025
Yeah that's fair, I've done the same after too many hours lost to troubleshooting Alpine / musl specific bugs that don't occur with glibc images/builds.
If you can use Google distroless, that's pretty decent. Canonical
chiselprovides additional flexibility and can be just as competitive in size/performance while allowing for a wider range of customization package wise, but it's still fairly new so not as streamlined as I'd like.Fedora and openSUSE Leap are great base images alternatives when you need something more familiar for customization when the earlier distroless focused options aren't viable. I've created
Dockerfiles for a few projects where the size is better than Alpine offered and sometimes competitive with distroless equivalents. You just need to use the--installrootoption of a package manager 👍Here's an older example for the testssl project:
KonradHoeffner commentedon Apr 30, 2025
This outputs HTTP Code 000 (I guess this means it cannot open a connection at all?)
Alpine 3.18 also outputs HTTP code 000.
However Alpine 3.19, 3.20 and 3.21 successfully output code 200!
Yes, I am using the latest Alpine 3.21 with doggo from apk:
The host didn't have doggo installed but I now ran doggo using Docker on the server directly then it works:
Now I am wondering why Alpine 3.19 and newer succeed in the curl test but fail the other one.
In general, it seems like Alpine in any version fails to connect to github.com while busybox can starting with version 1.36:
The strange thing is that Alpine 3.21 includes busybox 1.37 which should work...
KonradHoeffner commentedon Apr 30, 2025
Wow, I didn't know you could achieve a size below Alpine! For our use case it's:
polarathene commentedon Apr 30, 2025
I have no clue, that's quite strange. As stated I can't reproduce the failure on my end, always works even on older Alpine.
It's sometimes more effort than it's worth though 😓 (UPDATE: Turns out the Alpine image wasn't optimized well, it's approx half the size of the glibc images I came up with, but runtime performance is a tad worse)
I'm not a fan of chainguard/wolfi due to the lack of version pinning. Debian is a bit more of a pain to be competitive.
If you'd like some insights/advice regarding techniques or with Chisel based images, you may like this discussion thread as a reference. However for many projects you don't need the complexity and can often use Google Distroless if no extra packages are needed (otherwise chisel or fedora are pretty good for glibc).
KonradHoeffner commentedon May 2, 2025
Thanks for the link! I do not need any extra packages for the project which caused this issue because all I'm doing is wrapping a single executable binary compiled with Rust but I'm sure that will come up in the future in another project, so I will use that as a reference.