「RipGrep」(rg)を Alpine の Docker コンテナで動かす

RipGrep 入りの Alpine コンテナを作る Dockerfile とサンプルです。Intel アーキテクチャ1(Core i5、MacBook Pro)で動作確認しました。(残念ながらラズパイなどの ARM アーキテクチャには対応していません。ラズパイ(ARM)対応の実験がはじまったようです。)

#  Dockerfile to build RipGrep (rg) for Alpine linux image
#  via multi stage build
# =========================================================
# Note: As of 2019/02/06, rust-musl-builder is not compa-
#       tible to ARM architecture such as RaspberryPi.

# First stage (build)
# -------------------
FROM ekidd/rust-musl-builder:stable AS rg-build

WORKDIR /home/rust/src

RUN set -x &&\
    : "Cloning git from ripgrep repo" && \
    git clone https://github.com/BurntSushi/ripgrep && \
    : "Buildng ripgrep" && \
    cd ripgrep && \
    cargo build --release && \
    : "Show version" && \
    cd ./target/x86_64-unknown-linux-musl/release && \
    ./rg --version

# Second stage (copy)
# -------------------
FROM alpine AS ripgrep

COPY --from=rg-build \
     /home/rust/src/ripgrep/target/x86_64-unknown-linux-musl/release/rg \
     /usr/local/bin

Dockerイメージの作成例

$ ls
Dockerfile
$ # ビルド開始
$ docker build -t myripgrep .
(長いので省略)
Successfully built d2597650d47b
Successfully tagged ripgrep:latest
ラズパイで「standard_init_linux.go:190: exec user process caused “exec format error”」RaspberryPi でビルドすると「standard_init_linux.go:190: exec user process caused “exec format error”」

RaspberryPi3 などの ARM アーキテクチャの場合、Docker のビルド時に失敗してしまいます。これは、ekidd/rust-musl-builder のコンテナ自体が ARM 対応していないためです。コンテナ単体でも起動しません。

$ uname -a
Linux UTouchMyPi 4.14.41-v7+ #1113 SMP Thu May 17 16:29:48 BST 2018 armv7l GNU/Linux
$
$ docker pull ekidd/rust-musl-builder:stable
$ docker run –rm -it ekidd/rust-musl-builder:stable /bin/bash
standard_init_linux.go:190: exec user process caused “exec format error”

Issue にも上がっているのですが、「当面対応予定はない」とのこと。とほほ。

ripgrepイメージのサイズ

約 33MB になりました。

$ docker image ls | grep myripgrep
myripgrep           latest          d2597650d47b        2 hours ago         32.9MB

最初のステージで利用した Rust のバイナリ・ビルド環境の rust-musl-builder のサイズが大きいので、バイナリが出来上がったら rust-musl-builder のコンテナとイメージは削除してもいいかもしれません。

rgの基本構文

USAGE:
    rg [OPTIONS] PATTERN [PATH ...]
    rg [OPTIONS] [-e PATTERN ...] [-f PATTERNFILE ...] [PATH ...]
    rg [OPTIONS] --files [PATH ...]
    rg [OPTIONS] --type-list
    command | rg [OPTIONS] PATTERN

$ rg メキシコ ~/Documents のように $ rg 検索パターン 検索パス で検索できます。検索パターンは正規表現が利用可能です。検索パスを省略した場合は、カレントディレクトリ以下を検索します。

ホストのボリュームをマウントして検索する例

$ docker run --rm -it -v /path/to/you/local/dir:/data myripgrep /bin/sh
/ # # OS情報
/ # cat /etc/os-*
NAME="Alpine Linux"
ID=alpine
VERSION_ID=3.8.2
PRETTY_NAME="Alpine Linux v3.8"
HOME_URL="http://alpinelinux.org"
BUG_REPORT_URL="http://bugs.alpinelinux.org"
/ #
/ # # rg のバージョン確認
/ # rg --version
ripgrep 0.10.0 (rev 147e96914c)
-SIMD -AVX (compiled)
+SIMD +AVX (runtime)

/ # # rg の場所
/ # which rg
/usr/local/bin/rg
/ #
/ # # マウントしたディレクトリの確認
/ # ls /data
barge_test           gimp_test            php_test             sed_test
bash_test            git-sign_test        python_test          wav-for-test-sound
docker_test          git_test             reboot_test          word2vec_test
flutter_test         github-encrypt_test  ruby_test
gcc_test             go_test              scp-spams_test
/ #
/ # # ヘルプ表示
/ # rg --help
(長いので省略)
/ #
/ # # /data 内の「stdio.h」を含むファイルを検索
/ # rg stdio.h /data
/data/gcc_test/test.c
1:#include <stdio.h>
/ #
/ # # /data 内の「メキシコ」を含むファイルを検索
/ # rg メキシコ /data
/data/word2vec_test/DIC_KANA.original.csv
2654:あめりかめきしこせんそう Mexican-American War 名詞 アメリカメキシコ戦争
27414:ニューメキシコ New Mexico 名詞
40744:めきしこ Mexico 名詞 メキシコ
40745:めきしこじん Mexican (person) 名詞 メキシコ人
40746:めきしこわん Gulf of Mexico 名詞 メキシコ湾
40747:めきしこわんりゅう Gulf Stream 名詞 メキシコ湾流

/data/word2vec_test/DIC_KANA.txt
2654:あめりかめきしこせんそう Mexican-American War 名詞 アメリカメキシコ戦争
27414:ニューメキシコ New Mexico 名詞
40744:めきしこ Mexico 名詞 メキシコ
40745:めきしこじん Mexican (person) 名詞 メキシコ人
40746:めきしこわん Gulf of Mexico 名詞 メキシコ湾
40747:めきしこわんりゅう Gulf Stream 名詞 メキシコ湾流
/ #
/ # # /data 内の「studio.h」を含むファイルを検索し、結果を JSON で表示
# rg --json stdio.h /data
{"type":"begin","data":{"path":{"text":"/data/gcc_test/test.c"}}}
{"type":"match","data":{"path":{"text":"/data/gcc_test/test.c"},"lines":{"text":"#include
 <stdio.h>\n"},"line_number":1,"absolute_offset":0,"submatches":[{"match":
{"text":"stdio.h"},"start":10,"end":17}]}}
{"type":"end","data":{"path":{"text":"/data/gcc_test/test.c"},"binary_offset":null,"stats":
{"elapsed":
{"secs":0,"nanos":1433800,"human":"0.001434s"},"searches":1,"searches_with_match":1,
"bytes_searched":80,"bytes_printed":272,"matched_lines":1,"matches":1}}}
{"data":{"elapsed_total":{"human":"6.577406s","nanos":577405900,"secs":6},"stats":
{"bytes_printed":272,"bytes_searched":80,"elapsed":
{"human":"0.001434s","nanos":1433800,"secs":0},"matched_lines":1,"matches":1,"searches":1,
"searches_with_match":1}},"type":"summary"}

動作確認環境

    • macOS Mojave(OSX 10.14.3)

uname -a : Darwin MacBook-Pro.local 18.2.0 Darwin Kernel Version 18.2.0: Thu Dec 20 20:46:53 PST 2018; root:xnu-4903.241.1~1/RELEASE_X86_64 x86_64

docker: brew cask docker でインストール

Docker version:

$ docker version
Client: Docker Engine – Community
Version: 18.09.0
API version: 1.39
Go version: go1.10.4
Git commit: 4d60db4
Built: Wed Nov 7 00:47:43 2018
OS/Arch: darwin/amd64
Experimental: false

Server: Docker Engine – Community
Engine:
Version: 18.09.0
API version: 1.39 (minimum version 1.12)
Go version: go1.10.4
Git commit: 4d60db4
Built: Wed Nov 7 00:55:00 2018
OS/Arch: linux/amd64
Experimental: false

所感

RipGrep on Alpine Base-image

Rust 版 grep とも言える、爆速の文字列検索コマンド「rg」(RipGrep)が好きです。

RigGrep(rg)とは

RipGrep (rg)
ripgrep is a line-oriented search tool that recursively searches your current directory for a regex pattern while respecting your gitignore rules. ripgrep has first class support on Windows, macOS and Linux, with binary downloads available for every release. ripgrep is similar to other popular search tools like The Silver Searcher, ack and grep.
(BurntSushi/ripgrep @ GitHub より)

RipGrep(rg)とは
RipGrep(rg)は、grep に似たコマンドライン・ベースの UTF-8 対応テキスト検索ツールです。BurntSushi氏によって Rust で書かれており、Silver Searcher(ag) の使いやすさと GNU grep の本来のスピードを兼ね備えています。 Windows, Mac, Linux などの OS で動作します。
(「爆速 grep「ripgrep」をラズパイにインストールする【実測値あり】」 @ Qiita より)

ripgrep の Qiita 記事 @ Google

そこで、最近いまさらながら学習を始めた Docker で ripgrep を良い感じで使うにはどうすれば良いか考えてみました。

まずは「(Docker コンテナに)マウントされたボリューム内にあるファイルを rg で文字列検索するだけのコンテナ」を作ってみることにしました。動いてしまえば、あとはコンテナを API 化してコンテナ間で利用できそうです。

文字列検索に特化したコンテナであるため、できればイメージを軽くしたいので軽量 OS で有名な Alpine Linux をベース・イメージにしたいと思いました。

しかし、rg が対応しているパッケージマネージャーはたくさんある2のですが、残念なことに 2019/02/05 現在 Alpine のパッケージマネージャー「apk」には対応していません3。

そこで、Rust の静的リンクなバイナリを構築4してから、そのバイナリをプレーンな Alpine イメージにコピーするという「Docker のマルチステージビルド」の手法を使うことにしました。

便利なことに、サイズはいささか大きいのですが「rust-musl-builder」という Rust の開発に必要なものが揃っている Docker のイメージを DockerHub に公開されている方がいらっしゃったので、そちらを使わせていただくことにしました。

rust-musl-builder
Docker images for compiling static Rust binaries using musl-libc and musl-gcc, with static versions of useful C libraries. Supports openssl and diesel crates.

GitHub: emk/rust-musl-builder

DockerHub: ekidd/rust-musl-builder

参考文献

「AlpineでRustのバイナリを動かす」@ etogenのブログ
「glibc-と-musl | Rust でクロスコンパイルして Raspberry Pi Zero W で動かす」 @ Qiita
「Multi-stage buildでDockerイメージのサイズを最適化」@ Qiita

【Intel アーキテクチャとは】 Intel チップを前提に設計されたプラットホームのことです。「Intel 入ってる」とほぼ同義です。Intel 以外にも AMD64、ARMv6、ARMv7、IBM POWER、PowerPC64 など、たくさん種類があります。バイナリ(プログラムがコンパイルされたファイル)はアーキテクチャに合わせて作成されるため、アーキテクチャとカーネルの種類が異なるプラットホームではバイナリは動きません。Intel と AMD は互換が多いチップであるため、どちらでも動く場合は x86_64 アーキテクチャと呼ばれますが、全てのバイナリが動くという保証ではありません。特にチップの性能をフルに活用するライブラリを利用したプログラムの場合には注意が必要です。(機械学習系のプログラムなど)このことは Docker でも重要で、Docker Hub などから docker pull コマンドでダウンロードされるビルド済みイメージは、ビルド時と同じアーキテクチャでないと使えません。DockerHub のイメージは、カーネルのほとんどが Linux であるものの、例えば RaspberryPi Zero(ARMv6l)用の Docker イメージが提供されていない場合は、Dockerfile および関連するソースファイルをダウンロードして docker build する必要があります。この時、注意しないといけないのがベースとなるイメージ(Dockerfile の FROM の値)も同じアーキテクチャのものにする必要があるということです。Dockerfile を利用する場合は、ベース・イメージが対応するアーキテクチャを提供しているか Docker Hub で確認しましょう。 ↩

【ripgrep 対応のパッケージマネージャ一覧】 https://repology.org/metapackage/ripgrep/versions ↩

2019/02/05 現在 PullRequest #1250 @ GitHub ↩

「AlpineでRustのバイナリを動かす」@ etogenのブログ ↩

广告
将在 10 秒后关闭
bannerAds