Open21

コンテナ技術の学習(Linuxのプロセス管理、カーネルの名前空間など)

teslurteslur

https://medium.com/@saschagrunert/demystifying-containers-part-i-kernel-space-2c53d6979504#1d78

  1. Not negotiable: They have to run on a single host. Okay, so two computers cannot run a single container.
  2. Clearly: They are groups of processes. You might know that Linux processes live inside a tree structure, so we can say containers must have a root process.
  3. Okay: They need to be isolated, whatever this means in detail.
  4. Not so clear: They have to fulfill common features. Features in general seem to change over time, so we have to point out what the most common features are.

containers must have a root process. がちょっと分かりにくい。
コンテナのプロセスが走っているホストOSのルートプロセスではなくて、コンテナ自身がプロセス群でありプロセスはツリー構造なので、コンテナ自身のプロセス群のルートプロセスが存在するって意味かな。

teslurteslur

このドキュメント(medium.com全般?)はすごい細かい要素までid属性が指定されているのでアンカーリンクが作りやすくて捗る。

teslurteslur

chrootというコマンドがあって、そのプロセスが認識するファイルシステムのrootを指定できると。
(ファイルシステム、でいいのかな?)

それを使うことでプロセスを隔離できるのか。
ハニーポットに使われてたってことは指定されたrootより外のファイルシステムだったり他のプロセスが使用しているメモリにはアクセスできないってことなんだろうな。
どうやってそれが実現できるんだろう。

teslurteslur

すぐ下に書いてあった。

The current working directory is left unchanged when calling chroot via a syscall, whereas relative paths can still refer to files outside of the new root. This call changes only the root path and nothing else.

相対パスとかは参照が残り続けるし、あくまでrootを変えるだけ、だと。

teslurteslur

rootfsをマウントする方式でも外のプロセスに干渉できる。なるほど。

We can even kill programs running outside of the jail, what a metaphor!

ウケる。

teslurteslur

rootfsってナニって話はこれが答えなのかな。

This contains all binaries, libraries and the necessary file structure.

ちゃんとわかってないかも。

teslurteslur

(細かい話)
rootfsとルートファイルシステムは別物。
ルートファイルシステムはカーネルやライブラリのバイナリの実ファイルそのもの。
rootfs/に対応するファイルシステムで、そこに「ルートファイルシステム」がマウントされる。

https://www.wdic.org/w/TECH/rootfs (Linux)

teslurteslur

ルートファイルシステムはLinux OSの実体であるKernelだったりライブラリだったりで、それがrootfsによって/にマウントされている。
https://www.ibm.com/docs/pl/aix/7.1?topic=tree-root-file-system

ここにおいてのマウントって何だ。
Linuxの実体を誰がいつマウントするんだ。
実ファイルは記憶デバイスにあるわけで、それを「Linux OS上の/であるrootfsにマウントする」のは誰がやるの?BIOSとかUEFI?

teslurteslur

https://keichi.dev/post/linux-boot/

いろんな登場人物が出てくるけど

  1. CPUが特定メモリ番地からBIOSを起動する
  2. BIOSがブートローダーを起動する
  3. ブートローダーがディスクからファイルシステムを読んでOS(のカーネル)を起動する
  4. カーネルがinitrdとかinitramfs(=仮のルートファイルシステム)をマウントして実行する
  5. initrdとかinitramfsが実際のルートファイルシステムをマウントする、かな。

俺は「マウント」という言葉の使い方がわかってなさそうなのでこれはもっと勉強するとして、ざっくり理解した。

teslurteslur

Linux名前空間の話になっていく。

https://medium.com/@saschagrunert/demystifying-containers-part-i-kernel-space-2c53d6979504#a5a4

cgroupの話も出てきたがここでびっくり、cgroupはコンテナ化技術としては名前空間が実装されたリソースのうちの一つなのね。

The idea behind a namespace is to wrap certain global system resources in an abstraction layer.

ここで言っているglobal system resourcesは以下の7つ。

  1. mnt
  2. pid
  3. net
  4. ipc
  5. uts
  6. user
  7. cgroup

最初「グローバルリソース」ってのがメモリとかディスクかなと思ったけど、レイヤーが違いそう。
まあプロセス(=pid?)が分離できていれば、プロセスが使用するメモリとかのリソースはそもそも分離されている…のかな。

teslurteslur

Linux名前空間が何をやっているのかというと

The idea behind a namespace is to wrap certain global system resources in an abstraction layer. This makes it appear like the processes within a namespace have their own isolated instance of the resource.

名前空間はグローバルリソースをwrapする抽象レイヤーだと。
で、抽象レイヤーがリソースを分割してくれるから、分割されたリソースの中にいるプロセスは自身がそのリソースを専有しているように見える。
抽象レイヤーで分割されているから他の名前空間に割り当てられたリソースは見えないんだろうな。

これをLinuxのOSレベルでやっている前提があるからコンテナ技術はOS上の1プロセスでありながら他のリソースから隔離されていられるのね。

teslurteslur

現時点での疑問

  • CPUやメモリの割当管理はどうやっているの?
    • 普通のプロセスだからプロセスへのCPU/メモリ管理と同じなのかな
    • 普通のプロセスだとしても割当CPU/メモリってどう実現されているのか知らない
  • 異なるOS間のコンテナの可搬性はどう担保されているの?
    • それぞれのOSが同じように名前空間を実装しているのかな…実現できないOSもありそうに聞こえるけど
    • どう名前空間を定義するべき、みたいなのはRFPとかありそう
teslurteslur

Linuxの名前空間APIについて。
急に難しくなった気がする。

https://medium.com/@saschagrunert/demystifying-containers-part-i-kernel-space-2c53d6979504#af7b

teslurteslur

clone

clone(2)fork(2)のように子プロセスを作る。
fork(2)と違ってclone(2)は呼び出したプロセスの実行コンテキストの一部を子プロセスとシェアすることができる。
実行コンテキストはメモリ、ファイルディスクリプタ、シグナルハンドラなど。

わからんこと:

  • 実行コンテキストとは?
  • ファイルディスクリプタとは?
  • シグナルハンドラとは?

なんとなくだいたい分かるけど、すごくふわっとしか分からん。

teslurteslur

unshare

unshare(2)はプロセスが他のプロセスと共有している実行コンテキストをdisassociateできる。

まずこのparts ofをどう訳せばいいのか分からん。

The function unshare(2) allows a process to disassociate parts of the execution context which are currently being shared with others.

「実行コンテキストの一部(=実行コンテキストのうち他のプロセスと共有しているもの)」なのか、「実行コンテキストのうち他のプロセスと共有しているもの、の一部」なのかどっちだ…。
前者は共有しているものは一括で処理、後者は共有しているものの一部を処理。

そしてdisassociateとはなんだ。
関連付け解除なんだろうけど、ここにおける関連付けとはなんだ。

teslurteslur

setns

setns(2)は呼び出しもとのスレッドを渡された名前空間ファイルディスクリプタにreassociateする。
この関数は他の名前空間に参加するために使うことができる。

急にスレッドが出てきた。
スレッドは親プロセスとヒープ(プロセスメモリ)を共有するプロセス。
プロセスは必ずスレッドを持つ。シングルスレッドかマルチスレッドかだけ。
参考:https://www.baeldung.com/linux/process-vs-thread

なので、ここでのスレッドは別に特別なものじゃなくてプロセスと同じ(シングルスレッドの場合)。
あくまでもスレッドの単位で行われる処理であることを明示しているだけかな。

この参考文献、サクッとググって出てきたものだけどこれも面白いな。
スレッドの生成にもclone(2)が使われてるのか。
まあ確かにメモリを共有している子プロセスってPIDが違うだけでかなりスレッドに近いな…。

引き続きreassociateが分からんのと、ファイルディスクリプタが分からんことで理解が進まない。

teslurteslur

ファイルディスクリプタはファイルの識別子。
STDINとかSTDOUTとかSTDERRの0/1/2ってファイルディスクリプタだったんだ。
入出力はすべてファイルなのかな。
参考:https://www.computerhope.com/jargon/f/file-descriptor.htm

名前空間ファイルディスクリプタは、ファイルディスクリプタテーブルを抽象レイヤーで分割したものか。
なので、setns(2)を使うとスレッドが他の名前空間のファイルディスクリプタ(=入出力)に関連付けられて、ファイルディスクリプタを扱えるようになるのか。

確かに他の名前空間に参加している…がファイルディスクリプタだけでいいの?
例えば実行コンテキストでいうとメモリとかシグナルハンドラも含まれるんでしょ?

teslurteslur

In September 2016 two additional namespaces were proposed (time and syslog) which are not fully implemented yet.

ふと思ったけどtimeに名前空間が導入されるとホストOSに影響を与えずにコンテナ内の日時を変更できるのかな?
最近テスト用コンテナで日時を固定したくて調べたけどdateコマンドじゃホストOSに権限がないとだめで、しょうがなくlibfaketimeっていうライブラリを使ったんだよねー。
https://github.com/wolfcw/libfaketime

teslurteslur

Linuxのクロックって色々あるのね。
CLOCK_REALTIMEが普通にdateで変更したり参照したりできるやつで、これはtime namespaceが導入されても対象にはなってないのか。