dgiagio / warp

Create self-contained single binary applications
MIT License
1.92k stars 92 forks source link

Support linux-musl-x64 #50

Open r734 opened 4 years ago

r734 commented 4 years ago

I'd like to be able to use Warp with .NET Core to target linux-musl-x64. Right now only linux-x64 is supported.

Support for linux-musl-x64 would allow me to layer binaries onto the mcr.microsoft.com/dotnet/core/runtime-deps:3.1-alpine container.

This would save over 100 (!) MB in container size compared to the Debian-based runtime-deps container, bringing the total to around 23 MB (10 for container, 13 for binary) for a basic Hello World application.

And that would be really lightweight.

peterhirn commented 4 years ago

I just hacked this, using https://github.com/emk/rust-musl-builder to cross-compile warp.

I'm building a F# project + dependency on https://github.com/Hopac/Hopac, so my assembly is quite a bit larger than what a C# hello-world would yield (published ~46M, packed ~20M).

Relevant .fsproj properties:

<PublishTrimmed>true</PublishTrimmed>
<PublishSingleFile>true</PublishSingleFile>

warp-musl.patch:

diff --git "a/warp-packer/src/main.rs" "b/warp-packer/src/main.rs"
index 616ae45..d361da4 100644
--- "a/warp-packer/src/main.rs"
+++ "b/warp-packer/src/main.rs"
@@ -27,16 +27,16 @@ const VERSION: &str = env!("CARGO_PKG_VERSION");

 const RUNNER_MAGIC: &[u8] = b"tVQhhsFFlGGD3oWV4lEPST8I8FEPP54IM0q7daes4E1y3p2U2wlJRYmWmjPYfkhZ0PlT14Ls0j8fdDkoj33f2BlRJavLj3mWGibJsGt5uLAtrCDtvxikZ8UX2mQDCrgE\0";

-const RUNNER_LINUX_X64: &[u8] = include_bytes!("../../target/x86_64-unknown-linux-gnu/release/warp-runner");
-const RUNNER_MACOS_X64: &[u8] = include_bytes!("../../target/x86_64-apple-darwin/release/warp-runner");
-const RUNNER_WINDOWS_X64: &[u8] = include_bytes!("../../target/x86_64-pc-windows-gnu/release/warp-runner.exe");
+const RUNNER_LINUX_X64: &[u8] = include_bytes!("../../target/x86_64-unknown-linux-musl/release/warp-runner");
+//const RUNNER_MACOS_X64: &[u8] = include_bytes!("../../target/x86_64-apple-darwin/release/warp-runner");
+//const RUNNER_WINDOWS_X64: &[u8] = include_bytes!("../../target/x86_64-pc-windows-gnu/release/warp-runner.exe");

 lazy_static! {
     static ref RUNNER_BY_ARCH: HashMap<&'static str, &'static [u8]> = {
         let mut m = HashMap::new();
         m.insert("linux-x64", RUNNER_LINUX_X64);
-        m.insert("macos-x64", RUNNER_MACOS_X64);
-        m.insert("windows-x64", RUNNER_WINDOWS_X64);
+        //m.insert("macos-x64", RUNNER_MACOS_X64);
+        //m.insert("windows-x64", RUNNER_WINDOWS_X64);
         m
     };
 }

Dockerfile:

ARG FRAMEWORK=netcoreapp3.1
ARG RUNTIME=linux-musl-x64
ARG RUST_TARGET=x86_64-unknown-linux-musl

ARG WARP_VERSION=0.3.0
ARG WARP_PATH=/usr/local/bin/warp-packer

#---
FROM mcr.microsoft.com/dotnet/core/sdk:3.1-alpine as dotnet

ENV DOTNET_CLI_TELEMETRY_OPTOUT=1
ENV PATH="/root/.dotnet/tools:${PATH}"

RUN dotnet tool install paket -g

#---
FROM dotnet as restore
WORKDIR /build

COPY paket.dependencies .
COPY paket.lock .
RUN paket restore

#---
FROM restore as build

COPY App.sln App.sln
COPY App/ App/

ARG RUNTIME
RUN dotnet publish -c Release -r ${RUNTIME}

#---
FROM ekidd/rust-musl-builder as packer-build

ARG WARP_VERSION
ARG RUST_TARGET
ARG PATCH_FILE=/tmp/warp-musl.patch

COPY warp-musl.patch ${PATCH_FILE}
RUN git clone -v --depth 1 --single-branch --branch v${WARP_VERSION} https://github.com/dgiagio/warp . \
    && patch ~/src/warp-packer/src/main.rs ${PATCH_FILE} \
    && cargo build --release --target=${RUST_TARGET}

#---
FROM alpine:3.11 as packer

ARG RUST_TARGET
ARG WARP_PATH
COPY --from=packer-build /home/rust/src/target/${RUST_TARGET}/release/warp-packer ${WARP_PATH}

ARG FRAMEWORK
ARG RUNTIME
COPY --from=build /build/App/bin/Release/${FRAMEWORK}/${RUNTIME}/publish /publish

WORKDIR /pack
RUN warp-packer \
    --arch linux-x64 \
    --input_dir /publish \
    --exec App \
    --output App

#---
FROM mcr.microsoft.com/dotnet/core/runtime-deps:3.1-alpine as runtime-packed
COPY --from=packer /pack/App .

#---
FROM mcr.microsoft.com/dotnet/core/runtime-deps:3.1-alpine as runtime-published

ARG FRAMEWORK
ARG RUNTIME
COPY --from=build /build/App/bin/Release/${FRAMEWORK}/${RUNTIME}/publish/App App

Comparing the image sizes:

REPOSITORY                                   TAG                     IMAGE ID            CREATED             SIZE
runtime-published                            latest                  0bb788223154        16 minutes ago      58.1MB
runtime-packed                               latest                  591241270919        16 minutes ago      30.4MB

It took me a while to realize that just running the App (published or packed) will immediately increase the image to >100M.

r734 commented 4 years ago

Awesome, I'll have to try that out--thanks!

Would still be nice to see it officially supported, so I'll leave the issue open.