🦀

Rust の Docker イメージを小さくする方法

2024/04/16に公開

Rust で作ったアプリケーションを Docker でデプロイする際、イメージのサイズが大きくなってしまうことがあります。
今回は、そんな Rust の Docker イメージを小さくする方法をご紹介します。

TL;DR

  • distroless/static を使うことでイメージサイズを大幅に小さくできる
  • Rust の公式イメージの Alpine を使えば自動的に static にビルドしてくれる
  • 依存 crate をキャッシュしておくために空の main ファイルを作っておく

以下は、実際に使った Dockerfile です。

FROM rust:1.77.2-alpine as builder

RUN apk --no-cache add musl-dev

WORKDIR /app

COPY Cargo.toml .
COPY Cargo.lock .
RUN mkdir src && echo "fn main() {}" > src/main.rs
RUN cargo build --release

COPY src src
RUN touch src/main.rs
RUN cargo build --release
RUN strip target/release/myappname -o main

FROM gcr.io/distroless/static-debian12:nonroot
USER nonroot

WORKDIR /app

COPY --from=builder /app/main /app/main

ENTRYPOINT [ "/app/main" ]

ビルドには Alpine を使う

Rust の公式イメージには、Alpine ベースのものがあります。
Alpine は軽量な Linux ディストリビューションで、musl-libc を使っています。

Alpine ベースのイメージを使えば、自動的に static にビルドしてくれるので、配備先にライブラリがなくても大丈夫です。

さらに strip コマンドでオブジェクトファイルから余計な情報を削ぎ落としています。

依存 crate をキャッシュする

自分のコードを変えるたびに crate のダウンロードから始まるのは大変です。
そのため、依存 crate をキャッシュしておけるように、2ステップに分け、最初のビルドでは空の main ファイルを作っておくのがよいでしょう。

COPY Cargo.toml .
COPY Cargo.lock .
RUN mkdir src && echo "fn main() {}" > src/main.rs
RUN cargo build --release

こうすることで、依存 crate のビルドがキャッシュされるので、ビルド時間を短縮できます。

distroless/static を使う

Docker イメージを小さくする一番の方法は、不要なものを含めないことです。
そのためには、distroless の static イメージを使うのが効果的です。

distroless は、Google が提供しているイメージで、必要最低限のファイルしか含まれていません。
つまり、シェルやパッケージマネージャなどが含まれていないので、イメージサイズを大幅に小さくできるのです。

手元の例では、通常の Rust イメージを使った場合は 99MB だったのが、distroless/static を使うことで 4.5MB まで小さくなりました。

nonroot ユーザーを使う

セキュリティを向上させるためには、root ユーザーを使わないことが重要です。
distroless/static イメージには、nonroot というユーザーが用意されているので、それを使うのがよいでしょう。

FROM gcr.io/distroless/static-debian12:nonroot
USER nonroot

こうすることで、万が一コンテナ内でプロセスが乗っ取られても、被害を最小限に抑えられます。

まとめ

Rust で作ったアプリケーションの Docker イメージサイズが小さくなれば、デプロイが速くなったり、ストレージの節約になったりと、嬉しいことがたくさんあります。
また、nonroot ユーザーを使えば、セキュリティ面でも安心です。

ぜひ、みなさんも試してみてください。

Discussion