RubyKaigi 2025レポート:Rubyで作成したスクリプトをバイナリにして簡単に配布できるか試してみた

こんにちは!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の方が最新と思われるのでそちらを利用します。

Demo

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で、WDPATHSなどの定義が重複しているようです。

Rustなんもわからんので雰囲気ですが、kompo-vfs/kompo_fs/dummy_fs.cの中でWDPATHSが定義されているので怒られた定義をコメントアウトして再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とともに成長していければと考えております。

一緒に働くメンバーも絶賛募集中なので、興味がある方はぜひこちらから ↓

herp.careers