🤞
Bun 1.2 の Single-file executable を Docker で動かす方法
元々 Bun は Bundler としての機能を持っているため import しているファイルを1つのファイルにまとめて実行ファイルにする機能があったのですが、Bun 1.2 でクロスコンパイルに対応したため、ローカルの ARM マシンの MacBook Pro から Linux 向けの実行ファイルを作成できるようになりました。
そのため、マルチステージでわざわざ bun install でファイルを取ってきたりコンパイルしたりする必要はなくなり便利になりました。
Standalone executables
You can use bun build --compile to compile your application, and Bun, into a standalone executable.
スタンドアロン実行ファイル
bun build --compile を使用して、アプリケーションと Bun をスタンドアロン実行ファイルにコンパイルできます。Bun 1.2 では、クロスコンパイルのサポートが追加されました。
In Bun 1.2, we've added support for cross-compilation. This allows you to build a Windows or macOS binary on a Linux machine, and vice versa.
これにより、Linux マシンで Windows または macOS バイナリをビルドでき、その逆も可能です。
この記事では作成した実行ファイルから Docker コンテナイメージを作成するところまで説明しています。
環境: MacBook Pro (M2 Pro)
bun build --compile --target=bun-linux-x64-baseline
新規ディレクトリで bun init
を実行し、以下のような index.ts ファイルを用意します。
index.ts
Bun.serve({
hostname: "0.0.0.0",
fetch: () => new Response("ok"),
})
以下のコマンドで dist/server
という実行ファイルを作成します。
bun build ./index.ts --compile --target=bun-linux-x64-baseline --outfile dist/server
Dockerfile
Dockerfile は oven/bun:1 をベースにしてもいいのですが、いらないファイルもそこそこ含まれていたので、筆者の検証の限りは /lib/x86_64-linux-gnu
と /lib64/ld-linux-x86-64.so.2
だけあればとりあえずは困りませんでした。
利用する機能によってはもっと /lib/x86_64-linux-gnu
内をスリムにできると思いますが、実行ファイルの方が大きいためこれ以上の最適化は行いませんでした。
FROM scratch
COPY /lib/x86_64-linux-gnu /lib/x86_64-linux-gnu
COPY /lib64/ld-linux-x86-64.so.2 /lib64/ld-linux-x86-64.so.2
WORKDIR /app
COPY ./dist/server /app/server
CMD ["/app/server"]
docker build --platform=linux/amd64 -t server:latest .
あとは、好きなコンテナプラットフォームで動作させるだけです。
まとめ
なお、ネイティブモジュールを含む場合大丈夫なのか、とかそこまでは検証していないので、利用する際は気をつけてください。
その他の細かいことは、公式ドキュメントを参照してください。
Discussion