16

I am attempting to compile a rust binary in docker but the compilation fails saying openssl is not found despite it being installed. Other answers suggest that having pkg-config and libssl-dev installed resolves the issue, but they already are installed. I believe this issue is related to cross compilation as I have been able to get this image built when the host and target are the same.

Dockerfile:

FROM rust:1.57.0 AS build
WORKDIR /usr/src

RUN rustup target add x86_64-unknown-linux-musl

RUN USER=root cargo new project
WORKDIR /usr/src/project
COPY Cargo.toml Cargo.lock ./
RUN apt-get update \
&& apt-get upgrade \
&& apt-get install -y cmake pkg-config libssl-dev
RUN cargo build --release

Error:

#18 14.01    Compiling openssl-sys v0.9.72
#18 14.17 error: failed to run custom build command for `openssl-sys v0.9.72`
#18 14.18 
#18 14.18 Caused by:
#18 14.18   process didn't exit successfully: `/usr/src/project/target/release/build/openssl-sys-64e55e6c4223d7aa/build-script-main` (exit status: 101)
#18 14.18   --- stdout
#18 14.18   cargo:rustc-cfg=const_fn
#18 14.18   cargo:rerun-if-env-changed=X86_64_UNKNOWN_LINUX_MUSL_OPENSSL_LIB_DIR
#18 14.18   X86_64_UNKNOWN_LINUX_MUSL_OPENSSL_LIB_DIR unset
#18 14.18   cargo:rerun-if-env-changed=OPENSSL_LIB_DIR
#18 14.18   OPENSSL_LIB_DIR unset
#18 14.18   cargo:rerun-if-env-changed=X86_64_UNKNOWN_LINUX_MUSL_OPENSSL_INCLUDE_DIR
#18 14.18   X86_64_UNKNOWN_LINUX_MUSL_OPENSSL_INCLUDE_DIR unset
#18 14.18   cargo:rerun-if-env-changed=OPENSSL_INCLUDE_DIR
#18 14.18   OPENSSL_INCLUDE_DIR unset
#18 14.18   cargo:rerun-if-env-changed=X86_64_UNKNOWN_LINUX_MUSL_OPENSSL_DIR
#18 14.18   X86_64_UNKNOWN_LINUX_MUSL_OPENSSL_DIR unset
#18 14.18   cargo:rerun-if-env-changed=OPENSSL_DIR
#18 14.18   OPENSSL_DIR unset
#18 14.18   cargo:rerun-if-env-changed=OPENSSL_NO_PKG_CONFIG
#18 14.18   cargo:rerun-if-env-changed=PKG_CONFIG_ALLOW_CROSS_x86_64-unknown-linux-musl
#18 14.18   cargo:rerun-if-env-changed=PKG_CONFIG_ALLOW_CROSS_x86_64_unknown_linux_musl
#18 14.18   cargo:rerun-if-env-changed=TARGET_PKG_CONFIG_ALLOW_CROSS
#18 14.18   cargo:rerun-if-env-changed=PKG_CONFIG_ALLOW_CROSS
#18 14.18   cargo:rerun-if-env-changed=PKG_CONFIG_x86_64-unknown-linux-musl
#18 14.18   cargo:rerun-if-env-changed=PKG_CONFIG_x86_64_unknown_linux_musl
#18 14.18   cargo:rerun-if-env-changed=TARGET_PKG_CONFIG
#18 14.18   cargo:rerun-if-env-changed=PKG_CONFIG
#18 14.18   cargo:rerun-if-env-changed=PKG_CONFIG_SYSROOT_DIR_x86_64-unknown-linux-musl
#18 14.18   cargo:rerun-if-env-changed=PKG_CONFIG_SYSROOT_DIR_x86_64_unknown_linux_musl
#18 14.18   cargo:rerun-if-env-changed=TARGET_PKG_CONFIG_SYSROOT_DIR
#18 14.18   cargo:rerun-if-env-changed=PKG_CONFIG_SYSROOT_DIR
#18 14.18   run pkg_config fail: "pkg-config has not been configured to support cross-compilation.\n\nInstall a sysroot for the target platform and configure it via\nPKG_CONFIG_SYSROOT_DIR and PKG_CONFIG_PATH, or install a\ncross-compiling wrapper for pkg-config and set it via\nPKG_CONFIG environment variable."
#18 14.18 
#18 14.18   --- stderr
#18 14.18   thread 'main' panicked at '
#18 14.18 
#18 14.18   Could not find directory of OpenSSL installation, and this `-sys` crate cannot
#18 14.18   proceed without this knowledge. If OpenSSL is installed and this crate had
#18 14.18   trouble finding it,  you can set the `OPENSSL_DIR` environment variable for the
#18 14.18   compilation process.
#18 14.18 
#18 14.18   Make sure you also have the development packages of openssl installed.
#18 14.18   For example, `libssl-dev` on Ubuntu or `openssl-devel` on Fedora.
#18 14.18 
#18 14.18   If you're in a situation where you think the directory *should* be found
#18 14.18   automatically, please open a bug at https://github.com/sfackler/rust-openssl
#18 14.18   and include information about your system as well as this message.
#18 14.18 
#18 14.18   $HOST = aarch64-unknown-linux-gnu
#18 14.18   $TARGET = x86_64-unknown-linux-musl
#18 14.18   openssl-sys = 0.9.72
#18 14.18 
#18 14.18   ', /usr/local/cargo/registry/src/github.com-1ecc6299db9ec823/openssl-sys-0.9.72/build/find_normal.rs:180:5
Qwertie
  • 5,784
  • 12
  • 45
  • 89
  • 2
    You need to install libraries for the *target* architecture. – n. m. could be an AI Jan 03 '22 at 07:38
  • @n.1.8e9-where's-my-sharem. Do you have any idea on how? I have attempted to install the package with `libssl-dev:amd64` but this did not seem to work either. – Qwertie Jan 03 '22 at 10:05
  • No idea, maybe look at this? https://askubuntu.com/questions/430705/how-to-use-apt-get-to-download-multi-arch-library – n. m. could be an AI Jan 03 '22 at 10:33
  • 1
    What architecture is this targeting? When using [`cross`](https://github.com/rust-embedded/cross) to target `arm-unknown-linux-gnueabi` from `x86_64-unknown-linux` I had to hunt down a header file and link it manually to the package config folder for the target triple. I can take a look at my docker containers later and see if I can point you in the right direction if you're having the same issues. – MeetTitan Jan 03 '22 at 13:57
  • @MeetTitan I'm attempting to target linux x86_64 but I'm building on an M1 Mac – Qwertie Jan 03 '22 at 21:16
  • looks like you dont have `apt install -y pkg-config` – Dinesh Feb 12 '23 at 23:56

1 Answers1

7

You are correct that the issue is related to cross compilation. You are compiling on a Debian container, and it doesn't have a MUSL library to compile against.

You have two options:

  1. Tell the Rust openssl crate to compile a vendored openssl.
  2. Compile on an Alpine container.

Option 1: Use a vendored openssl

Let's say we start with the example from reqwest:

use std::collections::HashMap;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let resp = reqwest::get("https://httpbin.org/ip")
        .await?
        .json::<HashMap<String, String>>()
        .await?;
    println!("{:#?}", resp);
    Ok(())
}

and Cargo.toml has dependencies:

[dependencies]
reqwest = { version = "0.11", features = ["json"] }
tokio = { version = "1", features = ["full"] }

We start with a reasonable default Dockerfile:

FROM rust:latest as build

RUN rustup target add x86_64-unknown-linux-musl
RUN apt-get update && apt-get install -y musl-tools

COPY . /app
WORKDIR /app

RUN cargo build --target=x86_64-unknown-linux-musl --release

When we build this with docker build . we get the same error you saw.

The solution is to add the following line to [dependencies] in Cargo.toml:

openssl = { version = "0.10", features = ["vendored"] }

This makes the openssl crate compile the C library itself for the x86_64-unknown-linux-musl target.

Note that there is no need to install libssl-dev or pkg-config in the build container.

Option 2: Build with an Alpine container

You can completely avoid the cross-compilation problems by compiling on an Alpine container.

With the original dependencies in Cargo.toml:

[dependencies]
reqwest = { version = "0.11", features = ["json"] }
tokio = { version = "1", features = ["full"] }

you can build using the following Dockerfile:

FROM rust:1.68-alpine as builder

RUN apk add openssl-dev musl-dev

COPY . /app
WORKDIR /app

RUN cargo build --release

We install openssl-dev in Alpine so that the openssl crate doesn't have to compile the library from source, and we install musl-dev so it can link to the C runtime.

Grandpa
  • 3,053
  • 1
  • 25
  • 35