Skip to content

Instantly share code, notes, and snippets.

@JadedBlueEyes
Last active June 12, 2024 19:14
Show Gist options
  • Save JadedBlueEyes/bbe0b3a8ebeafb764a7a3a1fc4e5645f to your computer and use it in GitHub Desktop.
Save JadedBlueEyes/bbe0b3a8ebeafb764a7a3a1fc4e5645f to your computer and use it in GitHub Desktop.

So, your program has dependencies, like tokio or openSSL. All of your dependencies are kind of like mini-programs that can be compiled by themselves. But to be useful, your program needs to be able to find and call the functions in your dependencies. To do this, a program called a linker exists - it effectively adds your program and all of your dependencies all together in one big file, and renames all the functions so that they call each other correctly.

You don't always want to include every dependency in your binary, though, so there are two sub-types of linking - static linking and dynamic linking. Static linking happens when you compile your program - by default, crates in Rust are statically linked. On the other hand, dynamic linking happens when the operating system tries to load your program. The system looks for all the libraries that your program says it needs, and links the versions it finds in.

Using a distroless base image gave you those errors because the dynamic linker couldn't find the libraries your binary said it needed. That's because not every dependency in a Rust program is statically linked by default. The one you'll hear about the most is libc - effectively an API for interacting with the operating system - but that wasn't the one causing the issues, as it's included in 'distroless' images. The one that was missing was OpenSSL.

In your Cargo.toml, you've included sqlx as sqlx = {version = "0.7.4", features = ["runtime-async-std-native-tls","postgres"]}. You're telling it to use native-tls - a crate that uses the TLS library considered native on a particular OS. On linux, that's OpenSSL, and by default the openssl crate dynamically links to the OpenSSL library included on the system. You can instruct it to statically link OpenSSL by adding the "vendored" feature.

RUSTFLAGS='-C target-feature=+crt-static' instructs the Rust compiler to statically link the C Run Time - libc. This (or building for the target x86_64-unknown-linux-musl, which uses musl as libc, which then gets statically linked by default) is needed to run in a from scratch container, because a libc is not included by default in a from scratch image. It also seems to make the compiler statically link any other libraries by default.

You can use the ldd command to print out all the libraries that a program will dynamically link to. If you run it on a binary build with crt-static, it should output statically linked, whilst your program built without that outputs this:

        linux-vdso.so.1 (0x00007ffed5fd2000)
        libssl.so.3 => /lib/x86_64-linux-gnu/libssl.so.3 (0x00007fa113b06000)
        libcrypto.so.3 => /lib/x86_64-linux-gnu/libcrypto.so.3 (0x00007fa113684000)
        libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007fa113664000)
        libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007fa113585000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fa1133a4000)
        /lib64/ld-linux-x86-64.so.2 (0x00007fa113f36000)
FROM rust:latest as builder
WORKDIR /app
COPY . .
# ENV RUSTFLAGS='-C target-feature=+crt-static'
RUN --mount=type=cache,target=/usr/local/cargo/registry \
--mount=type=cache,target=/app/target \
cargo build --release --target x86_64-unknown-linux-gnu && \
cp ./target/x86_64-unknown-linux-gnu/release/mb-exurl-ia-service /mb-exurl-ia-service
RUN mkdir /libs-to-copy/
RUN ldd "/mb-exurl-ia-service" | awk '{print $(NF-1)}' | grep -v -e "linux-vdso" -e "ld-linux" | xargs -I {} cp {} /libs-to-copy
RUN ls -r /libs-to-copy/
FROM scratch
WORKDIR /app
COPY --from=builder /mb-exurl-ia-service ./app
COPY --from=builder /libs-to-copy/ /lib/
COPY --from=builder /lib64/ld-linux-x86-64.so.2 /lib64/ld-linux-x86-64.so.2
CMD ["/app/app"]
FROM rust:latest as builder
WORKDIR /app
COPY . .
RUN --mount=type=cache,target=/usr/local/cargo/registry \
--mount=type=cache,target=/app/target \
cargo build --release --target x86_64-unknown-linux-gnu && \
cp ./target/x86_64-unknown-linux-gnu/release/mb-exurl-ia-service /mb-exurl-ia-service
RUN ldd "/mb-exurl-ia-service"
FROM scratch
WORKDIR /app
COPY --from=builder /mb-exurl-ia-service ./app
COPY --from=builder /lib/x86_64-linux-gnu/ /lib/x86_64-linux-gnu/
COPY --from=builder /lib64/ld-linux-x86-64.so.2 /lib64/ld-linux-x86-64.so.2
CMD ["/app/app"]
FROM rust:latest as builder
WORKDIR /app
COPY . .
ENV RUSTFLAGS='-C target-feature=+crt-static'
RUN --mount=type=cache,target=/usr/local/cargo/registry \
--mount=type=cache,target=/app/target \
cargo build --release --target x86_64-unknown-linux-gnu && \
cp ./target/x86_64-unknown-linux-gnu/release/mb-exurl-ia-service /mb-exurl-ia-service
RUN ldd "/mb-exurl-ia-service"
FROM scratch
WORKDIR /app
COPY --from=builder /mb-exurl-ia-service ./app
CMD ["/app/app"]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment