こんにちは!Findy Team+開発チームでEMをしているhamです。
今年もRubyKaigi 2025に参加してきました。 私はコロナ後に三重県で開催されたときから4年連続で参加しているのですが、今年も興味深いセッションがたくさんあり、Rubyが着実に進化していることを感じることができました!
本記事では、その中の1つである「The Ruby One-Binary Tool, Enhanced with Kompo」で紹介された「Kompo」について、実際に試してみた結果と所感を紹介します。
Kompoとは
Kompoとは、READMEで「A tool to pack Ruby and Ruby scripts in one binary.」と紹介されている通り、Rubyスクリプトをバイナリにして配布できるツールです。 Rubyのスクリプトをバイナリにすることで、配布が容易になったり、実行環境にRubyのインストールが不要になるため配布先での実行が容易になります。
Kompoは2024年のRubyKaigiでも「It's about time to pack Ruby and Ruby scripts in one binary」のセッションで紹介されており、興味を持っていました。
2024年の時点ではRailsなどの大きなGemは実行できていないとのことだったのですが、2025年の発表ではRailsが動いており進化を感じました!
'Hello, world!'を返すスクリプト
今回のセッションでRailsが動作するようになったと発表されていたので、Webサーバーが動作するバイナリを作ってみることにしました。 とはいえ、最初から大きなものを作ろうとすると詰まる可能性が高いです。何事もスモールスタートが良いですね。
入門といえば 'Hello, world!'ということで、まずは'Hello, world!'を返却するRubyスクリプトでトライしました。
なお、ここからの内容は執筆時点(2025年4月)の情報なので最新版では変更されている可能性があります。
kompo-vfs
Kompoは内部で仮想ファイルシステムを使っているとのことです。
当初は既存のライブラリで実現できないか検討したとのことですが、Kompoのやりたいことにマッチするものがなかったとのことで「kompo-vfs」を自作したそうです。 リポジトリを見ていただければわかりますが、こちらはRustで書かれていました。
Kompoを使うにはまずkompo-vfsをbuildしておく必要があるとのことです。 READMEに沿って作業します。
READMEには次のように記載されています。(※手順はKompoのREADMEに記載されています)
## prerequisites Install [kompo-vfs](https://github.com/ahogappa/kompo-vfs). #### Homebrew $ brew tap ahogappa/kompo-vfs https://github.com/ahogappa/kompo-vfs.git $ brew install ahogappa/kompo-vfs/kompo-vfs ### Building To build komp-vfs, you need to have cargo installation. $ git clone https://github.com/ahogappa/kompo-vfs.git $ cd kompo-vfs $ cargo build --release Set environment variables. $ KOMPO_CLI=/path/to/kompo-vfs/target/release/kompo-cli $ LIB_KOMPO_DIR=/path/to/kompo-vfs/target/release
MacBookを使っているのでbrewの手順を試しましたがうまくいかなかったので、リポジトリをcloneする方法で実施しました。
mainブランチで試してみましたが、buildがエラーになりました。
% cargo build --release ... error: could not compile `kompo_storage` (lib) due to 2 previous errors; 1 warning emitted
こちら色々解析したところ、MacBookには対応してなさそうだとわかりました。 そこでDockerを立ち上げてその中でbuildすることにしました。 Kompoの実行もDockerで実施した方が良さそうだったので、Rubyイメージから作成しました。
# Dockerfile FROM ruby:3.4.3 # Install dependencies RUN apt-get update && apt-get install -y \ git \ build-essential \ libssl-dev \ zlib1g-dev \ libyaml-dev \ libgmp-dev \ libreadline-dev \ pkg-config \ autoconf \ bison \ curl \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* # Install latest Rust using rustup RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y ENV PATH="/root/.cargo/bin:${PATH}" # Set working directory WORKDIR /app # Copy project files COPY . /app/ # Install bundler and dependencies RUN gem install bundler && bundle install CMD ["tail", "-f", "/dev/null"]
buildしてbashでコンテナに入り、改めてbuildしたら成功しました🙌
% docker build -t hello-world . % docker run -it --rm -v .:/app hello-world bash root:/app# cd kompo-vfs/ root:/app/kompo-vfs# cargo build --release ... Finished `release` profile [optimized] target(s) in 5.40s
Kompo
次に'Hello, world!'を返すRubyスクリプトを作成します。
# hello.rb p 'Hello, world!'
Kompoはgemが公開されていないのでリポジトリをcloneしてローカルで生成します。
色々試行錯誤したのちに気づいたのですが、登壇スライドの26ページによるとkompoはfeature/use_rtld_next
の方が最新と思われるのでそちらを利用します。
Dockerコンテナ内でgem build
を実施して、無事kompo-0.2.0.gem
が生成できました。
root:/app/kompo# gem build kompo.gemspec WARNING: licenses is empty, but is recommended. Use an license identifier from https://spdx.org/licenses or 'Nonstandard' for a nonstandard license, or set it to nil if you don't want to specify a license. WARNING: open-ended dependency on mini_portile2 (>= 0) is not recommended use a bounded requirement, such as "~> x.y" WARNING: open-ended dependency on async (>= 0) is not recommended use a bounded requirement, such as "~> x.y" WARNING: You have specified the uri: https://github.com/ahogappa0613/kompo for all of the following keys: homepage_uri changelog_uri source_code_uri Only the first one will be shown on rubygems.org WARNING: See https://guides.rubygems.org/specification-reference/ for help Successfully built RubyGem Name: kompo Version: 0.2.0 File: kompo-0.2.0.gem
次に、Kompoをインストールします。
root:/app# gem install kompo/kompo-0.2.0.gem ... Successfully installed kompo-0.2.0 10 gems installed
時は来た!あとは梱包(Kompo)するだけです!実行には数分かかるので待ちます。
root:/app# kompo --help Usage: kompo [options] -e, --entrypoint=VAL File path to use for entry point. (default: './main.rb') -g, --use-group=VAL Group name to use with 'bundle install'. (default: 'default') --[no-]gemfile Use gem in Gemfile. (default: automatically true if Gemfile is present) --local-kompo-fs-dir=VAL --verbose Verbose mode. --dest-dir=VAL Output directry path. (default: current dir) --bundle-cache=VAL Specify the directory created by 'bundle install --standalone'. --ruby-version=VAL Specify Ruby version. (default: current Ruby version) --rebuild --repack root:/app# kompo -e hello.rb --local-kompo-fs-dir=kompo-vfs ... /usr/bin/ld: /app/kompo-vfs/target/release/libkompo_fs.a(529179467e613863-dummy_fs.o):(.rodata.WD+0x0): multiple definition of `WD'; /tmp/ccNwyWlB.o:(.rodata+0x0): first defined here /usr/bin/ld: /app/kompo-vfs/target/release/libkompo_fs.a(529179467e613863-dummy_fs.o):(.rodata.PATHS_SIZE+0x0): multiple definition of `PATHS_SIZE'; /tmp/ccNwyWlB.o:(.rodata+0x28): first defined here /usr/bin/ld: /app/kompo-vfs/target/release/libkompo_fs.a(529179467e613863-dummy_fs.o):(.rodata.PATHS+0x0): multiple definition of `PATHS'; /tmp/ccNwyWlB.o:(.rodata+0x30): first defined here /usr/bin/ld: /app/kompo-vfs/target/release/libkompo_fs.a(529179467e613863-dummy_fs.o):(.rodata.FILES_SIZE+0x0): multiple definition of `FILES_SIZE'; /tmp/ccNwyWlB.o:(.rodata+0x192c8): first defined here /usr/bin/ld: /app/kompo-vfs/target/release/libkompo_fs.a(529179467e613863-dummy_fs.o):(.rodata.FILES+0x0): multiple definition of `FILES'; /tmp/ccNwyWlB.o:(.rodata+0x192d0): first defined here collect2: error: ld returned 1 exit status /usr/local/bundle/gems/kompo-0.2.0/lib/kompo.rb:193:in 'Kernel#system': Command failed with exit 1: gcc (RuntimeError)
エラーが発生しました。
kompo-vfsで、WD
やPATHS
などの定義が重複しているようです。
Rustなんもわからんので雰囲気ですが、kompo-vfs/kompo_fs/dummy_fs.c
の中でWD
やPATHS
が定義されているので怒られた定義をコメントアウトして再buildしてやり直してみました。
// kompo-vfs/kompo_fs/dummy_fs.c // const char FILES[] = {}; // const int FILES_SIZE = 0; // const char PATHS[] = {}; // const int PATHS_SIZE = 0; // const char WD[] = {47,119,111,114,107,115,112,97,99,101,115,47,114,117,98,121,95,112,97,99,107,97,103,101,114,47, 0}; const char START_FILE_PATH[] = {46,47,109,97,105,110,46,114,98, 0};
再度Kompoを実行。今回は正常終了し、バイナリ(app
)が生成されました🎉
root:/app# kompo -e hello.rb --local-kompo-fs-dir=kompo-vfs ... info: Finish kompo! root:/app# ls -l app -rwxr-xr-x 1 root root 76437456 Apr 24 02:15 app root:/app# ./app "Hello, world!"
最後に実行します。せっかくなのでRubyが入っていない環境で実行します。
Dockerfileはこちらを使いました。
FROM ubuntu:latest # Set working directory WORKDIR /app # Copy project files COPY . /app/ CMD ["tail", "-f", "/dev/null"]
コンテナを立ち上げて、バイナリを実行します。 Rubyが入っていない環境で実行できました🎉
% docker build -t ubuntu-app . % docker run -it --rm -v .:/app ubuntu-app bash root@62df4e7aa257:/app# ./app "Hello, world!"
Rails
簡単なRubyスクリプトでは実行できることがわかったので、次はRailsに挑戦です!
ただ、結論は「色々試行錯誤したものの起動できず」でした...
Kompoするところでエラーになったり、Kompoはできたが起動できなかったり、これ以上の解析は難しいので今回は諦めました🙏
最後に
今回は簡単なRubyスクリプトしかできませんでしたが、ワンバイナリで配布してすぐに実行できることはとても便利だと感じました。今後の更なる進化に期待です!!
5/13(火)に、「After RubyKaigi 2025〜ZOZO、ファインディ、ピクシブ〜」として、ピクシブ株式会社、株式会社ZOZO、ファインディ株式会社の3社でRubyKaigi 2025の振り返りを行います。
LTやパネルディスカッションなどコンテンツ盛りだくさんなのでぜひご参加ください!!
https://pixiv.connpass.com/event/352852/pixiv.connpass.com
また、ファインディではこれからも新しいものを取り入れつつ、Rubyを積極的に活用してRubyとともに成長していければと考えております。
一緒に働くメンバーも絶賛募集中なので、興味がある方はぜひこちらから ↓