Container Runtime Meetup #3 https://runtime.connpass.com/event/198071/ で発表したスライドです
CRIの仕様とdockershimの実装について調べてみたContainer Runtime Meetup #3(2021/01/28)@bells17
View Slide
▶ @bells17▶ Software Engineer▶ 普段やってること:+ Kubernetes 関連コンポーネントの開発+ Kubernetes as a Service開発の調査・研究▶ Kubernetes SIG-Docs Japanese localization reviewer▶ Kubernetes Internal Organizer▶ #kubenews▶ @bells17_
今⽇話すこと▶ CRIについて▶ dockershimについて
このセッションの⽬標▶ CRIの仕様の構成と内容について、”ふわっと”知ってもらう▶ dockershimとは何か?を”ざっくりと”理解してもらう▶ dockershimがどんなふうにDockerと通信してコンテナを起動しているのか、”なんとな〜く”雰囲気を感じてもらう
注意点▶ コンテナランタイム超絶初⼼者枠です▶ ついでに以下も初⼼者です+ Linuxコンテナ+ コンテナ周りのネットワーク▶ ガチでただの調べてみた系のLTです▶ ⾼度な内容は期待しないでください!!!▶ ⼀応dockershimのコードベースはKubernetes v1.19ベースでのお話になります
アジェンダ1. CRIとは?2. dockershimとは?3. dockershimの挙動4. まとめ
CRIとは?
CRIとは?▶ CRI = Container Runtime Interface▶ Kubernetesが定義しているコンテナランタイムと連携するための仕様がCRI▶ CRIの定義はDesign Proposal(的なもの)が機能種別ごとに別れており、またあまり情報がまとまっていないので、結局現⾏の正しい?CRI全体の仕様を定義をまとめたドキュメントが無くて分かりづらい▶ ドキュメントではCRI実装のことをRuntime ShimやCRI Shimと呼んでる▶ ちなみにまだv1ではないらしい(今はbetaっぽい)
CRI定義の種別▶ Protocol Buffer/gRPC Server▶ Networking Specifications▶ Container Metrics▶ Exec/Attach/PortForward Streaming Requests▶ Container stdout/stderr logs
Protocol Buffer/gRPC Server▶ 以下の2種類のServiceに分割されている+ Runtime Service: コンテナの操作に関するもの+ Image Service: コンテナイメージの取得などに関するもの▶ Kubeletの設定値/実装を⾒る限りRuntime ServiceとImage Serviceは別々のランタイムを使い分けることが可能なように⾒える(詳細不明)▶ PodSandboxというPodのベースとなるコンテナを作り、Podで定義されたその他のコンテナがSandboxコンテナが作成したネットワーク空間などをシェアしてもらうようなモデル▶ ⼀応CRIの定義の中にLinuxコンテナだけでなく(micro)VMを使うことを想定しているようなことも書かれている(でも詳細はほぼ書いてない)https://github.com/kubernetes/community/blob/master/contributors/design-proposals/node/container-runtime-interface-v1.md
https://github.com/kubernetes/community/blob/master/contributors/design-proposals/node/runtime-client-server.mdPod作成時のフロー
https://github.com/kubernetes/community/blob/master/contributors/design-proposals/node/runtime-client-server.mdPod削除時のフロー
Networking Specifications▶ CRIのネットワーク周りに関する定義▶ “RunPodSandbox” RPC でPodネットワークを設定する必要がある▶ “StopPodSandbox” RPC でPodネットワークを停⽌?する必要がある▶ といったPod操作とその時のネットワークの操作に関する定義がざっくりとされている感じ▶ CRI networking requirements/k8s networking requirementsが満たされている限りは、CNI/CNM/その他の実装でも何でも動くようにという感じらしい+ CRI networking requirementsは“RunPodSandbox” RPC ~といった部分だと思われるhttps://github.com/kubernetes/community/blob/master/contributors/devel/sig-node/kubelet-cri-networking.md
k8s networking requirements▶ ノード上のPodが、NATなしですべてのノード上のすべてのPodと通信できること▶ systemdやkubeletなどノード上にあるエージェントが、そのノード上のすべてのPodと通信できること▶ ノードのホストネットワーク内のPodは、NATなしですべてのノード上のすべてのPodと通信できること+ 注: ホストネットワークで実⾏されるPodをサポートするプラットフォームの場合(Linuxなど)はhttps://kubernetes.io/docs/concepts/cluster-administration/networking/
Container Metrics▶ コンテナランタイムから取得できるメトリクス情報を抽象化したもの▶ 取得できるメトリクス情報がProtocol Bufferによって定義されている▶ メトリクスの取得⾃体はRuntime ServiceからRPCコールで取得できるhttps://github.com/kubernetes/community/blob/master/contributors/devel/sig-node/cri-container-stats.md
Exec/Attach/PortForward Streaming Requests▶ Exec/Attach/PortForwardそれぞれのストリーミングリクエストの⽅法について定義されている▶ Exec/Attach/PortForward⾃体はRuntime Serviceに対してRPCコールで呼び出せる▶ Exec/Attach/PortForwardリクエストをShimが受け付けるとリクエストを受け付けるサーバーを起動し、起動したサーバーのポート情報を返し、KubeletがAPI Serverからのリクエストを返されたポートにリダイレクトする▶ API ServerではリダイレクトされたShimの起動されたサーバーに接続を⾏いExec/Attach/PortForwardの処理を⾏う▶ API Server - Shim間の認証/認可はKubeletと同様に証明書などを利⽤する▶ のような感じで書いてはあるが、Kubeletの実装は書いてる事と結構違うhttps://docs.google.com/document/d/1OE_QoInPlVCK9rMAx9aybRmgFiVjHpJCHI9LrfdNM_s/edit#heading=h.4yfjiw58o8d3
Execなどでコンテナに接続するまでのフローhttps://docs.google.com/document/d/1OE_QoInPlVCK9rMAx9aybRmgFiVjHpJCHI9LrfdNM_s/edit#heading=h.4yfjiw58o8d3
Execなどでコンテナに接続するまでのフロー(実際)https://docs.google.com/document/d/1OE_QoInPlVCK9rMAx9aybRmgFiVjHpJCHI9LrfdNM_s/edit#heading=h.4yfjiw58o8d3
Container stdout/stderr logs▶ Kubernetesがコンテナのストリーミングstdout/stderrログを扱うための仕様▶ KubeletがPodSandboxコンテナ起動時に /var/log/pods// ディレクトリを作成する▶ CRI Shimは(Sandboxコンテナ以外の)各種コンテナを起動する際にコンテナのログが /var/log/pods//_.logに出⼒されるように設定を⾏う▶ ログフォーマットは以下のようになっている必要がある+ プレフィックスにRFC 3339Nano timestamp + ストリームタイプが付き+ 改⾏で終わるhttps://github.com/kubernetes/kubernetes/blob/release-1.5/docs/proposals/kubelet-cri-logging.md
dockershimとは?
dockershimとは?▶ コンテナランタイムにDockerを使⽤する際に、Kubeletが内部で起動するDocker⽤のCRI Shim実装▶ Kubelet内部でgoroutineとして起動される▶ 内部は以下の3区分のアプリケーションとなっている+ Streaming Server: kubectl execやkubectl port-forwardなどをプロキシするtcpサーバー+ gRPC Server: CRIのServiceを実装したgRPC Server+ Container Manager: コンテナプロセスのoom_score_adjの設定などを⾏う▶ Kubernetes v1.22 で削除される予定となっている▶ 主にContainer Manager周りが独⽴しておらず、その他のKubeletの処理でContainer Managerなどの操作を⾏っていたりする▶ ここらへんの保守コストが原因で削除されることになったのでは?と予想
dockershimの特徴▶ RunPodSandbox/StartContainerなどのRPCコールの裏側でDockerのライブラリを使って普通にDockerのAPI呼び出しを⾏っている▶ なので普通にdocker create/docker startのようなdockerコマンドに変換して読んでいくことが可能+ ただし、dockerコマンドで渡せる様々なオプションがどういったことをしているのかの理解は必要(誰か教えて…)▶ そのためdockerコマンドを使ってどのようにdockershimがコンテナを作成~起動などをしているかの勉強になる(気がしている)
dockershimの挙動
RunPodSandbox▶ もし⼿元にSandboxコンテナ⽤のイメージがなければ、イメージのPullを⾏う▶ Sandboxコンテナ⽤のdocker createのコンフィグを⽣成▶ docker create相当のAPIを呼び出し⽣成したコンフィグに沿ったSandboxコンテナを作成▶ 作成したコンテナのPortMapping情報など(Checkpoint)をファイルに保存▶ docker start相当のAPIを呼び出しSandboxコンテナを起動▶ resolv.confを⽣成し、Sandboxコンテナに保存▶ ネットワークプラグインを使⽤してPod間ネットワーク?を設定+ CNIを利⽤している場合にはCNIのAddNetworkListというRPCが呼び出されるよう
CreateContainer▶ 作成するコンテナ⽤のdocker createのコンフィグを⽣成▶ Sandboxコンテナの情報を元にコンフィグをアップデート▶ docker create相当のAPIを呼び出し⽣成したコンフィグに沿ってコンテナを作成
StartContainer▶ docker start相当のAPIを呼び出し対象となるコンテナを起動▶ /var/log/pods//_.log パスに起動したコンテナのログファイルのシンボリックリンクを作成
Exec(Attach/PortForwardも同じ)▶ API ServerからKubeletに/exec/{podNamespace}/{podID}/{containerName}といったWebSocketエンドポイントにGET or POSTリクエストが送られる▶ リクエストを受けるとKubeletは以下のような処理を⾏う+ 認証のためのトークンを発⾏+ 実際にコンテナにexecを⾏うための /exec/{token} エンドポイントを⽣成+ このエンドポイントにプロキシを⾏うプロキシサーバーを起動+ プロキシされて /exec/{token} にリクエストが送られると、内部でdockershimのExec RPCをリクエストする+ dockershimのExecでは内部でdocker exec相当の処理を⾏い、コンテナにexecを⾏う
まとめ
まとめ▶ Kubernetesにはコンテナランタイムとやり取りをする仕様であるContainer RuntimeInterface(CRI)がある▶ CRIではKubernetesのPodを起動したり、コンテナにexecするためのRPCコールの定義がされている▶ dockershimはDocker向けのCRI実装(CRI(Runtime) Shim)▶ dockershimはStreaming(tcp) Server/gRPC Server/Container Managerの3つのアプリケーションによって構成されている▶ dockershimの中⾝はdocker cliに変換して考えられるような実装の組み合わせになっている
感想▶ CRIの仕様はCSIに⽐べると結構ざっくりしてるなーという印象だったのですが、CRIの様々な仕様についてスライドにまとめていく過程でなんとなくCRIの仕様の全体像がイメージできる感じになってきてよかったです▶ また、dockershim側の実装についても調べることで、CRIのイメージがより具体化されたなという感じでした▶ とはいえdocker createで実際に指定しているオプション(コンフィグ)の具体的な設定値についてはまだ調べきれてないので、次はそこらへんについてまとめてみたいなと思いました
参考資料▶ Kubernetes v1.19: https://github.com/kubernetes/kubernetes/tree/release-1.19▶ CRI: the Container Runtime Interface: https://github.com/kubernetes/community/blob/master/contributors/devel/sig-node/container-runtime-interface.md▶ Container Runtime Interface (CRI) Networking Specifications: https://github.com/kubernetes/community/blob/master/contributors/devel/sig-node/kubelet-cri-networking.md▶ Container Runtime Interface: Container Metrics: https://github.com/kubernetes/community/blob/master/contributors/devel/sig-node/cri-container-stats.md▶ CRI Streaming Requests (exec/attach/port-forward): https://docs.google.com/document/d/1OE_QoInPlVCK9rMAx9aybRmgFiVjHpJCHI9LrfdNM_s/edit#heading=h.4yfjiw58o8d3▶ CRI: Log management for container stdout/stderr streams: https://github.com/kubernetes/kubernetes/blob/release-1.5/docs/proposals/kubelet-cri-logging.md▶ Client/Server container runtime: https://github.com/kubernetes/community/blob/master/contributors/design-proposals/node/runtime-client-server.md▶ Redefine Container Runtime Interface: https://github.com/kubernetes/community/blob/master/contributors/design-proposals/node/container-runtime-interface-v1.md▶ Add a new container runtime interface: https://github.com/kubernetes/kubernetes/pull/25899▶ Kubelet CRI support: https://github.com/kubernetes/enhancements/tree/master/keps/sig-node/2040-kubelet-cri▶ libnetwork design: https://github.com/moby/libnetwork/blob/master/docs/design.md▶ Kubelet network plugin for client/server container runtimes: https://github.com/kubernetes/kubernetes/issues/28667▶ Cluster Networking: https://kubernetes.io/docs/concepts/cluster-administration/networking/▶ containernetworking/cni: https://github.com/containernetworking/cni▶ Core Metrics in kubelet: https://github.com/kubernetes/community/blob/master/contributors/design-proposals/instrumentation/core-metrics-pipeline.md▶ Kubernetes monitoring architecture: https://github.com/kubernetes/community/blob/master/contributors/design-proposals/instrumentation/monitoring_architecture.md
唐突ですがKubeletについてはこの本にまとめています書いてます▶ 技術書典: http://bit.ly/tbf-kubelet▶ Booth: http://bit.ly/booth-kubeletKubeletの詳細が気になる⽅は良ければ買ってください!また▶ Kubeletの概要についてはJFT 2021 Winter▶ KubeletのコードがどんなふうになっているかはKubernetes Internal #4でそれぞれ説明してますので興味があればどうぞ!
Thanks / Question?▶ @bells17▶ Slide: https://speakerdeck.com/bells17▶ @bells17_