Slide 1

Slide 1 text

runcのUNIXプログラミング ryotaro612 2024 年 12 月 9 日

Slide 2

Slide 2 text

目次 1. 導入 2. ホストとコンテナの端末間通信 3. 名前空間 4. ファイルシステムの変更 5. 伝えたかったこと 1

Slide 3

Slide 3 text

runc 低レベルなコンテナランタイムのCLI Docker, runc, OS の階層1 1containerd vs. Docker: Understanding Their Relationship and How They Work Together より 2

Slide 4

Slide 4 text

抽象度の低いrunc イメージは不要、コンテナのルート/で十分 mkdir rootfs # busybox の/以下を rootfs にコピー docker export $(docker create busybox) | \ tar -C rootfs -xvf - # コンテナを起動するパラメタの雛形を./config.json に出力 runc spec # コンテナ ID を cid としてコンテナを起動 runc --root /tmp/runc run cid # /bin/sh を実行中のコンテナにアタッチ runc でコンテナの sh を開始 3

Slide 5

Slide 5 text

資料の目的 UNIXプログラミングの基本的な道具を知る Infrastructure Plumbing Manifesto2 When you need to create new plumbing, make it easy to re- use and contribute improvements back. Follow the unix principles: several simple components are better than a single, complicated one. Define standard interfaces which can be used to combine many simple components into a more sophisticated system. runc は UNIX の原則による小さな機能を組合せ 2docker のブログ Introducing runC: a lightweight universal container runtime より 4

Slide 6

Slide 6 text

runc runの手続き runの呼出すinitがコンテナになる SIGCHLDをうける run initのptsと通信するチャネルをつくる run initを非同期実行 パイプからの通信を待つ Cのnsexec関数で名前空間を切替 execveでinitをshに置換 疑似端末をつくる exit init コンテナの構造体をつくる コンテナの起動を通知する名前付きパイプをつくる sh 正常な起動をパイプに通知 exit run と init コマンドの手続き init はコンテナの PID 1 のプロセスになる 5

Slide 7

Slide 7 text

目次 1. 導入 2. ホストとコンテナの端末間通信 3. 名前空間 4. ファイルシステムの変更 5. 伝えたかったこと 6

Slide 8

Slide 8 text

疑似端末 pty ptyはキャラクタデバイスのマスタ、スレーブの組[1] ∘ マスタ/dev/ptmx を開くと/dev/pts 下にスレーブができる ∘ 一方の入力が他方の出力になる ∘ ptsname 関数にマスタのファイル記述子を渡すとスレーブの パスがわかる ∘ 通常、プロセスはマスタを開いて fork する。子プロセスはス レーブを複製して標準 I/O, エラーにする[2]3 3ls -l /proc//fd で記述子 0, 1, 2 がスレーブへのリンクか分かる 7

Slide 9

Slide 9 text

runcでのptyの準備 initはrunにマスタのファイル記述子を送る4 1. run は socketpair でソケットの組をつくる。双方向通信 できる 2. run は Cmd.ExtraFiles でソケットを 1 つ init にわたす 3. init は/dev/ptmx を開く 4. init は sendmsg でソケットを通してマスタを run に送る 5. run はマスタの入出力を標準 IO にコピーする 4次ページより上の手続きの実装を確認する 8

Slide 10

Slide 10 text

init マスタを開き、その記述子をrunに送る pty, slavePath, err ^:= console.NewPty() ^// 中略 if err ^:= utils.SendRawFd( socket, pty.Name(), pty.Fd()); err ^!= nil { return err } setupConsole 関数の抜粋 9

Slide 11

Slide 11 text

init dup3でスレーブを複製 fd, err ^:= unix.Open(slavePath, unix.O_RDWR, 0) ^// 中略 for _, i ^:= range []int{0, 1, 2} { if err ^:= unix.Dup3(fd, i, 0); err ^!= nil { return err dupStdio 関数の抜粋 コードの 0, 1, 2 は標準 IO, エラー出力の記述子 10

Slide 12

Slide 12 text

init スレーブをプロセスの制御端末にする[3] if err ^:= unix.IoctlSetInt(0, unix.TIOCSCTTY, 0); e return err } Setctty 関数の抜粋 11

Slide 13

Slide 13 text

run ホストの標準入力をマスタに書き、マスタの出力を ホストの標準出力に送る f, err ^:= utils.RecvFile(socket) ^// 中略 socket からマスタの記述子を取得 go func() { _, _ = io.Copy(epollConsole, os.Stdin) }() t.wg.Add(1) go t.copyIO(os.Stdout, epollConsole) recvtty 関数の抜粋 epoll でマスタの入出力を監視 12

Slide 14

Slide 14 text

目次 1. 導入 2. ホストとコンテナの端末間通信 3. 名前空間 4. ファイルシステムの変更 5. 伝えたかったこと 13

Slide 15

Slide 15 text

名前空間[4] 空間のプロセスには自分達がリソースを占有したよう に見える ∘ マウントポイント、プロセス ID など 6 種類の名前空間がある ∘ 名前空間の間でリソース名が重複しても互いに影響しない ∘ API clone 新しいプロセスを作る。子プロセスを新しい名前空 間に入れることもできる setns 呼びだしたスレッドを既存の名前空間に入れる。用 途はコンテナ間でのネットワークの共有など unshare 指定した種類の名前空間を作り、呼びだしたプロセ スを移動する 14

Slide 16

Slide 16 text

nsexecでinitの名前空間を移動 Goの前にCのnsexec関数を実行する ^/* #cgo CFLAGS: -Wall extern void nsexec(); void <中略> init(void) { nsexec(); } ^*/ import "C" nsenter.go の抜粋 Go のランタイムには複数のスレッドがあるが、setns は呼びだ したスレッドの名前空間のみを移動する[5] 15

Slide 17

Slide 17 text

nsexec cloneでpid 1を割り当てる ∘ clone に CLONE_PARENT を 渡すことで、新しい init の 親プロセスを常に run にし、 SIGCHLD を run に届ける ∘ uid_map, gid_map には、 親と子の名前空間のユーザ、 グループ ID の写像を書く[6] init runからsetns対象の 名前空間を受信 clone setns pid /proc/pid/uid_map /proc/pid/gid_map 更新 unshare clone setuid(0) setgid(0) init init returnしてGoのmainへ exit exit nsexec の処理手順 unshare では呼出元のプロセス名前空間を変更できない[7] 16

Slide 18

Slide 18 text

目次 1. 導入 2. ホストとコンテナの端末間通信 3. 名前空間 4. ファイルシステムの変更 5. 伝えたかったこと 17

Slide 19

Slide 19 text

initのルートファイルシステムを変更 pivot_rootでファイルシステムを変更する cd rootfs ^&& mkdir put_old # 新しいマウントポイントの名前空間に移動 unshare -mpfr /bin/sh # pivot_root の引数はマウントポイントでないとだめ mount --bind $(pwd) $(pwd) # put_old にもとのルートをおく。後で unmount 可 pivot_root $(pwd) $(pwd)/put_old pivot_root の実行例 18

Slide 20

Slide 20 text

目次 1. 導入 2. ホストとコンテナの端末間通信 3. 名前空間 4. ファイルシステムの変更 5. 伝えたかったこと 19

Slide 21

Slide 21 text

実装とPlumbling Manifestoをくらべて コンテナの基礎の実装に特別なからくりはない ∘ 標準のインターフェース ∘ 端末, 名前空間、マウントは互いに異質だが、どれ も/proc 下のディレクトリ (ns, fd, mounts) にファイル として、その状態が公開されている ∘ ファイル開き、返った記述子を関数に渡して操作できる ∘ 小さな機能の組合せ ∘ コンテナに用途を限らない機能で実装されている5 ∘ runc 自体も抽象度の高い API から組合せられて使われる 5clone の CLONE_NEWIPC などコンテナのために用意された機能も一部ある[8] 20

Slide 22

Slide 22 text

参考資料 [1] M. Kerrisk, ``pty(7) - Linux manual page,'' (2024), [Online]. Available: https://man7.org/linux/man-pages/man7/pty.7.html (visited on 11/29/2024). [2] V. G. Teodorovici, ``Advanced programming in the unix environment, third edition by w. richard stevens and stephen a. rago,'' SIGSOFT Softw. Eng. Notes, vol. 38, no. 6, p. 45, Nov. 2013, ISSN: 0163-5948. DOI: 10.1145/2532780.2532798. [Online]. Available: https://doi.org/10.1145/2532780.2532798. [3] M. Kerrisk, ``TIOCSCTTY(2const) - Linux manual page,'' (2024), [Online]. Available: https://man7.org/linux/man- pages/man2/TIOCSCTTY.2const.html (visited on 11/30/2024). 21

Slide 23

Slide 23 text

参考資料 [4] M. Kerrisk, ``namespaces(7) - Linux manual page,'' (2024), [Online]. Available: https://man7.org/linux/man- pages/man7/namespaces.7.html (visited on 11/30/2024). [5] Open Container Initiative, ``Runc,'' (2015), [Online]. Available: https://github.com/opencontainers/runc (visited on 11/23/2024). [6] M. Kerrisk, ``user_namespaces(7) - Linux manual page,'' (2024), [Online]. Available: https://man7.org/linux/man- pages/man7/user_namespaces.7.html (visited on 06/15/2024). 22

Slide 24

Slide 24 text

参考資料 [7] M. Kerrisk, ``unshare(2) - Linux manual page,'' (2024), [Online]. Available: https://man7.org/linux/man-pages/man2/unshare.2.html (visited on 06/15/2024). [8] M. Kerrisk, ``clone(2) - Linux manual page,'' (2024), [Online]. Available: https://man7.org/linux/man-pages/man2/clone.2.html (visited on 12/03/2024). 23