TenForward

技術ブログ。はてなダイアリーから移転しました

技術書典 17 でコンテナ本第 1 巻の改訂版を出します

技術書典13で、初めて "Linux Container Book"(コンテナ本)の第 1 巻を出して以来、毎回新刊を出してきました。

そして、5 回目の技術書典17では、このとき出した第 1 巻の改訂版(第 2 版)を出します。80 ページに届かないくらいだった初版に比べると、大幅ページ数アップで 120 ページに届かない程度になっています。

techbookfest.org

初版でも、これぞ Linux におけるコンテナの中心となる機能である Namespace と、コンテナの Network 機能を紹介しました。これに加えて、

  • User Namespaceを使って非特権コンテナを起動する際に重要な機能である "ID mapped マウント"
  • 現時点で最新の Namespace である Time Namespace

を新たな章として追加しました。Time Namespace については、この本のための書き下ろしです。

ほかにも、既存の説明を大きく充実させています。

  • Namespace 操作に使うシステムコール
  • システムコンテナとアプリケーションコンテナ
  • NSFS(/proc/[PID]/ns以下)の pid_for_childrentime_for_children ファイルの説明
  • PID Namespace の pid_for_children の説明

を追加しています。これらの説明の充実分もほぼ書き下ろしとなります。

初版を買った人は第 2 版を買うべきか?

私のお小遣いが増えますので買ってください。というのは置いといて…

基本的には、初版で現時点で Docker や Kubernetes で使われているコンテナの主要機能についてはカバーできているので、そういう視点で Linux カーネルのコンテナ機能を学びたい人は、第 2 版を買わなくても知識のカバーはできているはずです。

ID mapped マウント

そして、新たに章として追加した ID mapped マウントについては、連載記事で紹介しています。比較的最近の機能ですので、記事の情報が古いということもありません。

gihyo.jp

gihyo.jp

この記事と今回の第 2 版で異なる点は、ID mapped マウントで使っているコマンドです。記事では、ID mapped マウントの実装を主に担当したChristian Brauner氏の実装であるmount-idmappedを使っていました。第 2 版では、Linux で通常ファイルシステムをマウントするときに使う mount コマンドを使っています。

この mount コマンドについても、ブログで紹介しています。

tenforward.hatenablog.com

つまり、ID mapped マウントについては、本を買わなくても情報はゲットできます。情報を一冊の本でまとめて学びたいケース以外は、新たに買い直さなくても大丈夫です。

Time Namespace

Time Namespace は完全に書き下ろしですので、Time Namespace について知りたい場合は本を買ってください。もちろん、lwn.net とか色々な情報を集めれば学習できますが。特に udzura さんのこの記事は、第 2 版で新たに追加した情報とほぼ同等の内容になっています(私も執筆の際にはかなり参考にしています)。

udzura.hatenablog.jp

Namespace 操作に使うシステムコール

clone(2)unshare(2)setns(2)の説明をしているだけですので、man ページをご覧になれば理解できるはずです。

それに、第 2 版で追加した内容も大した内容ではないので、ここを特に知りたいと思った方は、わざわざ買い直す必要はありません。

NSFS

第 2 版で追加した内容は次のブログを参考にしています。こちらをご覧になって十分理解した人は買い直す必要はないでしょう。

tenforward.hatenablog.com

まとめ

内容だけを見ると、第 2 版を買い直さなくてもわかりやすい情報はありますので、あまり買い直す必要性はないかと思います。

買い直すと良いのは次のような人でしょうか。

  • 情報が 1 ヶ所にまとまっている書籍を使って勉強したい
  • シリーズ物はコンプリートしたい

コンテナ本第1巻第2版をよろしくです(笑)。

シトロエンDS3のBluetooth

DS3を買ってから、マルチファンクションディスプレイを見ながら操作したものの、Bluetooth の設定画面がありません。

調べてみると、このようなメニューが出てくるという話がありますが…

DS3マルチファンクションディスプレイのBluetooth設定画面

私の DS3 にはそんなメニューは出てきません。

しかし調べてみると、当初は機能的には備えていたものの、動作確認などのために機能が殺されていたバージョンがあり、ファームウェアのアップデートで対応した時期があるようです。その場合はメニューがない?

その場合でも対応している場合があるようで、試してみたらいけました。

Bluetoothで再生中

手順は

kobe-higashi.citroen-dealer.jp

を見れば良いですが、

  1. 車のエンジンをかけるか、電源だけオンの状態にします
  2. スマホ側で機器検索をします
  3. "BT_RADIO" というのが出てくるので選択します
  4. PINコードを聞いてくるので "0000" を入力します
  5. マルチファンクションディスプレイでも PIN の入力を促されるので "0000" を入れて OK を押します
  6. これで完了

Source で Bluetooth を選択できるようになります。

私は Pixel9 Pro を使っていますが、特に相性の問題もなく、ちゃんとマルチファンクションディスプレイには曲名などが表示されて使えています。

以前乗ってたアウディの時(純正のクラリオン製カーナビ)は接続が不安定で「曲名表示非対応」になったり、曲名表示できたり、接続のたびに状態が変化してたのに比べると安定しています。

シトロエン DS3 納車

IT技術関係のポストばかりでしたが、これ以上ブログを増やすのも何なので、ここで車関係も書くことにしました。

DS3
新しい愛車

これまでは家の車だけでしたが、相方が家の車をほぼ使っている状態で、自由に乗れる時間がないし、少し余裕ができたのもあり、自分専用の車を買うことにしました。

で、ずっと欲しかったシトロエンDS3の中古を探して買いました。

  • 2012年式
  • スポーツシック ウルトラプレステージ(色:ブラウンヒッコリー)
  • 6MT
  • 41,000kmほど走行

というわけで、初めてのラテン車の中古で心配なところはありますが、状態も良いですし、とりあえず順調に走ってます。10年ぶりくらいの MT 車ですが、乗って 30 分ほどでカンが戻ったというか、身体が覚えてる感じでした。人間の身体はすごい。

ブラウンヒッコリーという色もなかなかない色でいいですね。買う前は「シトロエンといえば赤!」と思ってたのですが、良い色で気に入ってます。

しばらく乗った感想ですが、

  • 足回りは硬い。突き上げる感じがある
  • 街中だと 3 速くらいまでで走れそう
  • 加速がヤバい。走り始めると気づかないうちにすぐに 50km/h くらいになってる。加速がすごい感じはあるが、スピード感がそれほど感じられない

天井にステッカーで模様がついているのは、コーティングとかどうするんやろ?と思ってます。

色々書いていこうと思います。

util-linux での ID mapped マウント

連載の第50回第51回で、ID mappedマウントについて書きました。

これらの記事を書いた時点(2022年末)では、mount コマンドでは ID mapped マウントができなかったので、記事では、ID mapped マウントの主要開発者であるChristian Brauner氏の mount-idmapped を使って説明しました。

その後、util-linux 2.39-rc1 の libmount で ID mapped マウントがサポートされ、2.40 で mount コマンドで --map-users と --map-group オプションが追加されました

ID mappedマウントの必要性

User Namespaceは、図のようにホストOS環境のUID/GIDと、コンテナ環境のUID/GIDマッピングさせる機能です。

User Namespace

図だと、ホスト上のUID:100000がコンテナ内の0に、UID:100001がコンテナ内の1に、UID:101000がコンテナ内の1000にマッピングされます。つまり、コンテナ内でUID:0のrootユーザーは、実はコンテナの外から見るとUID:100000の一般ユーザーの権限で動いており、仮にコンテナからホストに対して悪意ある操作を行おうと思っても、UID:100000の一般ユーザー権限でできることしかできません。

さて、コンテナを起動する際は、コンテナホスト上にコンテナイメージを展開し、それをマウントしてコンテナのルートファイルシステムとします。コンテナがUID:100000の一般ユーザー権限で動いているとすると、コンテナホスト上に展開されるコンテナイメージも、UID:100000から始まるマッピング先のUIDやGIDから操作できる権限がなければいけません。

しかし、一般的には、コンテナイメージはコンテナホスト上のrootから読める前提、つまりUID/GIDが0から始まるIDで作成されているでしょう。元から一般ユーザー権限で起動する前提でイメージを作れないことはないですが、そもそも各ユーザーでどのようなマッピングを行うのかは、イメージ作成時にはわかりません。

例えば、次のようにLXCコンテナをroot権限で作成したとします。

$ sudo lxc-create -t download c1 -- -d alpine -r 3.19 -a amd64
$ sudo ls -l /var/lib/lxc/c1/rootfs
合計 68
drwxr-xr-x  2 root root 4096  614 22:00 bin
drwxr-xr-x  3 root root 4096  616 22:54 dev
drwxr-xr-x 24 root root 4096  616 22:54 etc
drwxr-xr-x  2 root root 4096  127 02:53 home
  :(略)
$ sudo chmod 775 /var/lib/lxc/c1 (これはこのあとの操作のために権限を緩めています)

このように、ほとんどのディレクトリーはホストのroot所有になっています。

ここで、unshareコマンドを使い、User Namespaceを使ってコンテナを作ります。

$ unshare --user --map-root-user ls -l /var/lib/lxc/c1/rootfs/
合計 69,632
drwxr-xr-x  2 nobody nogroup 4,096  614日  22:00 bin
drwxr-xr-x  3 nobody nogroup 4,096  616日  22:54 dev
drwxr-xr-x 24 nobody nogroup 4,096  616日  22:54 etc
drwxr-xr-x  2 nobody nogroup 4,096  127日  02:53 home
  :(略)

ここでは、現在のユーザーをコンテナ(User Namespace)内のrootにマッピングして、ls -lコマンドを実行しています。しかし、ファイルの所有権は何も触っていないので、所有者がnobody:nogroup所有になってしまっています。これは、コンテナホスト上のUID/GID:0が、新たに作ったUser Namespace内ではマッピングされていないためです。

この変換をID mappedマウント以前は、chownなどで実行していたのですが、これは非常に効率が悪いために、コンテナからマウントする際にファイルの所有者についても、マッピングを使ってずらそうという考えで実装されたのがID mappedマウントです。

図のように、User Namespaceで使うマッピングをそのまま使い、ファイルの所有者についても変換を行ってしまおうという機能です。

ID mappedマウントの動き

mountコマンドからID mappedマウントを利用する

さて、2.40からmountコマンドに追加されたID mappedマウントを行うためのオプションを使って、ID mappedマウントを試していきましょう。

追加されたオプションは次の2つです。2つとも使い方は同じです。いずれのオプションも複数回指定できます。このオプションとバインドマウントを組み合わせます。

オプション 説明
--map-users <id-from>:<id-to>:<id-range> UIDのマッピング指定
--map-groups <id-from>:<id-to>:<id-range> GIDマッピング指定

このオプションで指定するコロンで接続された値 <id-from>:<id-to>:<id-range> のそれぞれで指定する値は次の通りです。

説明
id-from マッピング元、つまりmountコマンドを実行する元のUser NamespaceでのID
id-to マッピング先、つまりマウント先のUser NamespaceでのID

例えば、次のようにマッピングとマウント元、マウント先のディレクトリーを指定します。

$ sudo mount --bind --map-users 1001:1002:1 --map-group 1001:1002:1 /path/to/src /path/to/dest

この例では、mountを実行する元のNamespaceのUID/GID:1001を、マウント先ではUID/GID:1002にマッピングして、バインドマウントしています。

それでは、実際にID mappedマウントの動きを見ていきます。実行はUID/GIDがいずれも1002のu1002ユーザで実行しています。

u1002@host:~$ id
uid=1002(u1002) gid=1002(u1002) groups=1002(u1002),10(wheel)

そして、UID/GIDが1001のu1001ユーザのホームディレクトリーをu1002ユーザでID mappedマウントしてみます。

u1002@host:~$ id u1001
uid=1001(u1001) gid=1001(u1001) groups=1001(u1001),10(wheel)
u1002@host:~$ sudo ls -l /home/u1001
合計 8
drwxr-xr-x 2 u1001 u1001 4096  5月 13 18:10 Mail
drwxr-xr-x 2 u1001 u1001 4096  5月 13 18:10 Sample
-rw-r--r-- 1 u1001 u1001    0  6月 16 21:41 u1001-file

上のように、u1001ユーザのホームディレクトリには、u1001-fileというファイルをu1001ユーザ権限で作成してあります。

それでは、このu1001ユーザのホームディレクトリである/home/u1001を、UID/GIDu1002ユーザのIDである1002にマッピングして、/mntにマウントしてみます。

u1002@host:~$ sudo mount --bind --map-users 1001:1002:1 --map-group 1001:1002:1 /home/u1001 /mnt

これで/home/u1001がIDマッピングされて、/mntにマウントされているはずです。/mntディレクトリの所有権を確認してみましょう。

u1002@host:~$ ls -l /mnt
合計 0
-rw-r--r-- 1 u1002 u1002 0  6月 16日  21:41 u1001-file

元の/home/u1001では、u1001ユーザ所有だったファイルがマッピングされ、u1002ユーザ所有に見えています。

次に、/mnt配下でファイルをu1002ユーザ(UID/GID=1002)権限で作成してみましょう。

u1002@host:~$ touch /mnt/u1002-file
u1002@host:~$ ls -l /mnt
合計 0
-rw-r--r-- 1 u1002 u1002 0  6月 16日  21:41 u1001-file
-rw-r--r-- 1 u1002 u1002 0  7月  9日  01:34 u1002-file

ファイルを問題なく作成でき、新たに作成されたファイルの所有権はu1002ユーザになっています。

ここで、新たにID mappedマウントされたディレクトリである/mntで作成したu1002-fileを、マウント元の/home/u1001で確認しておきましょう。

u1001@host:~$ ls -l /home/u1001
合計 0
-rw-r--r-- 1 u1001 u1001 0  6月 16 21:41 u1001-file
-rw-r--r-- 1 u1001 u1001 0  7月  9 01:34 u1002-file

/mnt上でu1002ユーザの権限で作成したu1002-fileは、元の/home/u1001で確認すると、きちんとUID/GIDが1001のu1001ユーザ所有になっています。


さて、ここまでで util-linux に含まれている mount コマンドで ID mappedマウントの動きを見てきました。記事では、このあと、ACLやケーパビリティの動きを見ていますが、マウントされてしまったあとの動きは同じですので(カーネルの同じ機能を使ってるので当たり前ですね)、そのあたりは記事を参照いただければと思います。

大吉祥寺.pm に参加し、コンテナのお話をしてきました

7/13(土)に武蔵野公会堂ホールで開催された大吉祥寺.pm に行って、コンテナの話をしてきました。

会場の武蔵野公会堂ホール

吉祥寺.pm 自体や、Perl 系のイベントへの参加経験はこの日までありませんでした。それでも CFP を提出したのは、次のような理由です。

  • そこそこ著名なサイトで連載したり、そこそこ著名なイベントでの登壇をしていても、意外に知られていないことが多い、ということをここ何年も色々なところで感じています。吉祥寺.pm に参加される方々は、私が普段参加する勉強会やイベントに参加する層とは違う方々も多いのではないかと思い、応募しました。「コンテナ」という、今や当たり前で特に意識せずに使っている技術について、少しだけでもどんな風に動いているのかをイメージできると役に立つことがあるかなと思うからです
  • 主催者である @magnoliak さんとは、X 上では結構ポストのやりとりがあり、昔に都内のイベントでニアミスをしているにも関わらず、直接お会いしたことがなく、お会いしたいなと思ってたんですよね。大吉祥寺.pm のお話を聞いて、「magnolia さんに会うのはこれやん」と思い応募しました。CFP 採択されなかったどうしようと少し悩んでたりしましたw

どちらかというと後者がメインだったかもww

私も連載が 10 年、自身主宰の勉強会も 10 年ってことで、少し親近感も湧きましたしね。

自分の発表「Linux コンテナの歴史を追うとコンテナの仕組みがわかる」

こんな感じで、CFP としては、ここ 10 年くらいずっと登壇して話している内容で応募しました。ほんの少し、内容はアップデートしていますし、スライド自体は過去の自分のスライドを参照しながら、書き起こしています。

speakerdeck.com

当日のトークとスライドでは、ひとつひとつの技術については、そこまでツッコんで細かく紹介はしていません。次の 2 つが伝わればいいかな程度です。今回のイベントでは、30 分という一番長い時間でしたが、時間は限られるので欲張りません。

  • コンテナは「隔離」と理解するとわかりやすい
  • Linuxでは)コンテナはカーネルに実装されている様々な機能を組み合わせて起動・動作する

昼イチの枠でした。当日、調子に乗ってペラペラ話しすぎて時間足りなくならないかな?という懸念はあったので、昼食時にビールは控えましたw 幸い、大体時間内に収まって、予定通りデモができたので、なかなか良いペースで話せたかなと思ってます。細かいところは覚えてませんがw

昼イチということで、午前中にいた人数よりは若干少なめで午後が始まった気がしましたが、きっとビールで盛り上がった方が多かったのかと想像しています。

登壇中は、大体は自分のスライドを見てたので、あまり客席の方を見れなかったのが反省ですが、それでも時折チラッと客席の方を見ると、「うんうん」とうなづいている方が見えたりしたので、安心しました。

登壇後は懐かしい方に声をかけていただいたり、Ask the Speaker で色々お声がけいただいてお話ができたりと、直後の反応もいただけて良かったです。

当日行ったデモは、後で見てもわかるようにコメントを入れてます。事前に 2 つ作って、当日は紹介出来なかったデモも公開済みですので、是非ご覧ください。(最初から 2 つめのデモはできない想定でした)

こちらは当日行ったデモ。Mount Namespace を作り、bind mount と pivot_root でコンテナのファイルシステムを作るデモです。加えて PID Namespace も紹介しました。

asciinema.org

こちらは準備したけど使わなかったデモ。Network Namespace を作り、veth インターフェースをホストとコンテナに所属させて通信するデモです。

asciinema.org

自分のはこのくらいにして、他のお話で印象的だったものの感想を。


私の発表は、すでにそこにある技術を調べて、ひたすら事実をお話するだけのトークだったのですが、他の方の発表は、総じて、世の中の方法論や、自分の経験などをもとに、自分の考えをまとめて、どうすれば◯◯が良くなるのか、という風な発表が多かったと思います。

懇親会でも話してたのですが、そういう「世の中の方法論と自分の考えから、このようにすれば良い」というようなお話は私では絶対にできないことなので、もうそれだけでみなさんすばらしいと思いました。

ここで紹介していないトークも、どれもすばらしいものでした。

基調講演

黒歴史」っておっしゃってましたが、普通にすごい人のお話としか思えませんでした。お話の中であったようなことは私には絶対にできないことなので、素直にすごいなと思いました。

開発部に不満を持っていたCSがエンジニアにジョブチェンしてわかった「勝手に諦めない」ことの大切さ

午前は席がお隣で、発表前に少しお話ができていて、「初登壇」「スライドめちゃくちゃたくさんのページ数になった」というお話を聞いていたのですが、蓋をあけると「え?初登壇?」、「全然時間きっちり収まってるし、話の流れも完璧やん」と思わせる堂々としたトークでした。

内容についても、開発と CS 両方を経験したことに基づいて、日々色々どのようにやっているか、どうやるとうまくコミュニケーションが取れるのかというお話で、納得感しかありません。それ以前に「CS時代に不満があったので開発にジョブチェンジしてしまえ」という前向きな行動自体が私にはすごすぎて真似できません。すごいとしかいいようがないです。

ランチ

この日配られる名札にはランチに何を食べたいかを記入する欄があり、それをもとにロビーで仲間を集めてランチに行くということになっていました。

私は「カレー」。昼イチの登壇だし、あまりゆっくりしてられないけど、そこそこお腹にたまるものと考えて書きましたが、意外に書いている人が少なく、それでもなんとか 5 名が集まりカレーを食べてきました。うまかった!!

カレー

歩きながら、食べながら色々なお話もできて、非常に有意義な時間でした。

さすが吉祥寺の昼ってことで、どこも混雑しており、少し並びましたが、無事午後の時間には間に合いました。

デジタルデザインのこれまでとこれから

10 年前から、1 年おきにどういう出来事が起きて、デザインがどう変わってきたかを淡々と紹介するトークでした。

語り口が良く、ユーモアも混じえて話されていて、楽しく聞けました。

僕のキャリアとワインと鍋

ソフトウェアエンジニアをやりながら「ワインと鍋」という飲食店を経営しているお話。それだけで、もうすごい人ですが、飲食店経営をどのように行っているのかに、ソフトウェア開発にもつながるような考えが取り入れているとのことで、そういう思考はできない私からすると、ただただすごいとしか思えませんでした。

話は、普段勉強会に出ても絶対聞けないようなお話だったので、普通に楽しく聞けるトークという感じでした。おもしろかったです。

「ワインと鍋」も、遠方にいる私からすると少しハードル高いですが、ぜひ一度行ってみたいと思いました。

LT

ここも、大吉祥寺.pm をぎゅっと短時間に凝縮したようなバラエティに富んだテーマが並んでいましたし、みなさん短時間ですごく上手に自分の思いを伝えていて、楽しく聞けました。(全部まとめての感想ですみません)

僕はまだ見ぬ誰かを動かすために登壇をする。

これは、基調講演ですか?って言いたいくらいの素晴らしい、今回のイベントにぴったりの内容で、個人的にはこの日一番のトークでした(多分、そう思ってる人多いはず)。

登壇することで、それを聞いた人の何かが変わる、何かが伝わる、それこそが登壇する意義ではないかということで、共感しかないお話でした。

トークの流れもすばらしく、聴衆をぐっと自分のトークに引き込む魅力的なお話で、トーク自体もすばらしいかったです。絶対真似できません。

当日参加されなかった方は、あとで動画が公開されたら、ぜひご覧になるのが良いと思います。そして、勇気を出して、登壇にチャレンジしましょう。

ナカミチさんとは、お昼もご一緒できたので良かったです。

懇親会

雰囲気の良い、広い店内のかなりの部分を使っての懇親会でした。料理もおいしかったです。テーブルにわかれて適当に着席するというスタイルでした。

懇親会

スピーカーやってても、懇親会ではぼっちになる私ですが、最初に偶然座ったテーブルのスピーカーが私だけで、話しかけていただいたおかげで、ありがたいことに結構みなさんと色々なお話ができました。

その後も、積極的に席を移動をして、かなりの方々とお話ができ、私のトークの感想をいただくこともできました。楽しかったです。ただ、限られた時間の中でテーブルの数が多すぎて、残念ながらかなりの方とお話ができませんでした。

まとめ

本当に良いイベントでした。刺激がもらえました。magnolia さんにも会えました(あまりお話出来ませんでしたが)。

このようなノンジャンルで色々な話を聞けるというのは、なかなかない機会ですし、普段勉強会に行っても絶対聞けないような話が聞けるというのは、考えてた以上に刺激になりました。

magnolia さん、スタッフのみなさま、スピーカーのみなさま、スポンサーのみなさま、参加のみなさま、本当にありがとうございました。

当日のまとめ

こちらに当日の反応がまとまっています。作成ありがとうございます!!

togetter.com

おまけ

当日の自己紹介

これは、私の当日の自己紹介スライドですが、

  • 12(金)推し活(コンサート)
  • 13(土)大吉祥寺.pm

と来たら、もう 14 日は古墳しかないでしょう

保渡田古墳群
、ってことで雨の中、高崎まで移動し、古墳を堪能してきました。せっかく東京まで来てるんだしね。土日ともに充実した日が送れました🙌