💡

小さな疑問を大事にしたら次に繋がった話

2024/06/11に公開

ちょっとした疑問を放置せずに調査をして解消したら思わぬところで役に立ったという話の共有です。主な対象読者は、IT技術者として成長したいなと思いつつも、どこから初めていいやら困っている人、腰を据えて書籍を読んだりして体系的な知識を身に着けるのとは別の手段があればいいなと思っているような方です。

本記事は以下動画のテキスト版のようなものです。既にこの動画を見た方は新しいことは書いていないので、とくに見なくていいと思います。

https://youtu.be/g0OOIDM23oI?feature=shared

前置き

ソフトウェア開発者として生きていると日々大小さまざまな疑問に遭遇します。これらの疑問を「まあそういうこともある」と全部放置してはいないでしょうか。本記事は、この手の疑問をちょっと調べて解消したところスカっとして、さらにその後に思いもよらぬところで役立ち、さらにスカっとしたという経験談を共有するというものです。こういう方法が自分にも合ってそうと思うかたは試してみてください。既に疑問に遭遇するたび調べているというかたはこの記事は見なくていいと思います。

本記事の構成は次のようになっています。

  1. 疑問が湧く: lsblkというブロックデバイスをリストするコマンドの仕組みが気になった。
  2. 疑問を解消: lsblkの仕組みが明らかになってスカっとした。
  3. 別件で役に立つ: 数か月後、lsblkの実行結果を利用する別コマンドの挙動で困ることがあった
    が、ステップ2で得た知見を生かして対処できたしスカッとした。

ここからは1~3について順番に何が起きたのか説明していきます。

疑問が湧く

私は所属している会社の業務として、Rookというソフトウェアのメンテナをしています。RookはCephという分散ストレージのオーケストレーションです。Cephは様々なノード上に存在するブロックデバイス上にOSDというデータ構造を作成して、OSDを束ねて巨大なストレージプールを作ります。Rookはこの作業を自動的にやってくれます。具体的には以下2つのステップに分かれています。

  1. 各ノード上で、ノード上に存在するブロックデバイスをリストするlsblkというコマンドを実行する。
  2. lsblkコマンド実行結果に出てきたデバイスのうち、Cephがサポートする所定のタイプ(後述)のデバイス上にOSDを作成する。

lsblkの出力結果は次のようになっています。

$ lsblk
NAME   MAJ:MIN RM   SIZE RO TYPE MOUNTPOINTS
sda      8:0    0   128G  0 disk
├─sda1   8:1    0     1G  0 part /boot/efi
└─sda2   8:2    0 126.9G  0 part /
sdb      8:16   0     6G  0 disk
sdc      8:32   0     6G  0 disk

TYPEフィールドがデバイスのタイプを示しています。たとえばディスク全体を示すsdadiskタイプで、その中に作成したパーティションであるsda1,sda2のタイプはpartです。タイプには他にも暗号化デバイスを示すcryptなど、さまざまなものがあります。

わたしは何度かlsblkコマンドの出力を見ているうちに、「タイプはどこに書いてある情報をもとにしているのだろう」というのが気になりました。ここでこの疑問は放置してもよかったのですが、たまたま時間に余裕があった、かつ、それほど難しいことはしていないだろうという勘に基づき、調べることにしました。

疑問を解消

lsblkコマンドはutil-linuxの一部ということを知っていたので、util-linuxのコードを読むことにしました。こういうときコードがさくっと読めるオープンソースは嬉しいですね。

調査の結果、TYPEフィールドはsysfsから得られる情報やLinuxのdevice mapperのUUIDなどから得た情報をもとにしていることがわかりました。詳しい調査方法は以下の動画、あるいは動画で参照している資料をごらんください。

https://youtu.be/x_QSV1tM3qY?feature=shared

https://speakerdeck.com/sat/lsblknotypehuirudonosikumi

動画や資料を見るとわかるのですが、別に大したことはしていません。ただ当たりをつけて小さな関数のコードを読んでいるだけです。小さな手間で知的好奇心を満たせたので、大変よかったです。

別件で役に立つ

数か月後、Kernel/VM北陸part6というイベントで、任意のブロックデバイスのI/Oエラーをエミュレーションするという機能を紹介する発表をしました。以下はそのときの発表を2つのパートに分けてyoutubeにアップロードしたものです。

https://youtu.be/8Mbd31KHDR4

https://speakerdeck.com/sat/ozhang-hai-noemiyuresiyon-ji-cun-tagetutobian

https://youtu.be/nbwF9uaw-sQ

https://speakerdeck.com/sat/ozhang-hai-noemiyuresiyon-kanerumoziyuruzi-zuo-bian

この発表自体は幸いにも好評でした。しかし、発表の準備時間の都合で実践例を紹介できなかったという悔いが残っていました。そこで「間に合えばLTで実践例のデモをする」と宣言して、他のセッションが終わってLT大会が始まるまでに、Cephを構成するOSD(ディスク)上でI/Oエラーが発生した場合に、Cephは壊れたデータを復旧して正しい値を返すことを示すことにしました。

ところがここで問題が発生しました。I/Oエラーをエミュレーションするためにはdevice mapper機能が作る仮想ブロックデバイス上にOSDを作る必要があるのですが、device mapper機能が作るデバイス上へのOSDの作成はCephがサポートしていなかったのです。

ここでハッと数か月前の記憶がよみがえりました。lsblkでデバイスのタイプを得るためのコードを読んでいたので、device mapperのUUIDの値を所定の値に設定するとtypeフィールドの値を好きな値に見せかけられるということがわかっていたのです。

https://youtu.be/D_pecRQXn0k

https://speakerdeck.com/sat/lsblkkomandonotypehuirudonozhi-wozi-you-nibian-geng

このハックを使って、無事仮想ブロックデバイス上にOSDを作ることができて、デモもうまくいきました。

https://youtu.be/uN_Gn-bfiSI

https://speakerdeck.com/sat/fen-san-sutorezicephnodetapo-huai-jian-zhi-xiu-fu-ji-neng-haben-dang-nidong-zuo-surunoka

このデモは数か月前にlsblkのソースを見ていなければ不可能だったでしょう。「かつて思いつきで調べたことがこんな時にこんな形で役に立つとは!」と、かなりスカっとした記憶が残っています。

おわりに

ここまで述べた通り、小さな疑問を捨て置かず、ちょっと調べてみたことによって満足できて、さらに数か月後に別のことに役立って二度おいしかったわけです。これまでにこのような体験はいくらでもあります。また、わたしは参考書を読んで体系的に物事を理解するのが苦手なので、これまで基本的には、このような実践ベースの方法で成長してきました。この記事で紹介した方法はわたしと似たようなタイプの人にはとくに役立つのではないかなと期待しています。

最後になりますが、ここまでに書いた疑問について調べてみることについて、注意点を2つ書いておきます。第一に、全ての不明点を明らかにしようとしないことです。時間は有限なので、全部調べていくと本来やるべきことがいつまで経っても終わりません。とくに仕事の場合は終わらせるべきことは終わらせて、余剰時間があれば調べる、くらいでいいでしょう。第二に、成長にこだわりすぎないことです。ずっと成長のことばかり考えていると思い詰めてしまって心身の健康に良くないです。飽きたり、思っていたよりも調べるのが難しそうならやめるか後回しにする、といった逃げ道を残しておくといいかと思います。疑問は別に逃げないです。

Discussion