diff --git a/Dockerfile.multistage-example b/Dockerfile.multistage-example new file mode 100644 index 0000000..aceac93 --- /dev/null +++ b/Dockerfile.multistage-example @@ -0,0 +1,24 @@ +# -*- mode: dockerfile -*- +# +# An example Dockerfile showing how to build a Rust executable using this +# image, and deploy it with a tiny Alpine Linux container. + +# Our first FROM statement declares the build environment. +FROM ekidd/rust-musl-builder AS builder + +# You would normally add your source code to /home/rust/src like this. +# ADD . ./ + +# ...but we're going to just create a new app instead for demo purposes. +RUN cd .. && rm -r src && USER=rust cargo new --vcs none --bin --name hello src + +# Build our application. +RUN cargo build --release + +# Now, we need to build our _real_ Docker container, copying in `hello`. +FROM alpine:latest +RUN apk --no-cache add ca-certificates +COPY --from=builder \ + /home/rust/src/target/x86_64-unknown-linux-musl/release/hello \ + /usr/local/bin/ +CMD /usr/local/bin/hello diff --git a/README.md b/README.md index be836f7..e4c411b 100644 --- a/README.md +++ b/README.md @@ -18,11 +18,7 @@ making final release builds. ## Deploying your Rust application -With a bit of luck, you should be able to just copy your application binary -from `target/x86_64-unknown-linux-musl/release`, and install it directly on -any reasonably modern x86_64 Linux machine. In particular, you should be -able to copy your Rust application into an -[Alpine Linux container][]. +With a bit of luck, you should be able to just copy your application binary from `target/x86_64-unknown-linux-musl/release`, and install it directly on any reasonably modern x86_64 Linux machine. In particular, you should be able make static release binaries using TravisCI and GitHub, or you can copy your Rust application into an [Alpine Linux container][]. See below for details! ## How it works @@ -50,32 +46,6 @@ fn main() { } ``` -## Adding more C libraries - -If you're using Docker crates which require specific C libraries to be -installed, you can create a Dockerfile based on this one, and use -`musl-gcc` to compile the libraries you need. For example: - -```Dockerfile -FROM ekidd/rust-musl-builder - -# EXAMPLE ONLY! libz is already included. -RUN VERS=1.2.11 && \ - cd /home/rust/libs && \ - curl -LO http://zlib.net/zlib-$VERS.tar.gz && \ - tar xzf zlib-$VERS.tar.gz && cd zlib-$VERS && \ - CC=musl-gcc ./configure --static --prefix=/usr/local/musl && \ - make && sudo make install && \ - cd .. && rm -rf zlib-$VERS.tar.gz zlib-$VERS -``` - -This usually involves a bit of experimentation for each new library, but it -seems to work well for most simple, standalone libraries. - -If you need an especially common library, please feel free to submit a pull -request adding it to the main `Dockerfile`! We'd like to support popular -Rust crates out of the box. - ## Making static releases with Travis CI and GitHub These instructions are inspired by [rust-cross][]. @@ -122,6 +92,42 @@ For a working example, see [faradayio/cage][cage]. [uploading]: https://docs.travis-ci.com/user/deployment/releases [cage]: https://github.com/faradayio/cage +## Making tiny Docker images with Alpine Linux and Rust binaries + +Docker now supports [multistage builds][multistage], which make it easy to +build your Rust application with `rust-musl-builder` and deploy it using +[Alpine Linux][]. For a working example, see +[`Dockerfile.multistage-example`](./Dockerfile.multistage-example). + +[multistage]: https://docs.docker.com/engine/userguide/eng-image/multistage-build/ +[Alpine Linux]: https://alpinelinux.org/ + +## Adding more C libraries + +If you're using Docker crates which require specific C libraries to be +installed, you can create a `Dockerfile` based on this one, and use +`musl-gcc` to compile the libraries you need. For example: + +```Dockerfile +FROM ekidd/rust-musl-builder + +# EXAMPLE ONLY! libz is already included. +RUN VERS=1.2.11 && \ + cd /home/rust/libs && \ + curl -LO http://zlib.net/zlib-$VERS.tar.gz && \ + tar xzf zlib-$VERS.tar.gz && cd zlib-$VERS && \ + CC=musl-gcc ./configure --static --prefix=/usr/local/musl && \ + make && sudo make install && \ + cd .. && rm -rf zlib-$VERS.tar.gz zlib-$VERS +``` + +This usually involves a bit of experimentation for each new library, but it +seems to work well for most simple, standalone libraries. + +If you need an especially common library, please feel free to submit a pull +request adding it to the main `Dockerfile`! We'd like to support popular +Rust crates out of the box. + ## Development notes After modifying the image, run `./test-image` to make sure that everything diff --git a/test-image b/test-image index 37d11bf..c4f1496 100755 --- a/test-image +++ b/test-image @@ -9,6 +9,10 @@ docker build -t ekidd/rust-musl-builder . # Make sure we can build our example derived container. docker build -t rust-musl-zlib -f Dockerfile.example . +# Make sure we can build a multi-stage container. +docker build -t rust-multistage-example -f Dockerfile.multistage-example . +docker run --rm rust-multistage-example + # Make sure we can build a static executable. docker run --rm ekidd/rust-musl-builder bash -c " set -euo pipefail