しげぽん日記

技術屋の魂は失わない

Rustと私

このブログを書くのは5年ぶりらしい。

転勤を機に自宅をスマートホーム化したりしているが何も書いていない。

twitterでRustのコマンドラインツール群の紹介をしたい気分と書いたら、いいねがついちゃったので書かざるをえないので公開する。

 

機械学習に世の中がうぇーいする前から、私は諸々のツールの開発にPythonを使っていた。

Perlがイヤになったから。

Perlの事は私は当時Write Onlyが言語と呼んでいた。

同じ処理を記述するのに自由度が高過ぎて、自分で書いたコードでも後から読んで理解できない事が多かったから。

 

で、何にしよう?って思った時にインデントでスコープを表現するというただその1点と書き方の自由度が比較的少ない(これはそのうち自由度が高くなったというか、処理系にまかせた書き方にしないと処理が遅くなるので覚えないといけない事が増えた)のでこれにしようと思ったのだった。

 

最初に自宅をスマートホーム化した4年ほど前はPythonで書いていた。

 

一方、会社では、イントラのツールがクソ過ぎてつらかったので、改善するツールも書いていた。

最初は、Chromeプラグインを書いてブラウザの中でDOMを書き換えて、本来必要な情報を補完表示するようなものだった。

その時にJavaScriptを書くようになった。

けど、当時はJSはなんとなくまどろっこしくって嫌いだった。

だからChromeプラグイン以外は使わなかった。

しかし、Chromeプラグインはストア以外での配布がうるさくなってきたのでだんだん社内での配布も難しくなってきたので、イントラ改善ツールの提供方法としては適さなくなってきた。

 

このため、Webのフロントエンドも書く事を考え始めた。

最初はPython + Djangoで書いていた。

ただ、どうしてもPythonだとasyncを書くのがいまいちなのでフロントエンドにはあまり向いていないなと感じていた。

その時にVue.jsを使ってみてアプリを書いてみた。

なるほど、Node.jsというのはなかなかよくできているなと思った。

特に非同期が書きやすいのはすぐれていると思った。

処理系も世の中はどんどん進んでるんだと思った。

ただ、Vue.jsとReactとどっちがいい?って考えた時に、どうもReactの方がたくさん使われてそうなのでReactにしちゃおうって思った。

なかざんさんのブログとか見てたので、イントラの改善ツールもReact Native for Webで書いちゃえってなって、結局React Nativeで書いている。

会社で利用している LINC Biz(リンク ビズ)| ビジネスチャット × ビデオ会議 のプレゼンス情報を座席レイアウトに並べるアプリを作って、テレワーク環境でもなんとなくみんなそこにいる気分にさせてみたりとか。

一番は労務管理ツールなんだけど。

 

で、自宅のスマートホームもNode.jsに書き直してみた。

それなりに動いた。

現在の状況をモニターして、制御するUIを用意するくらいはどうとでもなった。

ただ、その時のシステム構成があまり気に入らなかったので、ずっとシステム構成をどうすべきか悩んでいた。

 

1. フロントエンドはLINCBizみたいなチャットツールにする
2. Prometheusに時系列DBを持たせてGrafanaで可視化する
3. 自宅のサーバで動かすけれどできるだけプアな環境でも動かしたい
4. 自宅のサーバで動かすけれどポートの外部公開はしたくない
5. 本当はGraphQL的なAPIも用意したかったけれど別にそれってWebSocketでセッションはってJSONの交換すればいいだけだからGraphQLにはこだわらない

あたりかなぁ…もう忘れた。

結局この時点でフロントエンドを積極的に自分で書く必要がなくなったので、自宅システムはできるだけ軽量な環境にのっけたいと思っていた。

 

で、GoかRustかなぁと思ったのだけどGoを最初に見た時に感じたのが、最初にJavaScriptを見た時と同じ感覚で、めんどくせって感じだったので、Rustにした。少なくともネイティブのバイナリまで落としこんでしまうその潔さにほれたという感じはある。

 

ということでRustにどっぷりはまりこんでいる。

 

結局のところ現時点ではフロントエンド書くならReactでそれ以外は全部Rustという感じになっていて、もはやPython書けなくなってきていると思う。

OpenCVで手軽に書く時だけPython使うかもしれない。

Rustのsysクレートをクロスコンパイルする環境を整備するのが面倒で、ARMクロスでバイナリを作りたい時に、opencv_sysをビルドできないためだ。

RasPi上で監視カメラの画像をフレーム間差分抽出してmp4にエンコードするなんてのは、Rustで書かずにPythonで書いた方が手間が少ないのでそういう用途ではまだ使っている。

 

でも、会社でExcelを読み書きしたり、イントラ改善する際のバックエンド処理(WebSocketのサーバとか)とか、オレオレRPAツール(まぁただのクローラーだけど)とか、チャットボットとか、自宅スマートホームとか、そういうのはもはや全部Rust化してしまった。

 

あと、Rustだけどできるだけ、gnueabiではなくmusleabiを使うようにしている。

Dockerコンテナにする際にmuslにする事でイメージのサイズを極限まで小さくできるため。

DockerfileはFROM scratchで書き始めておいて、OpenSSLの証明書とtzinfoだけホストマシンのファイルをmountすれば、極小のDockerイメージが作れる。

まぁ複数のコンテナを同時に走らせる運用をしていないので、もはやDockerコンテナ化する必要もないので、最近は普通にsystemdに登録して動かしているけど、それにしてもOSに依存するバイナリの数を極力減らせるので、変な依存関係の解決のための諸々の手続を省略できる。

 

上記のRustのmuslビルド環境はWSL2上に構築していて(自宅も会社もメインはWindowsなので…)、Dockerデーモンを起動するのが面倒なので、WSL2上に↓のイメージと同じ環境をDockerfileと同じように展開して作っておいて、デフォルトのビルドターゲットをmuslにしてビルドするようにしている。

 

GitHub - emk/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.

Linuxディストリビューションが何だろうがmuslビルドしているのでバイナリのまま配布できる。

ソースコード管理はGiteaでやってるけどGiteaのリリースにバイナリをそのまま添付しておいて、実行するサーバでバイナリをダウンロードして、実行するだけですぐにサービスが動いちゃうので、最近はイントラ改善ツールはホストして公開するのではなくて、自分でサーバとして動く単一バイナリを会社で配布している。

ただ、動かす人に対してハードルあげてるのはたしかなのでちょっと考えた方が良いかもしれないけど、WindowsLinuxで1つずつバイナリを用意しておけば、どんなディストリビューションでも基本動くサーバ構築できるので、非常にポータビリティは高いと思う。

ついでに言うと、フロントエンドで動かすReact Nativeについてもzipで圧縮して上記のサーババイナリの中にinclude_bytes!で埋め込んでおき、起動時に自分でカレントディレクトリに展開するように作っているので、Webフロントエンドつきサーバだって1バイナリで配布できてしまう。

React Nativeももはや面倒なのでExpo使っておけばビルドするのもコマンド一発なのでそこは手をかけないようにしている。

どうせ私の書くのはお遊びレベルを越えないので。

 

ということでRustaceansの端くれとなって経緯を書いてみました。

あーツールの紹介してねーなっていうので、cargo install-update -lの結果だけさらしておきます。

Windows環境での実行結果。

 

Package       Installed  Latest   Needs update
bandwhich     v0.20.0    v0.20.0  No
bat           v0.17.1    v0.17.1  No
cargo-update  v5.0.0     v5.0.0   No
du-dust       v0.5.4     v0.5.4   No
fd-find       v8.2.1     v8.2.1   No
grex          v1.1.0     v1.1.0   No
hyperfine     v1.11.0    v1.11.0  No
nu            v0.26.0    v0.26.0  No
procs         v0.11.3    v0.11.3  No
racer         v2.1.44    v2.1.44  No
ripgrep       v12.1.1    v12.1.1  No
sd            v0.7.6     v0.7.6   No
starship      v0.50.0    v0.50.0  No
streampager   v0.9.2     v0.9.2   No
tealdeer      v1.4.1     v1.4.1   No
tokei         v12.1.2    v12.1.2  No
zoxide        v0.5.0     v0.5.0   No

 

nuが肝になっていて、実はzoxideとかはnuに対応していないので、実質使えていないのだけど、とりあえず入れたままにはしている。

あと、vimの外部コマンド実行もnuは対応していないので、vim.rustとかはnu経由では使えないので、仕方ないからbash経由でvimは起動しないといけない。

まぁメインのエディタは例に漏れずVSCodeなのだけど、コマンドラインでちょいちょいっといじりたいケースもあってvimも使ってるので…。

 

まぁ入れてはみたけど使ってないものも多いかな…

よく使うのは…

  • bat
  • cargo-update
  • fd-find
  • nu
  • ripgrep
  • starship
  • streampager … Windowsだけ

かな。

byobuのデフォルトシェルをnuにしておいて、byobuを起動したらnuが起動するけど、そうじゃない場合はbashが起動するようにしておけば、byobuのtmuxが固まったりしても非byobuなシェルを用意できるのでnuのstartupに以下のようなコマンドを書いておいて、

def ssh [host] { ssh -t $host byobu }

 ssh ホスト名でリモートログインした場合はbyobu + nuが起動、^ssh ホスト名でリモートログインした場合は、bashが起動、といった形でbyobuの設定でのログイン時に自動でbyobuを起動するオプション(よくはまる)をオンにしない運用にしている。

このへんはnuの話なのでまた別途トピックを分離して書こう。

nuってドキュメントがいまいち(リリースノートがドキュメントになってる…)とかいうのもあるので癖はあるけど非常によくできているので、そのへんの事もどっかで書いてみる。

starshipはnuを入れる前にbashpowershellに導入してみたけど見た目が統一されるのも含めて非常に良い感じ。あまりにも統一され過ぎて、今、自分がWindowsのネイティブなのか、WindowsのWSLなのか、リモートのLinuxなのか、区別つかなくなってしまうくらい…。

その上シェルまでnuで全部統一したので、byobuのstatuslineでホスト名出しておかないと、さっぱりわからなくなってしまう…

なのでWindowsのネイティブ環境でも動くbyobuがあると良いなぁ…と。

まぁ当座はWindows Terminalのタブを見て推定するしかないかなと…。

Windows Terminalもいきなりnuが起動するようにしていて、かつ、デフォルト起動にしているので、シェルスクリプトの書き方で悩む事は減った。

nuのスクリプトの書き方はクセはあるけれど、トライアンドエラーで書けるし、Rust的な感じでエラーメッセージ眺めりゃなんとかなくので、WindowsネイティブでもLinuxでも同じスクリプトで同じ処理(Giteaに最新リリースを追加してビルドした成果物をリリースにアップロードする、とかそういうの)を書けるので、かなりプラットフォームを意識しないで作業できる環境が整いつつある。

 

Windowsでbat動かしてもページャーがきかなかったのはずっと悩ましいなと思っていたのだけど、streampagerを入れたら解決した。Linuxでやると、byobuとの相性が悪いのか、streampager起動後はカーソルの表示位置がおかしくなってしまうので、Linuxでは、pagerはbatを使うようにしている。

alias less = bat --paging=always --color=always -p
alias cat = bat --paging=never --color=always -p

 と書いておけば、悩まずに使えるので。

Windowsの場合はlessは

def less [file] { bat --paging=never --color=always -p $file | sp }

と書いておけば同様に使えるのでそれで良いことにしている。

WSL2側のcargo install-update -lは以下でもうちょっと入ってる。

Package          Installed  Latest   Needs update
bandwhich        v0.20.0    v0.20.0  No
bat              v0.17.1    v0.17.1  No
cargo-audit      v0.13.1    v0.13.1  No
cargo-deb        v1.29.0    v1.29.0  No
cargo-update     v5.0.0     v5.0.0   No
du-dust          v0.5.4     v0.5.4   No
exa              v0.9.0     v0.9.0   No
fd-find          v8.2.1     v8.2.1   No
gitui            v0.11.0    v0.11.0  No
grex             v1.1.0     v1.1.0   No
hyperfine        v1.11.0    v1.11.0  No
mdbook-graphviz  v0.0.2     v0.0.2   No
nu               v0.26.0    v0.26.0  No
procs            v0.11.3    v0.11.3  No
racer            v2.1.44    v2.1.44  No
ripgrep          v12.1.1    v12.1.1  No
rmesg            v1.0.13    v1.0.13  No
rustscan         v2.0.0     v2.0.0   No
sd               v0.7.6     v0.7.6   No
starship         v0.50.0    v0.50.0  No
streampager      v0.9.2     v0.9.2   No
tealdeer         v1.4.1     v1.4.1   No
tokei            v12.1.2    v12.1.2  No
ytop             v0.6.2     v0.6.2   No
zoxide           v0.5.0     v0.5.0   No

まぁ入れたけどWindowsで積極的に使ってるもの以外はあまり使ってないかも。

あとは、ARMコアのNASでも動くように、上記のソフトウェアはsrcをダウンロードして、

GitHub - messense/rust-musl-cross: Docker images for compiling static Rust binaries using musl-cross

を使ってビルドして/opt/binとかにインストールするようにしている。

NASのシェル環境を変えられたのはかなり大きい。こいつもbyobuがないのだけど。

 

だいぶ書いたのでいっぺん公開する。

また次気が向いたら書きます。