Open13
コンテナを作るとはどういうことか理解する

docker run
やkubectl apply
を実行すると内部的に何が起こるか人へ説明できる自信が無いのでまとめていく。

いつもお世話になっているfukabori.fmを聞く。
2021年の配信なのでここ数年でアップデートがあるはず。それは後でキャッチアップする。

おさらい
- コンテナとはホストOSのやその他プロセスとは隔離されたアプリケーションの実行環境
- それを作るのがコンテナランタイムの役割の1つ
- cgroups, namespaceを使って隔離する
- cgroupsはプロセスからアクセスできるデバイスを制限したり、リソースの使用量や使い方を制限する
- runcはコンテナランタイムの1種
- コンテナを隔離の境界と考えるは不十分、kernelやrunCの脆弱性によってコンテナのプロセスの外のホストへアクセスできてしまう可能性もあり、いろいろな手法がある

ランタイムの階層構造
- DockerはOCIランタイムを使ってコンテナを作成する
- k8sはCRIランタイムを使ってNode上でコンテナやイメージ群を管理し、CRIランタイムはOCIランタイムを使ってコンテナを作る
- 階層構造
- CRIランタイムの上にkubeletがいたりする
- runCはOCIランタイムの実装の1種
- docker run実行 -> dockerdへHTTP API経由で作成指示 -> dockerからrunCへ作成指示
- runCにもrunというサブコマンドがある
- k8sの場合はkubectl -> k8s(API?) -> CRIランタイム -> OCIランタイムという流れ

コンテナ作成までの流れ
- OCIの仕様にはコンテナのライフサイクル、作成や削除などの操作に関すること、コンテナの実行時情報- 実行時情報とはDockerfileに書いてあるようなENTRYPOINTや環境変数など
- docker buildを実行するとその情報がDockerイメージへ焼きつけられる
- イメージからコンテナを作成するときに、実行時情報が高レベルのランタイムからOCIランタイムまで流れ、指示通りにコンテナを作成する
docker run実行からコンテナ作成までの流れがおおよそイメージできた。

歴史
- Dockerという1つの大きなものからコミュニティの成熟により標準仕様が定められた
- rktなど他の実装もあるがコンテナの実装の互換性は壊したくない
- DockerはrunCを切り離してOCIへ移譲、OCIが仕様を定めた
- 他のランタイムも仕様に沿うことでバリエーションが増えた

k8sでPodを作成するまでの流れ
- ランタイムが関係する前の指示の流れ
- kubectl apply -> kube-apiserverへ送られてメタデータ追加 -> Podを起動するNodeを決める(kube-scheduler?) -> kubelet
- kubeletは各Node上で稼働しているエージェント
- その後
- kubeletがPod作成指示を受ける -> CRIランタイムへ指示 -> OCIランタイムへ指示
- kubelet -> CRIランタイムはUNIXソケット経由でgRPCを使って指示
- DockerはUNIXソケット経由でHTTP APIを使う
- kubelet -> Docker API経由のリクエストはdeprecated

歴史2
- CRI仕様に沿ってCRI-O, containerdというランタイム実装が出てきたことでk8sはdockershimから離れていく
- コンテナイメージが標準化されているのでCRIランタイムとは疎結合、コンテナが動かなくなるは誤解だった

まとめたはいいけど数年経っているので知識が陳腐化する懸念があったが大きな変化はなさそう。

高レベルなランタイム
- 人間がCLIを叩いて使うランタイム、k8s上で使われるCRIを実装しているランタイムの2種類がある
- 高レベルなランタイムであるcontainerdはDockerイメージをpull、展開、実行時情報を取り出して実行の準備をする
- containerdから低レベルのOCIランタイムへ指示を出す

CRI-Oとcontainerd
- CRI-Oはk8sに特化したミニマムなランタイム、containerdはプラグインシステムが成熟していて裾野の広いランタイム、イメージのpullなどもできて重厚
- k8s, CRI-Oのバージョンは同調

OCIランタイムあれこれ
- runcはGoで実装
- crunはC言語で実装
- crunのほうがパフォーマンスが良いと言われている(kernelはCで書かれていてオーバーヘッドが小さいから?)
- Kata Containersは二層防御構成
- runcはnamespaceを作成するときにcgoを使ってCのコードをGoランタイムが実行される前に実行している

OCI Image Specification
- イメージビルダーにはdocker build, BuildKit, kanicoなどがある
- Buildpacksもそう?