Inside of LOVOT

GROOVE X 技術ブログ

Lovot Frameworkチーム座談会(中編):ハードウェアとの連携

こんにちは、SWチームの Junya です。

LOVOT は様々な技術要素が組み合わさって作り上げられていますが、 LOVOT がどのように開発されているか、 なかなかイメージしにくいのではないかと思います。

その中でも特にイメージのしにくい、LOVOTの基盤部分の開発について、 Lovot Framework チーム (以下LFチーム)の皆さんにインタビューしました。

今回は3部構成の第2回、中編です。前回の記事は、こちらをご覧ください。

tech.groove-x.com

ハードウェアの話

司会

LFチームで扱っているハードウェア周りの話も聞かせてください。

マイコンのファームウェアとの連携

bucchi

ハードウェアに近い部分としては、LFチームではメインコンピュータに直接繋がっているデバイス向けのドライバ・サービスと、マイコンとの通信部分を扱ってます。

司会

LOVOTにはとてもたくさんのマイコンが載っていますが、どうやって通信しているのでしょうか?

bucchi

マイコンとはSPI、UARTやUSBなどのインタフェースで繋がっています。

ato

初代・LOVOT 2.0 の構成ですが、ファームウェアチームのブログにこのあたりのことが書いてありましたね。

tech.groove-x.com

司会

メインコンピュータとファームウェアの間の連携はどのようになっているのでしょうか?

bucchi

Memmory Map Sync (以下mm-sync)というサービスが各マイコンごとにあり、ファームウェア側のデータを数百 Hz 程度の周期でメインコンピュータの共有メモリに同期しています。

データの中身としては、センサー値の読み取りやサーボへの指示値など、Read/Write 合わせて数百項目あります。

司会

共有メモリにデータを集約することで、各アプリケーションはファームウェアとの通信を気にすることなく、任意のタイミングでセンサ値にアクセスできるのですね。

bucchi

はい。ただ、各アプリケーションは、直接共有メモリにアクセスしているわけではなく、代わりに Nerve System (「神経回路」由来。以下ns)が提供する gRPC を利用しています。

ns は共有メモリへの入出力を仲介するだけでなく、上位レイヤーからの指示値を逆運動学を用いてサーボへの指示値へ変換したり、可動域のガード制御をするなど、データ変換処理も一部担当しています。

他にも、安全制御のためサーボへの指示がなくなるとトルクを抜くような仕組みも入っています。

マイコン以外のデバイス

司会

マイコンとの通信以外だとどういったものがありますか?

bucchi

LOVOT 3.0 のケースでは、メインコンピュータである Jetson Orin NX に直接接続されている、3Dレーダー、NFC、IMU、WiFi、SSD、Bluetooth などが LF チームの担当になります。

他にも、カメラも Jetson に接続されていますが、カメラ関係はスマラボチーム(主に画像認識を担当するチーム)が担当しています。

h1sakawa

ファン制御、バッテリー制御もやっています。

bucchi

そうですね。バッテリーは、ファームウェアチームと半々くらいの感じですね。

直接バッテリー制御ICをコントロールするのはファームウェアチームで担当していて、LFチームではFCC更新(バッテリー容量を正しく推定するための仕組み)などの上位の部分を担当しています。

司会

マイクやスピーカーに関してはどうでしょうか? Jetson に直接繋がっているのですか?

bucchi

確かにそうですね。マイクとスピーカーも Jetson に直接繋がっています。

これらもLFチームの担当ですね。

司会

Device Tree も修正していましたよね? Device Tree もハードウェアに関係しますか?

bucchi

はい。Linux kernel のデバイス設定として、設定を変更したり使わないデバイスを無効化したりするのに使っています。

Jetson Orin では上記の使い方以外に、Bootloader でも Deivce Tree が使われていて、 各ピンのマルチプレクス設定やGPIOの初期状態なども Device Tree で設定できるようになっています。

これらの設定を LOVOT のボードに合わせ込むことも行っています。

起動高速化とディスプレイ制御

司会

起動の高速化みたいなこともやっていましたよね。どうやって速くするのでしょうか。

h1sakawa

そうですね、起動の高速化も実施しました。

簡単に言えば、起動時の制御をシュリンクをしています。 Jetson には LOVOT に必要のないハードウェア制御が数多く入っているので、 いるものといらないものを精査して、差し引いています。

単純に抜いて問題なければよいのですが、一つ一つのハードウェア制御には 他のハードウェアやソフトウェアとの間に依存関係があり、何かを抜くと、きちんと起動しなくなることがあります。

そこで、ハードウェアの仕様やボード設計、ソフトウェアの構造などを総合的にみて、残す、残さないを判断しました。

司会

起動時の目のところについても教えてください。

h1sakawa

起動時の目(ディスプレイ)は FPGA で表示させています。 ディスプレイに表示するスプラッシュ画像(LOVOTの起動時に表示するロゴ画像)とそれを映像信号に変換する回路を作成し、 FPGA に組み込みました。

LOVOT 3.0 では、これまでの LOVOT 1.0 / LOVOT 2.0 と比べると FPGA の性能を抑えたものを採用したため、 ディスプレイに出力する映像信号のタイミングが結構シビアでした。

ディスプレイに表示するための十分な信号スピードを確保するために、 FPGA のパラメータをチューニングして、きちんとディスプレイに表示されるような工夫をしました。

司会

FPGAとJetsonの関係はどうなっているんですか?

h1sakawa

FPGA は Jetson とは別のハードウェアで、 Jetson から映像信号を出力し、 それを FPGA で読み取って、 2つのディスプレイに表示しています。 この2つに分ける処理も FPGA で行ってます。

ato

デュアルディスプレイの仕組みで2つのディスプレイへ出力するのではなくて、FPGAで1枚の画像を2つのディスプレイに分けているんですよね。

h1sakawa

はい。もとは1枚のディスプレイ画像を、右半分、左半分っていう形で2つに分配しています。

司会

電源を入れた直後は、Jetson はまだ動いていないと思うのですが、どのようにして目の画像を表示しているのでしょうか?

h1sakawa

LOVOT に電源が入ると、 Jetson よりも先に FPGA に電源が入ります。

FPGA に電源が入ると、 FPGA の中のスプラッシュ画面を表示する回路がスタートして、目にスプラッシュ画像を表示します。 Jetson からの映像信号が届くまでの間、 FPGA はスプラッシュ画像を表示しつづけ、 Jetson から瞳やまぶたの映像信号が届くと Jetson の映像に切り替わるようにしています。

このあたりは、エレチームと連携しながらやりましたね。


中編のハードウェアの話はここまで。いかがでしたでしょうか?

LFチームでは、組み込みLinuxだけでなく、サーバの構成管理やサービス(デーモン)の開発経験、 Goを使ったバックエンド開発などのスキルを持っている方を探しています。

一緒に LOVOT を作りませんか?

recruit.jobcan.jp recruit.jobcan.jp

次回はとうとう最終回、お楽しみに。

Lovot Frameworkチーム座談会(前編):LOVOTのOSの話

こんにちは、SWチームの Junya です。

LOVOT は様々な技術要素が組み合わさって作り上げられていますが、 LOVOT がどのように開発されているか、 なかなかイメージしにくいのではないかと思います。

その中でも特にイメージのしにくい、LOVOTの基盤部分の開発について、 Lovot Framework チーム (以下LFチーム)の皆さんにインタビューしました。

前編・中編・後編の3部構成でお送りするので、お楽しみください!

Lovot Framework チームってなに?

司会

さっそくですが、本日はよろしくお願いします。 今日は、LFチームってどういうチームなのか、普段どういう仕事をしているのかなど、ざっくばらんに聞かせてください。

それでは簡単に自己紹介をお願いします。

ato

id:atotto です。LOVOT 3.0 では、クラウドサービスの開発からすこし離れ、LOVOTのアップデートインフラ構築や、LOVOT自体のアップデート、データ配信基盤、セキュアブート対応などに関わりました。Goでサービスを書き続けています。

h1sakawa

GROOVE Xに入社して3年目になります。LOVOT 3.0では、BIOS/UEFI、Linux Kernel、ドライバ開発、デバイスは内部ストレージや目の映像出力などを担当しています。

bucchi

以前、半年働いて感じたGROOVE Xの面白いところという記事を書いた bucchi です。 あれから時間が経ち、GROOVE Xに入社して2年が過ぎました。

LOVOT 3.0では、OSビルド、Linux Kernel、ドライバの開発や、ファームウェアとの通信部分などの開発を担当しています。

司会

LFチームってどのようなことをしているチームなのでしょうか?

ato

LFチームっていうと定義が曖昧で、結局いろんなところを担っているのですが、 LOVOT 内で動作している Linux OS のシステムづくりとか、 いろんなデバイスと上位SWとを繋ぐためのセンサー配信の仕組みづくりとか、 そういったところがメインとして挙げられると思います。

司会

センサーやOS以外に、アップデートの部分も開発していますよね。

ato

本当はアップデートは別のチームとして立ち上げたいな、と思っています。

というのも、OSという意味ではLFも関係しているのですが、 アップデートとしては OS だけではなくて、クラウド側の配信の仕組みもあるんですよね。

司会

アップデートは、OSとクラウドまでつながってますもんね。

ato

そうですね。LFチームでは Linux カーネルのメンテナンス、OSの作成から始まって、 OS アップデートまで、ぼやっと繋がっているので、きれいな境界はないですね。

LOVOTOS の話

司会

まずは LOVOTOS (LOVOT のOS)の話からはじめましょうか。 OS をアップデートするってことは、OS 自体の作成も必要じゃないですか。

bucchi

OS の作成とか、アップデートを全部込みで言うと、 LOVOTOS っていうディストリビューションを開発して配信している感じです。

司会

たしかにそうですね。 Ubuntu と同じレイヤーではなさそうだけど、どういう位置づけでしょうか?

ato

Debian→Ubuntu→Kubuntuみたいな、カスタマイズされていく流れで言うと、 Ubuntuから派生した、 Ubuntu ベースの LOVOTOS っていうイメージかな。

司会

ちなみに皆さんは、LOVOTOS以外でディストリビューションやカスタムOSを作ったことはありますか?

bucchi

私は、ディストリビューションっていうと違うかもですけど、 GROOVE Xに入る前も組み込み Linux の仕事をしてきたので、色々と製品向けのOSは作ってきました。

司会

だいたいどういうところから始まるんですか、そういうOS作りって。

bucchi

会社や製品によりますが、商用ディストリビューションを買ってきて載せる場合は、 その商用ディストリビューションをベースに、製品ボードに載ってる SoC 用の kernel をポーティングして作る感じですね。

SoC のチップベンダーから kernel が提供されるのですが、製品の用途に合わせてみると、 たいていの場合、製品レベルに達していなかったり、機能が足りないことが多いんですよね。

なので、それを商用ディストリビューションの kernel にポーティングしながら製品レベルの品質に仕上げていき、 BSP(Board Support Package)と呼ばれる、自社ボード用にドライバ等を合わせこんだ、小さな Linux みたいなものを作って、 それに製品で使うOSSパッケージを追加してOSを作る、といったことが多いです。

LOVOT では商用ディストリビューションは使わずに Ubuntu を使っていますが、大体は同じ流れです。

司会

LOVOT 3.0の開発でいうと、NVIDIA から kernel が提供されるということでしょうか?

bucchi

はい。そうですね。

LOVOT 3.0 では NVIDIA 社の Jetson Orin NX を使ってまして、NVIDIA から提供されている Jetson Linux を使っています。

www.macnica.co.jp

組み込み系の Linux では珍しく、ベンダー提供の kernel やドライバがかなりしっかりしていて、 商用レベルで使えるぐらいの品質だったので、 BSP開発っていう大げさな感じではなく、軽くポーティングしてるくらいの感じですね。

ansible

司会

なるほど。それから、GROOVE Xでは ansible を使っていますよね。

tech.groove-x.com

bucchi

はい。 Ubuntu のパッケージと Jetson Linux のパッケージを組み合わせてベースのものを作って、 ansibleで必要な修正を加えています。

ato

今の構成管理は必要なファイル配置してることが多いから、ansibleじゃなくても良さそうなところまで来てますね。

bucchi

そうですね。確かにがっつり構成管理をしているわけではないので、ansibleの良さはあんまり生きてないかもしれないです。 OSをビルドするたびに1から生成し直しているので、冪等性とか関係ないですし。 ファイル配置とかがうまくできるツールがあれば、そっちでもいいかも。

話がちょっと逸れちゃいますけど、ansible は intel 系のホストで arm 用の OS を変更しようとすると、QEMU 上で動かすので遅いんですよね。

司会

そうなんですね。

bucchi

ものすごく遅いんですよ。QEMU上 で Python 使って、apt install とかをするので、めちゃくちゃ遅くって。 なので、他の仕組みがあったらそちらの方が良いかも知れません。

OSビルド

司会

ansibleは、Jenkins 上で chroot して実行してる感じですよね? そこに Jetson 用のSWとかを組み込んでる感じでしょうか?

bucchi

そうですね、Jenkins上で動かしています。

Jetson用のSWは全部debパッケージになっているので、Jetson を意識する必要はなく、 普通のdebパッケージのインストールの形で、構成できるようになっています。

司会

Ubuntuのコアみたいなものに、Jetson用のdebパッケージを入れてあげれば、Jetson対応できちゃうってことですね。

bucchi

そうですね。このあたりのOSの構築方法は、LOVOT 1.0/2.0 用の LOVOTOS のビルド方法を踏襲しています。

司会

その後はどうするのでしょうか?

bucchi

LOVOT関連のパッケージも含めて必要なパッケージを一通りインストールして root filesystem ができたら、 ext4 のイメージ(Linuxのファイルシステムのイメージ)を作ります。

root filesystem を各パーティションごとのディレクトリに分けて、それぞれのext4のイメージを作っています。

インストーラーの作成

司会

それが出来上がったら、暗号化して配信するんでしたっけ?

bucchi

OSアップデートっていう意味だとそうなんですが、それとは別にインストーラーも作る必要があります。 アップデートができる前に機体にインストールする用途だけでなく、 生産フェーズで、機体にOSを書き込む際にも使います。

ext4のイメージを作るところまでは先ほど説明した通りで、 それを実際にJetson上で書き込むところは、NVIDIAから提供されているツールをカスタマイズして使っています。

そのツールを使ってパーテーションを切ったり、ext4に分けたイメージを特定のパーテーションに書き込んだりしています。

司会

インストーラーとは、USBインストーラーのことでしょうか? (GROOVE Xでは、オフラインのお客様向けに、USBのインストーラーを提供することがあります)

bucchi

USB経由ではあるんですが、USBメモリーから起動して書いてるわけではなくて、Jetson独自の仕組みでUSBブートしています。

ざっくり言えば、USBブートを使ってブートローダのイメージやLinux kernelを流し込んで Linuxを起動して、USBをネットワークデバイスとして見せて、ホストPC側のファイルをNFSをマウントして書き込む、みたいな感じです。

その一連の仕組みはNVIDIAから提供されているツールの機能で、書き込むデータの部分だけカスタマイズしています。

司会

OSが整ってからのアップデートはOTA (Over the Airの略: ネットワーク経由でアップデートすること)で出来るけど、はじめの段階ではこういう仕組みが必要なんですね。

bucchi

そうですね。 開発初期や生産時にUSBブートしてインストールする仕組みを利用しています。

司会

そうすると、LOVOTOS のインストールの手段は3つあるわけですね。 お客様先でのアップデートと、オフラインのお客様向けのUSBアップデートと、生産や初期開発のためのUSBブートの仕組み。

bucchi

そうですね。OSを書き込む手段としてはその3つになります。

アップデートの話

ato

JetsonでもUSBアップデートやOTAのような仕組みは提供されてたりするのかな?

bucchi

アップデートの仕組みは提供されていますね。

そのうちのブートローダーのアップデートしか LOVOT 3.0 では使っていないですけどね。 システム自体アップデートする機能も提供されているんですが、諸事情があって使っていないですね。

まだ LOVOT 3.0 の開発初期のときはJetson Linux でアップデートがサポートされていなかったんですよ。

あと、Jetson Linux のアップデートの仕組みでは、LOVOTみたいにファームウェアアップデートを挟み込むとか、 通知を目にアニメーションで表示するとか、そういったところはカスタマイズしにくいので、 初代のLOVOTで十分仕組みが作られていた、既存の仕組みを踏襲した方が良さそうだって判断しました。

ato

LOVOT 3.0 の開発時点では、Jetson のアップデートの仕組みは提供されてなかったので、自社で作ったって感じですね。

司会

たしかに、アップデートするときに、アップデートの目になったりしますもんね。

アップデートはどうやって LOVOT に反映するんですか?

bucchi

ざっくりいうと、通常のシステムとアップデートのシステムがあって、 それを切り替えてアップデートを実行しています。

多分アップデートがあるどの製品もそういう構成になっていると思いますが、 自分自身は書き換えられないから、別のシステムで起動させてから 通常のシステム側を書き換えるていますね。

2面化するこの方式は大体どの製品のアップデートでも似ていると思いますね。


長くなってきたので、前編はここまで。

GROOVE X では仲間を絶賛募集中です!

LFチームでは、組み込みLinuxだけでなく、サーバの構成管理やサービス(デーモン)の開発経験、 Goを使ったバックエンド開発などのスキルを持っている方を探しています。

一緒に LOVOT を作りませんか?

recruit.jobcan.jp recruit.jobcan.jp

次回、「Lovot Frameworkチーム座談会(中編):ハードウェアとの連携」に続きます。
お楽しみに〜!

LOVOTの中で動くRustなソフトウェア

少しずつ涼しさが感じられる季節になってきました。
こんにちは、GROOVE X でソフトウェアエンジニアをしているfmyです。 私は主に画像関係のアプリケーションを担当しており、去年の初冬にRustを導入していくという話をしておよそ一年が経ちました。 この記事では、導入がどのように進んだのかというお話をしたいと思います。

LOVOT 3.0の計算性能

LOVOT上で動くアプリケーションの殆どはGo, Pythonで実装を行っています。 Inside of LOVOTでの紹介記事としてはLOVOTの並行思考 with trioLOVOT と gRPCなどがあります。 LOVOT 3.0では新たにRustを使ったアプリケーションが増えました。

なぜRustを選んだのか、という話に入る前にLOVOT 3.0の計算性能を見てみます。 LOVOT 3.0ではSoCにJetson Orin NXを採用しており、計算力に関わる項目を抜粋すると以下のような性能になっています。

Jetson Orin NX Jetson AGX Orin
CPU Arm® Cortex®-A78AE v8.2 64-bit <
CPU Cores 6 or 8 8 or 12
CPU Freq(GHz) 1.4-2.0 1.4-2.2
GPU NVIDIA Ampere architecture <
GPU CUDA Cores 1024 1792 or 2048
GPU Tensor Cores 32 56 or 64
GPU Freq Max(MHz) 765 or 918 930 or 1300
DLA Cores 1 or 2 2
DLA Freq(MHz) 610 or 614 1400 or 1600
Mem(GB) 8 or 16 32 or 64
Mem bandwidth(GB/s) 102 204.8
AI Performance(TOPS) 70 or 100 248 or 275

以下をもとに改変
Jetson AGX Orin Series Hardware Architecture, TB_10749-001_v1.2 | p4
NVIDIA Jetson Orin NX Series Data sheet, Jetson_Orin_NX_DS-10712-001_v0.5.pdf | p1 DeveloperGuide: Platform Power and Performance

Jetson OrinはArm Cortex A78のCPUコアにAmpere世代のGPUを搭載しています。 汎用的な計算性能を場合、一般的なLaptop向けCPUと比較すると周波数は30%以上低く、潤沢に有るとは言えません。 実際にはSoC全体の電力消費の制約などから、CPU周波数を更に下げることもあります。

一方でAI Performanceと表記される推論計算の性能は、過去の世代から大きく伸びています。これにはGPUだけでなくDLAという専用のブロックが存在することが大きいです。 上のテーブルに書いてない項目として以下のようなHA(ハードウェアアクセラレータ)を搭載しているほか、UnifiedなメモリであるためCPU-GPU間やHA間のやり取りのコストが低いのが特徴です。

  • MIPI-CSIとISPのブロック
  • H.264, H.265, AV1,JPEGなどのエンコーダー、デコーダー
  • 画像処理に特化したPVA(Programmable Vision Accelerator)

一般的な汎用計算の効率化はもちろん大事ですが、Jetsonの性能を引き出すにはこれらHAを利用するのが効果的です。

JetsonのHAを使うには

JetsonのHAに実装された機能にアクセスするには。グラフィックならOpenGLやVulkanといったグラフィックスライブラリ、 推論や画像処理はNVIDIAの提供するCUDAやmultimedia-api、VPIといったライブラリを使います。 いずれもCで書かれており、実装するならCとの親和性が高い言語を使いたいです。

これまで採用してきたGoやPythonは、Cと連携を行うには不利です。C/C++ならば性能面でも親和性でも問題はありませんが、きれいなアプリケーションを書くには高いスキルが必要となります。 Cとの親和性があり、パフォーマンスも十分に高く、なおかつ安全に書けるということでRustが選択肢として上がりました。

Rustを活かした開発

目のデザインの話はLOVOTのひみつBLOGに記事があるのでこちらをご覧ください。 LOVOTの「目のデザイン」はセンスのかたまりだった!【前編】

LOVOT 3.0の目はRustで再実装を行いました。 以前のC++での実装は、ビジネスロジック以外にデータのパースや通信周りで書かなければならないコードが大きく、メンテナンスが難しくなっていました。 表現のコアはシェーダーであるためC++への強い依存は少なく、比較的移植はしやすいアプリケーションなので移植を決定しました。

実際、Rustでの再実装によってメンテナンス性は大きく改善され、ビジネスロジックに集中して記述ができるようになりました。 特に以下のところではRustの言語仕様、ライブラリを活かせたと思います。

  • HTTP通信周りはaxumをベースにし、非同期で実装をすることで全体的に見通しが良くなった
  • 内部プロトコルの文字列を手続き的にパースしていたが、traitとマクロを用いて適切な型として扱えるようになった
  • OpenGLのリソース管理は、Rust側に対応する型を定義してRAIIパターンで実装できた

Rust開発を支える環境

開発の多くは一般的なx86のPCで行っており、開発PC上ではJetson固有の機能には触ることができません。 そのためJetson開発者キットをベースに、必要に応じてカメラ等をつなぐことでLOVOTの実行環境に近い開発環境を用意しています。 基本的な機能の検証にはこれがとても役に立ちました。

またJetsonをCIランナーとしても利用しており、アプリケーションのテスト、コンパイル、パッケージ作成、TensorRT推論エンジンへの変換などをCIで行っています。 コンテナからmultimedia-apiなどJetsonの固有の機能にアクセスするため、deepstream_dockerをベースにして構築しています。 互換性の心配なく適切なバイナリ、パッケージが作れるため、安定した開発ができています。

最後に

LOVOTにおけるRustの活用について簡単に紹介させていただきました。 eyeのもっと細かいTipsや、カメラパイプラインでGStreamerを使っているなどより技術的な話もいずれ記事にしたいと思います。

弊社ではRustの書けるエンジニアも募集しています。 Jetson Orinにはまだ余力もあり、LOVOTも進化の余地がまだまだあります。 日常生活の中に溶け込むロボットに興味が有る方、ハードウェアの性能を活かしたりやJetson Orinの計算能力を引き出すことに興味の有る方はぜひご応募ください。

recruit.jobcan.jp

Ubuntuが標準の会社でFedoraを使っている男の話

こんにちは、斎藤@aznhe21です。会社では最近「あず」と呼ばれたり呼ばれなかったりしています。 転職してから初めてのブログです。すぐブログを書くつもりではいたんですが気付いたら9ヶ月も経っていました。時間経つのはや。

さて、皆さんの社用PCにはどんなOSが入ってるでしょうか? GROOVE Xでは開発用にはUbuntuの入ったPCが配布されます。 これはLOVOTの中身がUbuntuということからで、各種ツールの作りや管理をLOVOT用と開発PC用で共通化できるというメリットがあります。

またLOVOT用のパッケージや開発用の各種ツールは社内のaptレポジトリで管理されており、普通のパッケージと同じノリでインストールできます。 自分でビルドする必要がないのはとても便利です。

UbuntuではなくFedoraという選択

しかし私はFedoraを使っています。大きな理由というのはないんですが、 元々自宅鯖用にCentOSを使っていたことから前職でもFedoraを使っており、その流れでGROOVE XでもFedoraを使っています (今の自宅鯖にはRHEL無償版を使わせてもらっています)。 snapが嫌というのもあります。いやこれが半分くらいあるかも。

FedoraでもUbuntuのパッケージを使う

開発用のツールはUbuntu向けには配布されていますが、裏を返せばFedoraでは使えません。 一部ツールはGo製なのでその場合はパッケージからバイナリだけを抜き出して使うこともできなくはないんですが、 外部ファイルを必要としていたりGo製じゃなく依存ライブラリがあったりする場合は管理が面倒です。

そこでシステムコンテナを扱えるIncusを使います。 コンテナと言えばDockerやpodmanですが、これらはアプリケーションコンテナを扱うためのツールです。 アプリケーションコンテナはアプリケーション単体を扱うものですが、システムコンテナはsystemdなどを含めた複数プロセスを扱います。 これにより実質的にVMのような使い方ができるのです。 しかもコンテナであるためメモリ消費等オーバーヘッドは無視できるレベルです。

細かい使い方は説明しませんが、ホストのディレクトリをコンテナにマウントすればファイルの共有も簡単です。

コンテナ内でもmDNS

少し面倒なのがmDNSの扱いです。LOVOTの開発ではよくLOVOTにsshするのですが、 LOVOTに付けた別名がmDNSとして広告されるため、接続先はこの別名を指定するのが便利です(※)。 しかしUbuntu環境はコンテナ内でありマルチキャストを使うmDNSのパケットは届きません。 そこでmdns-repeaterを使います。

※LOVOTにsshできるのもmDNS名が広告されるのも開発モード限定です。

mdns-repeaterはネットワークのインターフェース名を2つ以上指定することで、各インターフェースに届いたmDNSのパケットを中継・転送してくれます。 Incusのネットワークインターフェース名がincusbr0でホスト側のネットワークインターフェースがwlp0s20f3なら、 ホスト側でmdns-repeater incusbr0 wlp0s20f3とコマンドを実行することでコンテナ内からもmDNSが使えるようになります。

Fedoraのパッケージにはsystemd用のファイルが含まれるので、設定しておくことで自動起動させることができます。

$ cat /etc/sysconfig/mdns-repeater
OPTIONS="incusbr0 wlp0s20f3"
$ sudo systemctl enable --now mdns-repeater

使っているツールとか

OS・ディストロの話だけでは味気ないのでツールの紹介もしておきましょう。

デスクトップ環境はKDE

KDEは普通です。なのに痒いところに手が届く利便性も持っています。デスクトップ環境にこれ以上何を望むでしょうか?

なぜかUbuntuもFedoraも、標準のデスクトップ環境にはGNOMEを採用しています。 しかしGNOMEはデスクトップ環境としては特殊と言わざるを得ません。 WindowsともmacOSとも大きく異なったUIを持ち、数多の拡張機能を入れなければ不満が募り続けます。

私はカスタマイズをするためにデスクトップを使っているわけではないのでKDEを使います。 最初からストレスなく使えますし、ウィジェットによって大小様々なカスタマイズもできます。

デスクトップの様子
Windows 11っぽくランチャーは真ん中にし、左下にシステム情報用ウィジェットを配置している

スクショはSpectacle

前回の記事でいいスクショのツールがないよーという話があったので書いておきます。

私はスクショの撮影には専らSpectacleを使っています。 KDEに付属しているツールで、スクショを撮ったまま編集もできます。 動画の撮影もできます。多分WindowsのSnipping Toolを参考にしてそうです。ただし今のところ文章の抽出はできません。 KDE付属なのでもちろんWaylandでもちゃんと動きます。

エディタはNeovim

社内ではVS Code派がいたりJetBrains派がいたりしますが、私はNeovimを使っています。

学生時代に軽い気持ちでvimを導入したらキーバインドから離れられなくなりました。 エディタ向けvim系プラグインは大体不満が出てくるので諦めました。助けてください。

ここで宣伝です。LSPのコードアクションを適用する前からどうなるかをプレビューできるプラグインを作っています。 便利なので皆さんも使ってみてね!

ターミナルはWezTerm

OSC 52(エスケープシーケンスでコピペ)やundercurlなどニッチっぽい機能にも対応していて便利です。 マルチプレクサが内蔵されてるのでtmuxいらずです。

さいごに

単純にLinuxで仕事ができるって良いですよね。

GROOVE XではLinuxデスクトップにこだわりのある方を募集しています。

使っているおすすめツール紹介(Ubuntuでスクリーンキャプチャしたい編)

こんにちは。 GROOVE X でソフトウェアエンジニアをやっている id: numa-gx です。

突然ですが、スクリーンキャプチャした画面にキャプションを追加して画像を誰かに送らねば…となったことはありませんか?

弊社では開発環境がLinux : Ubuntu 22.04 を使っているエンジニアが多いですが、標準のスクリーンショット機能ではキャプションを追加ができません。

そこで、最近使ってみて良かったのが Flameshotになります。 flameshot.org

(公式のデモ動画より)

以下のポイントに対応していたのが個人的に助かりました。

  • Linuxに対応している
  • スクリーンショット撮影した状態からそのままキャプション追加ができる
  • キーバインドを設定すれば通常のPrintScreenキー操作を上書きできる

Ubuntu22.04 でインストールする際に躓くポイントがあったので軽く解説したいと思います。

キャプション操作のUIが正しく表示されない場合

Flameshot は、Ubuntu22.04で標準のディスプレイサーバーとして採用されたWaylandへの対応がまだ不十分なため、この症状が発生します。そのため、ディスプレイサーバーをXorgに切り替える必要があります。

手順としては以下を実施します。

  1. sudo権限で /etc/gdm3/custom.conf を開く (例: sudo nano /etc/gdm3/custom.conf)
  2. #WaylandEnable=false となっている記述から先頭の#を削除(コメントアウトを解除する)して、ファイルを保存します

また Xorg で正しく動作するために、以下の記述を環境変数を .bashrc などに追加します。

export QT_QPA_PLATFORM=xcb

これらの手順を行った後、PCを再起動して、Flameshotを起動するとUIが表示されるはずです。

さらに、PrintScreenなど標準のキーバインドを置き換える方法も公式で手順も書かれていますが、かなり便利です。 ぜひ参考にしてみてください。

最後に

弊社では、Linux環境を使いこなせるエンジニアを絶賛募集中です。ぜひ一緒に開発しましょう!

また、様々な分野で募集しているため、是非下記リンクをご確認下さい。

recruit.jobcan.jp

最近の小ネタ3つ

こんにちは、クラウドチームへ出張中の Junya です。
最近気づいて便利だった小ネタを3つ紹介します。

goのgenericsで任意のmapのキーを並べ替える

今更感あるのですが、go の generics 便利ですね。

map を決まった順番で処理したい場面があったんですが、genericsを使ってこんな関数を用意したら、

package function

import "golang.org/x/exp/slices"

func SortedKeys[V any](m map[string]V) []string {
    keys := make([]string, 0, len(m))
    for k := range m {
        keys = append(keys, k)
    }
    slices.Sort(keys)
    return keys
}

string キーのどんな map に対しても使えて便利でした。

package function

import (
    "reflect"
    "testing"
)

func Test_sortedKeys(t *testing.T) {
    stringMap := map[string]string{
        "key2": "value2",
        "key1": "value1",
        "key3": "value3",
    }
    intMap := map[string]int{
        "key3": 3,
        "key1": 1,
        "key2": 2,
    }
    stringMapKeys := SortedKeys(stringMap)
    intMapKeys := SortedKeys(intMap)
    if !reflect.DeepEqual(stringMapKeys, []string{"key1", "key2", "key3"}) {
        t.Fatal("SortedKeys failed: ", stringMapKeys)
    }
    if !reflect.DeepEqual(intMapKeys, []string{"key1", "key2", "key3"}) {
        t.Fatal("SortedKeys failed: ", stringMapKeys)
    }
}

SignedURL で frontend から直接GCSへアップロード

社内向けのツールで frontend から直接 GCS へファイルをアップロードしたいユースケースで、 GCS の SignedURL を活用できました。

めちゃ便利。
なお、発行された SignedURL を知られてしまったら、有効期限のあいだ、誰でも何でもアップロード出来てしまうのでご注意ください。

GoLand(Ubuntu)での日本語入力

開発で GoLand(Ubuntu) を使っているのですが、なぜか GoLand 内での日本語入力が出来ず、悩んでいました。

Mozc や Fcitx の問題かなと調べていたのですが、結果的には GoLand の Java ランタイムの問題で、 IDE の起動 Java ランタイムを変更する を参考に、Java のランタイムを JetBrains 提供のデフォルトのものから、Ubuntu 側の openjdk-17-jdk に切り替えることで解決しました。

なお、カスタムの Java ランタイムのパスは

~/.config/JetBrains/GoLand2024.1/goland.jdk

に保存されます。うまく動作しない場合は、このファイルを削除すると設定がリセットされます。

絶賛採用中

LOVOT のようなロボット開発というと、ハードウェアを扱っているイメージが強いですが、実際には、EC・データ分析・生産管理・業務システムなど、ロボット開発そのものではない開発も多岐にわたります。 GCP, Kubernetes, Go, TypeScript, Teraform などを用いたクラウド開発の分野でも人を募集しているので、ご興味のある方はぜひお声がけください!

recruit.jobcan.jp

クラウド費用のコスト削減を試みたけど失敗した話

こんにちは、クラウドチームに出張中の Junya です。 今日は、クラウド費用のコスト削減を試みたけど失敗した話について、ご紹介します。

ことのはじまり

クラウドチームでは定期的に GCP の Billing ダッシュボードを見て、コストのボトルネックを確認しているのですが、イベントデータを処理する pubsub コストが高いことに気づきました。

出来る限りイベントを取りこぼさないよう、イベントデータは一度 pubsub に入れてからワーカー経由でデータベースに保存しているのですが、イベントは量も数も多いため、pubsub のコストがかさんでいました。

イベントデータを保存するためのパイプライン処理

Pub/Sub の料金 によると、Pub/Sub の費用は以下の3つの要素で決まります。

  1. メッセージのパブリッシュと配信のスループット費用
  2. Google Cloud のゾーンまたはリージョンの境界を越えるスループットに関連するデータ転送費用
  3. スナップショット、トピックで保持されるメッセージ、サブスクリプションで保持される確認応答済みメッセージのストレージ費用

今回の場合、1番目のスループット費用がボトルネックでした。はじめの 10 GiB は無料で、TiB あたり $40 かかります。我々の場合、イベントデータのスループットは数十TiB/月あるので、Pub/Sub だけで月に数千ドルかかる計算です。

Pub/Sub コスト削減対策

スループットはデータサイズに依存するので、Pub/Sub に生データを直接流す代わりに、Cloud Storage にデータを保存してから、その場所だけを Pub/Sub に流せばコストを削減できるのではと考えました。

イベントデータを Cloud Storage に保存することで Pub/Sub コスト削減する構成

Pub/Sub のコストと Cloud Storage のコストを比較すると、以下のとおりです。

  • Pub/Sub
    • $40 / TiB / 月
    • 数千ドル / 数十 TiB / 月
  • Cloud Storage
    • $0.023 / GB / 月 (保存期間に比例)
    • 数十ドル!? / 月

Cloud Storage へのデータの保存時間は非常に短いので、Pub/Sub に流していたイベントデータを一時的に Cloud Storage に保存することで、コストは数十分の一になることが期待できます。

実際、同じような方法でコスト削減を達成した事例がほかでも紹介されていました。

対策結果

思惑通り、Pub/Sub コストは 95% 削減されました。

Pub/Sub コスト(右端が切り替え後のコスト)

Storage コストの増分も、わからない程度です。

Standard Storage のコスト

しかし、Cloud Storage のオペレーションコストがヤバイほど爆上がりしていました

Standard Storage の Class A, Class B Operation コスト

全てを合わせると、このようになります。

Pub/Sub と Cloud Storage のトータルコスト

濃いオレンジの部分が Pub/Sub 費用で、それ以外が Cloud Storage の費用です。 思惑通りに Pub/Sub 費用は削減できたものの、それ以上に Cloud Storage の費用がかさみ、全体として 1,200% のコスト増となりました。

大失敗です。システム構成はすぐにリバートしました。

なぜ Cloud Storage の費用が爆上がりしたのか?

実は、Cloud Storage ではストレージ費用の他にオペレーション費用が発生します。

「Cloud Storage の料金」より抜粋(2024年4月現在)

クラスAオペレーションにあたる「データ書き込み」の場合、

  • $0.005 / 1,000 回

ですが、この数字を甘く見ていました。

イベントデータの数は1日に数億件あるため、

  • $0.005 / 1,000 回
  • $5 / 100万回
  • $500 / 1億回

1日に数億件のデータを読み書きすると、1日に数千ドルのコストがかかります。 オペレーション費用は、まったく無視できる単価ではありませんでした。

まとめ

ちょっとした工夫でクラウドのコストを大幅に削減できると期待したのですが、今回は思い通りにいきませんでした。 課金額を監視していたので短時間でリバートできましたが、見積計算は慎重にすべきだったと反省しています。 Cloud Storage のオペレーション費用にはお気をつけください。

LOVOT のようなロボット開発というと、ハードウェアを扱っているイメージが強いですが、実際には、EC・データ分析・生産管理・業務システムなど、ロボット開発そのものではない開発も多岐にわたります。 GCP, Kubernetes, Go, TypeScript, Teraform などを用いたクラウド開発の分野でも人を募集しているので、ご興味のある方はぜひお声がけ頂けると幸いです。

recruit.jobcan.jp