コンテナ技術の学習(Linuxのプロセス管理、カーネルの名前空間など)
Dockerの公式Docからリンクされている以下のページを読みつつメモをまとめる。
適宜Linuxシステムプログラミングなんかも参照する(ことがあるといいなぁ)。
- Not negotiable: They have to run on a single host. Okay, so two computers cannot run a single container.
- 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.
- Okay: They need to be isolated, whatever this means in detail.
- 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のルートプロセスではなくて、コンテナ自身がプロセス群でありプロセスはツリー構造なので、コンテナ自身のプロセス群のルートプロセスが存在するって意味かな。
このドキュメント(medium.com全般?)はすごい細かい要素までid属性が指定されているのでアンカーリンクが作りやすくて捗る。
chroot
というコマンドがあって、そのプロセスが認識するファイルシステムのrootを指定できると。
(ファイルシステム、でいいのかな?)
それを使うことでプロセスを隔離できるのか。
ハニーポットに使われてたってことは指定されたrootより外のファイルシステムだったり他のプロセスが使用しているメモリにはアクセスできないってことなんだろうな。
どうやってそれが実現できるんだろう。
すぐ下に書いてあった。
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を変えるだけ、だと。
rootfsをマウントする方式でも外のプロセスに干渉できる。なるほど。
We can even kill programs running outside of the jail, what a metaphor!
ウケる。
rootfs
ってナニって話はこれが答えなのかな。
This contains all binaries, libraries and the necessary file structure.
ちゃんとわかってないかも。
(細かい話)
rootfs
とルートファイルシステムは別物。
ルートファイルシステムはカーネルやライブラリのバイナリの実ファイルそのもの。
rootfs
は/
に対応するファイルシステムで、そこに「ルートファイルシステム」がマウントされる。
ルートファイルシステムはLinux OSの実体であるKernelだったりライブラリだったりで、それがrootfs
によって/
にマウントされている。
ここにおいてのマウントって何だ。
Linuxの実体を誰がいつマウントするんだ。
実ファイルは記憶デバイスにあるわけで、それを「Linux OS上の/
であるrootfs
にマウントする」のは誰がやるの?BIOSとかUEFI?
いろんな登場人物が出てくるけど
- CPUが特定メモリ番地からBIOSを起動する
- BIOSがブートローダーを起動する
- ブートローダーがディスクからファイルシステムを読んでOS(のカーネル)を起動する
- カーネルがinitrdとかinitramfs(=仮のルートファイルシステム)をマウントして実行する
- initrdとかinitramfsが実際のルートファイルシステムをマウントする、かな。
俺は「マウント」という言葉の使い方がわかってなさそうなのでこれはもっと勉強するとして、ざっくり理解した。
Linux名前空間の話になっていく。
cgroupの話も出てきたがここでびっくり、cgroupはコンテナ化技術としては名前空間が実装されたリソースのうちの一つなのね。
The idea behind a namespace is to wrap certain global system resources in an abstraction layer.
ここで言っているglobal system resources
は以下の7つ。
mnt
pid
net
ipc
uts
user
cgroup
最初「グローバルリソース」ってのがメモリとかディスクかなと思ったけど、レイヤーが違いそう。
まあプロセス(=pid
?)が分離できていれば、プロセスが使用するメモリとかのリソースはそもそも分離されている…のかな。
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プロセスでありながら他のリソースから隔離されていられるのね。
現時点での疑問
- CPUやメモリの割当管理はどうやっているの?
- 普通のプロセスだからプロセスへのCPU/メモリ管理と同じなのかな
- 普通のプロセスだとしても割当CPU/メモリってどう実現されているのか知らない
- 異なるOS間のコンテナの可搬性はどう担保されているの?
- それぞれのOSが同じように名前空間を実装しているのかな…実現できないOSもありそうに聞こえるけど
- どう名前空間を定義するべき、みたいなのはRFPとかありそう
Linuxの名前空間APIについて。
急に難しくなった気がする。
clone
clone(2)
はfork(2)
のように子プロセスを作る。
fork(2)
と違ってclone(2)
は呼び出したプロセスの実行コンテキストの一部を子プロセスとシェアすることができる。
実行コンテキストはメモリ、ファイルディスクリプタ、シグナルハンドラなど。
わからんこと:
- 実行コンテキストとは?
- ファイルディスクリプタとは?
- シグナルハンドラとは?
なんとなくだいたい分かるけど、すごくふわっとしか分からん。
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
とはなんだ。
関連付け解除なんだろうけど、ここにおける関連付けとはなんだ。
setns
setns(2)
は呼び出しもとのスレッドを渡された名前空間ファイルディスクリプタにreassociateする。
この関数は他の名前空間に参加するために使うことができる。
急にスレッドが出てきた。
スレッドは親プロセスとヒープ(プロセスメモリ)を共有するプロセス。
プロセスは必ずスレッドを持つ。シングルスレッドかマルチスレッドかだけ。
参考:https://www.baeldung.com/linux/process-vs-thread
なので、ここでのスレッドは別に特別なものじゃなくてプロセスと同じ(シングルスレッドの場合)。
あくまでもスレッドの単位で行われる処理であることを明示しているだけかな。
この参考文献、サクッとググって出てきたものだけどこれも面白いな。
スレッドの生成にもclone(2)
が使われてるのか。
まあ確かにメモリを共有している子プロセスってPIDが違うだけでかなりスレッドに近いな…。
引き続きreassociate
が分からんのと、ファイルディスクリプタが分からんことで理解が進まない。
ファイルディスクリプタはファイルの識別子。
STDINとかSTDOUTとかSTDERRの0/1/2ってファイルディスクリプタだったんだ。
入出力はすべてファイルなのかな。
参考:https://www.computerhope.com/jargon/f/file-descriptor.htm
名前空間ファイルディスクリプタは、ファイルディスクリプタテーブルを抽象レイヤーで分割したものか。
なので、setns(2)
を使うとスレッドが他の名前空間のファイルディスクリプタ(=入出力)に関連付けられて、ファイルディスクリプタを扱えるようになるのか。
確かに他の名前空間に参加している…がファイルディスクリプタだけでいいの?
例えば実行コンテキストでいうとメモリとかシグナルハンドラも含まれるんでしょ?
In September 2016 two additional namespaces were proposed (time and syslog) which are not fully implemented yet.
ふと思ったけどtime
に名前空間が導入されるとホストOSに影響を与えずにコンテナ内の日時を変更できるのかな?
最近テスト用コンテナで日時を固定したくて調べたけどdate
コマンドじゃホストOSに権限がないとだめで、しょうがなくlibfaketimeっていうライブラリを使ったんだよねー。