UPXによる圧縮されたネイティブ実行可能ファイルのビルド
UPXは、1996年に開発されたオープンソースのポータブルで高性能な 実行可能ファイルパッカー です。実行可能ファイルを入力に、圧縮された実行可能ファイルを出力します。昔、フロッピー・ディスクに収めるためにプログラムを圧縮する必要があった頃、 _ある_年代の読者はすでにUPXを使っていたかもしれません。20年以上経った今でも、UPXは健在です。
Quarkus 2.6では、UPX圧縮をQuarkusのビルドに統合しました。これにより、Quarkusは自動的に圧縮された実行可能ファイルを作成することができます。この記事では、この新機能の使い方を説明します。しかし、先に進む前に、 無料で手に入るものはない ということを理解しておく必要があります。圧縮された実行可能ファイルは、ディスク上では小さくなりますが、メモリ使用量は多くなります。そのため、使用する前に必ず「大きな警告」の項目をお読みください。
準備
システムにUPXがインストールされているか、コンテナ内ビルドを使用している場合、Quarkusは実行可能ファイルを圧縮できます。
UPXはほとんどのOSで利用できます。そのため、 リリースページからダウンロードできるはずです。UPXはクロスプラットフォームです。そのため、macOSやWindowsマシンからでも、Linux 64ビットの実行可能ファイルを圧縮することができます。
UPXをインストールすることができない場合は、Quarkusにコンテナ内ビルド( -Dquarkus.native.container-build=true
)を使用してネイティブ実行可能ファイルをビルドするように依頼することができます。Linux 64ビットの実行可能ファイルが得られます(コンテナには最適ですが、Linuxを使用していない場合は自分のマシンからは使用できません)。コンテナ内ビルドでは、実行可能ファイルを圧縮できるように UPX を提供しています。コンテナ内ビルドを使用する場合は、あなたのマシンにGraalVMやUPXは必要ありません。このオプションは、特にCI上で興味深いものです。
この記事では、最初のアプローチを使用します。 ネイティブ実行可能ファイルの構築のページでは、コンテナ内ビルドを使用する方法を説明しています。
圧縮するものを準備
まず、アプリケーションが必要です。簡単にするために、 https://code.quarkus.io/?a=upx-compression-demo&e=resteasy-reactive-jacksoncode.quarkus.io から新しいアプリケーションを作ってみましょう。このアプリケーションはRESTEasy ReactiveとそのJacksonサポートを使用していますが、圧縮はどのようなプロジェクトでも機能するので、コードを見ることもしません。
UPX を使用する前に、圧縮されていないネイティブ実行可能ファイルのディスク容量とメモリ使用量を測定する必要があります。そのためには、ネイティブ実行可能ファイルが必要です。
> ./mvnw package -Dnative
結果、実行可能ファイルは46MBのディスクスペースを使用します。
.rwxr-xr-x 46M clement 11 Dec 17:44 upx-compression-demo-1.0.0-SNAPSHOT-runner
では、メモリの消費量を見てみましょう。次のコマンドを使ってアプリケーションを起動します。
> ./target/upx-compression-demo-1.0.0-SNAPSHOT-runner
別の端末で、curlを使ってアプリケーションを起動し、そのメモリ使用量を取得します。
> curl http://localhost:8080/hello
Hello RESTEasy Reactive%
> rss runner
PID 0M COMMAND
3947 21M ./target/upx-compression-demo-1.0.0-SNAPSHOT-runner
そのため、基本的には使用するRAMの量である RSSを21MB使用します。
rss コマンドは以下の関数です。
|
rss () {
pgrep $1 | xargs ps -o pid,rss,command -p | awk '{$2=int($2/1024)"M";}{ print;}'
}
RSSとその測定方法については、 Quarkus - パフォーマンスの計測をご覧ください。
圧縮設定
実行可能ファイルを圧縮するには、圧縮レベルを設定する必要があります。圧縮率は1から10まであります。
-
1
: より速い圧縮 -
9
: より高い圧縮率 -
10
: 最高の圧縮率(大きなファイルでは遅い場合があります。)
application.properties
ファイルからレベルを設定します。
quarkus.native.compression.level=7
これだけで圧縮が有効になります。
圧縮されたネイティブ実行可能ファイルのビルド
ネイティブ実行可能ファイルを再生成してみましょう。今回は、設定された圧縮レベルのため、Quarkusが圧縮します。
> ./mvnw package -Dnative
...
...
[INFO] [io.quarkus.deployment.pkg.steps.UpxCompressionBuildStep] Executing /usr/local/bin/upx -7 /Users/clement/Downloads/upx-compression-demo/target/upx-compression-demo-1.0.0-SNAPSHOT-runner
Ultimate Packer for eXecutables
Copyright (C) 1996 - 2020
UPX 3.96 Markus Oberhumer, Laszlo Molnar & John Reiser Jan 23rd 2020
File size Ratio Format Name
-------------------- ------ ----------- -----------
46242352 -> 14774288 31.95% macho/amd64 upx-compression-demo-1.0.0-SNAPSHOT-runner
...
ご覧の通り、今回はUPXを実行してネイティブ実行可能ファイルを圧縮しています。サイズを確認すると、15MB前後のものが出てくるはずです。
.rwxr-xr-x 15M clement 11 Dec 18:03 upx-compression-demo-1.0.0-SNAPSHOT-runner
46Mから15Mになりました。これは、フロッピーディスクに収まらないとはいえ、かなりの収穫です。
大きな 警告
しかし、冒頭で述べたように、タダで手に入るものはありません。先ほど、圧縮されていない実行可能ファイルのメモリ使用量(21MB)も測定しました。圧縮した実行可能ファイルと比較してみましょう。
次のコマンドでアプリケーションを実行します。
> ./target/upx-compression-demo-1.0.0-SNAPSHOT-runner
そして、別の端末で、次を実行します。
> curl http://localhost:8080/hello
Hello RESTEasy Reactive%
> rss runner
PID 0M COMMAND
4501 57M ./target/upx-compression-demo-1.0.0-SNAPSHOT-runner
57MB! つまり、圧縮されていない実行可能ファイルに比べて2.7倍ものRSSを使用していることになります。このオーバーヘッドは、圧縮された実行可能ファイルが起動時にプログラムを解凍してメモリに格納しなければならないためです。また、起動時間が長くなることもありますが、この起動時のオーバーヘッドはほとんどの場合、重要ではありません。
概要
UPXを使用すると、ネイティブ実行可能ファイルを圧縮することができます。Quarkus 2.6では、圧縮レベルを設定するだけで、自動的に圧縮してくれます。
しかし、すべてが無料で手に入るとは思わないでください。ディスクスペースを得るのは素晴らしいものですが、RSSのオーバーヘッドを無視してはいけません。
UPXの圧縮は、CLIツールや、ディスク・スペースが限られたリソースである環境にメリットをもたらします。長時間稼働するアプリケーションやマイクロサービスでは、RSSのオーバーヘッドがデプロイメント密度を低下させます。そのため、ストレージに問題がない場合や、デプロイの密度が重要な場合は、実行可能ファイルを圧縮しない方がよいでしょう。