RunCとは何ですか?前回の記事「コンテナを実際に動作させるためのツール:runcとOCI仕様の徹底理解」では、runcとOCIについて既に説明しました。ここでは、その概念を改めて確認します。 Docker、Google、CoreOS などのベンダーが Open Container Initiative (OCI) を作成しました。OCI には現在、コンテナ ランタイム仕様とコンテナ イメージ仕様という 2 つの主要な標準ドキュメントがあります。 コンテナランタイムのOCI標準は、主にコンテナの実行状態と、ランタイムが提供する必要のあるコマンドを規定しています。次の図は、コンテナの状態遷移を示しています。
ランクの起源Dockerのlibcontainerから移行されたRunCは、コンテナの起動/停止やリソースの分離といった機能を実装しています。Dockerは、OCIコンテナランタイム標準のリファレンス実装としてRunCをOCIに寄贈しました。Dockerはデフォルトでdocker-runc実装を提供しています。実際、containerdラッパーを使用することで、Dockerデーモンの起動時にRunC実装を指定できます。当初、人々はDockerのOCIへの貢献について混乱していました。Dockerが貢献したのはコンテナを「実行」するための標準的な方法だけで、それ以上のものではありませんでした。イメージフォーマットやレジストリのプッシュ/プルフォーマットは含まれていませんでした。Dockerコンテナを実行する際、Dockerは実際には以下の手順を実行します。
Dockerの標準化は、まだ3番目のステップに過ぎません。それ以前は、コンテナランタイムはDockerがサポートするすべての機能をサポートしていると誰もが考えていました。最終的にDockerは、元のOCI仕様では「実行中のコンテナ」部分のみがランタイムを構成すると明記されていたことを明確にしました。この「概念的な乖離」は今日まで続いており、「コンテナランタイム」というトピックは紛らわしいものとなっています。この記事では、どちらの側も完全に間違っているわけではないことを示せるよう、この用語を広く使用していきます。RunCは、このOCIドキュメントに準拠したコンテナを作成できます。これは標準であるため、KataやgVisorなど、OCI準拠のコンテナランタイムである他のOCI実装も確かに存在します。 runcの使い方
コマンドラインで `runc` を使用すると、必要に応じて任意の数のコンテナを起動できます。しかし、このプロセスを自動化するには、コンテナマネージャが必要です。なぜでしょうか?数十ものコンテナを起動し、その状態を追跡する必要があると想像してみてください。これらのコンテナの一部は障害発生時に再起動する必要があり、終了時にはリソースを解放する必要があり、レジストリからイメージを取得する必要があり、コンテナ間ネットワークを構成する必要もあります。これには低レベルと高レベルの両方のコンテナランタイムが必要であり、 `runc` は低レベル実装の実装です。 低レベルおよび高レベルのコンテナランタイムコンテナランタイムといえば、runc、lxc、lmctfy、Docker(コンテナ)、rkt、crio-o など、様々な例が思い浮かぶかもしれません。これらはそれぞれ異なる目的で構築され、異なる機能を実装しています。containerd や crio-o のように、コンテナの実行に runc を使用し、イメージ管理と API を高レベルで実装しているものもあります。これらの機能(イメージの転送、管理、展開、API など)は、runc の低レベル実装と比較すると、高レベル機能と言えるでしょう。この点を踏まえると、コンテナランタイムの領域が非常に複雑であることがわかります。各ランタイムは、この低レベルから高レベルまでのスペクトルの異なる部分をカバーしています。これは非常に主観的な図です。 したがって、実際には、実行中のコンテナのみに焦点を当てたランタイムは通常「低レベルコンテナランタイム」と呼ばれ、より高度な機能(イメージ管理やgRPC/Web APIなど)をサポートするランタイムは通常「高レベルコンテナランタイム」と呼ばれます。ここでは、これらを「高レベルコンテナランタイム」、または単に「コンテナランタイム」と呼びます。低レベルコンテナランタイムと高レベルコンテナランタイムは、根本的に異なる問題に対処することに注意することが重要です。
Kubernetes は、containerd などの高レベルコンテナランタイムをサポートするだけで済みます。containerd は、OCI 仕様に従って、汎用 runc、セキュリティ強化された gvisor、より独立した runv など、さまざまな低レベルコンテナランタイムとインターフェースします。 コンテナRunCと同様に、Dockerのオープンソース製品であるcontainerdも、かつてはオープンソースのDockerプロジェクトの一部であったことがわかります。containerdもまた、自己完結型のソフトウェアです。
containerd は、シンプルさ、堅牢性、移植性を重視した業界標準のコンテナ ランタイムです。containerd は次のタスクを処理できます。
上の図は、Containerdの全体的なアーキテクチャを示しています。下から上に向かって、ContainerdはLinux、Windows、ARMなどのプラットフォームなどのオペレーティングシステムとアーキテクチャをサポートしています。これらの基盤となるオペレーティングシステム上で実行されるのは、前述のruncやgVisorなどの基盤となるコンテナランタイムです。基盤となるコンテナランタイムの上には、Containerdランタイム、コア、API、バックエンド、ストア、メタデータなどのContainerd関連コンポーネントがあります。これらのContainerdコンポーネント上に構築され、それらと対話するのがContainerdクライアントです。KubernetesがCRIを介してContainerdと対話する場合、KubernetesはContainerdクライアントとしても機能します。Containerd自体はctrと呼ばれるCRIを提供していますが、このコマンドラインツールはあまりユーザーフレンドリーではありません。 これらのコンポーネントの上には、Google Cloud、Docker、IBM、Alibaba Cloud、Microsoft Cloud、RANCHER などの実際のプラットフォームがあります。これらのプラットフォームはすでに containerd をサポートしており、一部のプラットフォームではすでに containerd をデフォルトのコンテナ ランタイムにしています。 Kubernetes の観点から見ると、ランタイム コンポーネントとして containerd を選択すると、呼び出しチェーンが短くなり、コンポーネントが少なくなり、安定性が向上し、ノード リソースの消費量が削減されます。 ドッカー2013年にリリースされたDockerは、開発者がコンテナをエンドツーエンドで実行する際に直面する多くの問題を解決しました。Dockerに含まれる機能は以下のとおりです。
当時のDockerはモノリシックなシステムでした。しかし、その機能はどれも真に相互依存していませんでした。それぞれの機能は、より小規模で集中化されたツールに実装され、連携して利用できました。各ツールは、コンテナ標準という共通フォーマットを用いて連携することができました。Docker 1.11以降、DockerデーモンはOCI標準に準拠するために複数のモジュールに分割されました。この分割後、構造は以下の部分で構成されました。 このうち、containerd はコンテナのランタイムとライフサイクル (作成、起動、停止、中止、シグナル処理、削除など) を独立して担当し、イメージの構築、ボリューム管理、ログ記録などの他のタスクは Docker デーモンの他のモジュールによって処理されます。 Docker のモジュールはオープン スタンダードを取り入れており、OCI の標準化を通じてコンテナー テクノロジが急速に発展することを期待しています。 Dockerコンテナを作成する際、Dockerデーモンはコンテナを直接作成しなくなり、代わりにcontainerdにコンテナの作成を要求します。containerdは要求を受信すると、コンテナを直接操作するのではなく、containerd-shimというプロセスを作成します。このプロセスがコンテナを操作します。コンテナプロセスには、状態の収集、標準入力の維持、ファイル記述子(fds)のオープンを処理する親プロセスが必要であることを指定します。この親プロセスがcontainerdである場合、containerdがクラッシュすると、ホストマシン上のすべてのコンテナが終了しなければなりません。shimとしてcontainerd-shimを導入することで、ライブリストア機能が提供され、この問題を回避できます。systemdのMountFlagsがslaveに設定されていることに注意してください。 コンテナを作成するには、名前空間と cgroup を構成し、ルート ファイル システムをマウントする必要があります。その後、`runc` はこの OCI ドキュメントに従って準拠したコンテナを作成できます。 コンテナは実際にはcontainerd-shimがruncを呼び出すことで起動されます。runcはコンテナを起動した後、すぐに終了します。containerd-shimはコンテナプロセスの親プロセスとなり、コンテナプロセスのステータスを収集してcontainerdに報告し、コンテナ内のpid 1のプロセスが終了した後にコンテナ内の子プロセスを引き継いでクリーンアップを行い、ゾンビプロセスが発生しないようにします。containerd、containerd-shim、そしてコンテナプロセス(つまりコンテナのメインプロセス)の3つのプロセスは相互に依存しています。ライブリストア機能がどのように保証されているかについては、「containerd、containerd-shim、runc間の依存関係」[1]を参照してください。 参照https://www.ianlewis.org/en/container-runtimes-part-1-introduction-container-r https://iximiuz.com/en/posts/コンテナ化からオーケストレーションへの旅/#コンテナ管理 https://github.com/moby/moby/issues/35873#issuecomment-386467562 [1]https://fankangbest.github.io/2017/11/24/containerd-containerd-shim%E5%92%8Crunc%E7%9A%84%E4%BE%9D%E5%AD%98%E5%85%B3%E7%B3%BB/ この記事はWeChat公式アカウント「運営と発展の物語」から転載したものです。 |