innerblog rust-docker

Docker “FROM scratch” for Rust Applications

14 Nov, 2022

One of the benefits of using Rust is the possibility of building fully statically linked binaries. Those binaries can run in a Docker container that is created from an empty image instead of a Linux distribution. These images are built “FROM scratch”. scratch is also used as a starting point to base images for Debian and busboy.

With a “FROM scratch”-image, your executable runs in an empty container, which includes nothing but the absolute minimum for the program to work. One benefit is the image's tiny size. Another is that it isolates the execution environment of a process. Even if an attacker successfully hacks your software, they find themselves in an empty container with no further exploitable software.

In our example Dockerfile below, we’re building a Rust binary with SQLite, OpenSSL, and PostgreSQL as additional dependencies. They all have to be linked statically to work in a “FROM scratch”-image.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
FROM docker.io/library/rust:1.62-alpine as builder
RUN apk add --no-cache musl-dev sqlite-static openssl-dev openssl-libs-static pkgconf git libpq-dev

# Set `SYSROOT` to a dummy path (default is /usr) because pkg-config-rs *always*
# links those located in that path dynamically but we want static linking, c.f.
# https://github.com/rust-lang/pkg-config-rs/blob/54325785816695df031cef3b26b6a9a203bbc01b/src/lib.rs#L613
ENV SYSROOT=/dummy

# The env vars tell libsqlite3-sys to statically link libsqlite3.
ENV SQLITE3_STATIC=1 SQLITE3_LIB_DIR=/usr/lib/

# The env var tells pkg-config-rs to statically link libpq.
ENV LIBPQ_STATIC=1

WORKDIR /wd
COPY . /wd
RUN cargo build --bins --release

FROM scratch
ARG version=unknown
ARG release=unreleased
LABEL name="Product Name" \
      maintainer="info@company.com" \
      vendor="Company AG" \
      version=${version} \
      release=${release} \
      summary="High-level summary" \
      description="A bit more details about this specific container"

COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt
COPY --from=builder /wd/target/release/binaryName /
CMD ["./binaryName"]

Build the image using Podman: podman build --file Dockerfile --tag image:tag --build-arg version=1.1 --build-arg release=1

Build the image using Docker: docker build --tag image:tag --build-arg version=1.1 --build-arg release=1 .

And lastly, build this image automatically with your GitLab-Runner CI on every push to master, every new git tag, and the option to trigger the build on a merge request in GitLab’s UI:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
stages:
  - docker

build-docker-scratch:
  variables:
    GIT_DEPTH: 500
  stage: docker
  image:
    name: alpine:3.16.2
  script:
    - apk add podman
    - DOCKER_TAG_NAME="${CI_COMMIT_TAG:-master}"
    - podman build --file $CI_PROJECT_DIR/Dockerfile --tag $CI_REGISTRY_IMAGE:$DOCKER_TAG_NAME --build-arg version=$DOCKER_TAG_NAME --build-arg release=$DOCKER_TAG_NAME --target void
    - podman login --tls-verify --username "$CI_REGISTRY_USER" --password "$CI_REGISTRY_PASSWORD" "$CI_REGISTRY"
    - podman push --tls-verify $CI_REGISTRY_IMAGE:$DOCKER_TAG_NAME
  rules:
    - if: '$CI_COMMIT_REF_NAME == "master"'
    - if: '$CI_COMMIT_TAG != null'
    - if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
      when: manual
      allow_failure: true

This allows us to build tiny, secure container images for 21 Analytics' software. The images are immediately available on the registry to deploy and use in other steps of the CI/CD. If you have any feedback or questions, don't hesitate to get in touch with us.

Info Circle Outlined Icon

Disclaimer

This material is provided for educational and informational purposes only and is not intended to be a substitute for professional advice or detailed research.

Written by:
Lucas Author Picture
Before founding 21 Analytics, Lucas was Team Lead Crypto Assets at the Swiss consulting & development firm Inacta. He is president of the Bitcoin Association Switzerland, founder of the Bitcoin education initiative 21 Lectures, and a frequent lecturer at various universities, such as HSLU and ZfU. Lucas is involved in Bitcoin since early 2013.