K8をゼロから始める| Linuxコンテナーの詳細な分析
https:// www.kubernetes.org.cn/6202.html
著者| Tang Huamin(Huamin)Alibaba Cloud Container Platformテクニカルエキスパート
この記事は、「CNCF x Alibaba Cloud Native Technology Open Class」の講義15から編集されたものです。
「Alibaba Cloud Native」パブリックアカウントに従い、キーワード「Getting Started」に返信して、K8sシリーズの記事のPPTを最初からダウンロードします。
はじめに:Linuxコンテナーは、プロセスカーネルの分離と制限を実現するための名前空間とcgroupテクノロジーに基づく、共有カーネルに基づく軽量仮想化テクノロジーです。この記事では、Dockerを例にして、コンテナーイメージとコンテナーエンジンの基本的な知識を紹介します。
容器
コンテナーはハイパーバイザーレイヤーが仮想マシンよりも1つ少ないため、軽量の仮想化テクノロジーです。最初に次の図を見てください。この図は、コンテナーの起動プロセスを簡単に説明しています。
下部はディスクで、コンテナイメージはディスクに保存されます。上位層はコンテナーエンジンで、コンテナーエンジンはdockerまたは他のコンテナーエンジンです。エンジンは、たとえば、コンテナーを作成する要求を送信します。このとき、ディスク上のコンテナーイメージをホストマシン上のプロセスとして実行します。
コンテナーの場合、最も重要なことは、このプロセスで使用されるリソースを分離して制限する方法です。Linuxカーネルでは、これら2つのテクノロジーはcgroupと名前空間によって保証されています。次に、Dockerを例にして、リソースの分離とコンテナーのミラーリングの内容を詳しく紹介します。
1.リソースの分離と制限
名前空間
名前空間はリソースの分離に使用され、Linuxカーネルには7種類の名前空間があり、最初の6種類はdockerで使用されます。7番目のcgroup名前空間はdocker自体では使用されていませんが、cgroup名前空間はrunC実装で実装されています。
最初から見てみましょう:
- 1つ目はmout名前空間です。mout名前空間は、コンテナーによって表示されるファイルシステムビューがコンテナーイメージによって提供されるファイルシステムであることを確認するためのものです。つまり、-vパラメーターによってバインドされるモードを除いて、ホストマシン上の他のファイルを表示できません。ホストに使用できます。ホスト上のいくつかのディレクトリとファイルをコンテナに表示します。
- 2つ目はuts名前空間で、主にホスト名とドメインを分離します。
- 3番目はpid名前空間です。この名前空間は、コンテナーのinitプロセスがプロセス1によって開始されることを保証します。
- 4つ目はネットワーク名前空間です。コンテナネットワークモードに加えて、他のすべてのネットワークモードには独自のネットワーク名前空間ファイルがあります。
- 5番目はユーザーの名前空間です。この名前空間は、コンテナーとホストマシン内のユーザーUIDとGIDを制御するマッピングですが、この名前空間はあまり使用されません。
- 6番目はIPC名前空間で、この名前空間は、セマフォなどのプロセスと通信を制御するものです。
- 7つ目はcgroup名前空間です。上の図の右側には、cgroup名前空間を開閉するための2つの概略図があります。cgroup名前空間を使用する利点の1つは、コンテナに表示されるcgroupビューがルートの形式で表示されることです。この場合、これは、ホストマシンのプロセスで表示されるcgroup名前空間のビューと同じです。別の利点はコンテナー内でcgroupを使用する方が安全です。
ここでは、単にunshareを使用して、名前空間を作成するプロセスをサンプリングします。コンテナ内の名前空間の作成は、実際にはunshareシステムコールを使用して作成されます。
上の図の上部はunshareの使用例で、下部はunshareコマンドで実際に作成したpid名前空間です。bashプロセスがすでに新しいpid名前空間にあることがわかります。次に、psは、bash pidが1であることを確認します。これは、それが新しいpid名前空間であることを示しています。
cgroup
2つのcgroupドライバー
cgroupは主にリソースの制限に使用されます。Dockerコンテナーには2つのcgroupドライバーがあります。1つはsystemdで、もう1つはcgroupfsです。
- cgroupfsは理解しやすいです。たとえば、どのくらいのメモリを制限し、どれだけのCPUシェアを使用する必要がありますか?実際、pidを対応するcgroupファイルに直接書き込んでから、対応するメモリcgroupファイルとCPU cgroupファイルに制限する必要がある対応するリソースを書き込みます。
- もう1つはsystemdのcgroupドライバーです。このドライバは、systemd自体がcgroup管理方法を提供できるためです。したがって、systemdをcgroupドライバーとして使用する場合、すべてのcgroup書き込み操作はsystemdインターフェースを介して完了する必要があり、cgroupファイルを手動で変更することはできません。
コンテナーで一般的に使用されるcgroup
次に、コンテナーで一般的に使用されるcgroupを確認します。Linuxカーネル自体はさまざまなcgroupを提供しますが、dockerコンテナーは次の6つのタイプのみを使用します。
- 1つ目はCPUです。CPUは通常、CPU使用率を制御するためにCPUシェアとカップセットを設定します。
- 2つ目はメモリで、使用するプロセスメモリの量を制御します。
- 3番目のデバイスであるデバイスは、コンテナーに表示されるデバイスデバイスを制御します。
- 4番目の冷凍庫。それと3番目のcgroup(デバイス)はセキュリティ用です。コンテナーを停止すると、フリーザーは現在のすべてのプロセスをcgroupに書き込み、すべてのプロセスをフリーズします。これは、停止したときにフォークを実行しないようにするためです。この場合、セキュリティ上の理由から、プロセスがホストマシンにエスケープしないようにすることと同じです。
- 5番目はblkioです。Blkioは主に、コンテナーが使用するディスクのIOPSとbpsのレート制限の一部を制限します。cgroupは一意ではないため、blkioは同期ioのみを制限でき、docker ioは制限する方法がありません。
- 6番目はpid cgroupで、コンテナーで使用できるプロセスの最大数を制限します。
未使用のcgroup
Dockerコンテナーで使用されていないcgroupの一部もあります。コンテナーは一般的に使用され、一般的には使用されません。この違いはdockerです。runCの場合、下部のrdmaを除き、すべてのcgroupが実際にrunCでサポートされますが、Dockerはこのサポートの一部を有効にしません、したがって、以下に示すように、Dockerコンテナーはこれらのcgroupをサポートしません。
次に、コンテナイメージ
ドッカー画像
次に、コンテナーイメージについて説明します。例として、Dockerイメージを使用してコンテナーイメージの構成について説明します。
Dockerイメージは、ジョイントファイルシステムに基づいています。ジョイントファイルシステムについて簡単に説明します。これは、ファイルをさまざまなレベルで保存できることを意味しますが、最終的には、これらのレベルより上のすべてのファイルを統合ビューで表示できます。
上の図に示すように、右側は、Dockerの公式Webサイトから取得したコンテナーストレージの構造図です。
この図は、結合ファイルシステムに基づいており、階層化されているdockerのストレージを非常に鮮やかに示しています。各レイヤーはレイヤーであり、これらのレイヤーは異なるファイルで構成されており、他のミラーで再利用できます。ご覧のとおり、イメージがコンテナとして実行される場合、最上位のレイヤはコンテナの読み取り/書き込みレイヤになります。このコンテナーの読み取り/書き込みレイヤーは、commitを使用して、ミラーの最上位レベルの最新レイヤーに変換することもできます。
Dockerイメージのストレージはさまざまなファイルシステムに基づいているため、そのストレージドライバーも、AUFS、btrfs、devicemapper、overlayなどのさまざまなファイルシステム用にカスタマイズされています。Dockerはこれらのファイルシステムに対応するグラフドライバードライバーをいくつか作成し、これらのドライバーを介してイメージをディスクに保存します。
例としてオーバーレイを取り上げます
保管プロセス
次に、オーバーレイファイルシステムを例にして、Dockerイメージがディスクにどのように格納されているかを確認します。
まず、オーバーレイファイルシステムの動作原理を簡単に説明した次の図を見てください。
- 最下層は下位層、つまり読み取り専用層であるミラー層です。
- 右上のレイヤーは上のレイヤーです。上のレイヤーはコンテナの読み書きレイヤーです。上のレイヤーは現実的なコピーメカニズムを使用しています。つまり、特定のファイルを変更する必要がある場合にのみ、このファイルが下のレイヤーからコピーされます。変更操作は、上位層のコピーを変更します。
- 並行して作業ディレクトリがあり、その役割は中間層として機能することです。つまり、上位層のコピーが変更されると、最初にworkdirに配置されてから、workdirから上位に移動されますこれがオーバーレイの機能メカニズムです。
- 上部は統合されたビューレイヤーであるmergedirです。mergedirから、上と下のすべてのデータの統合を確認できます。次に、コンテナーにdocker execを実行すると、ファイルシステムが実際にmergedirの統合ビューレイヤーであることがわかります。
ファイル操作
次に、オーバーレイストレージに基づいてコンテナー内のファイルを操作する方法について説明します。
最初に読み取り操作を見てみましょう。コンテナが最初に作成されたとき、上部は実際には空でした。この時点で読み取ると、すべてのデータが下位層から読み取られます。
前述のように、オーバーレイの上位層にはデータを実現するためのメカニズムがあり、一部のファイルを操作する必要がある場合は、オーバーレイがコピーアップアクションを実行してから、下位層からファイルがコピーされます。一部の書き込み変更はこの部分で動作します。
次に、削除操作を見てください。オーバーレイには実際の削除操作はありません。いわゆる削除とは、実際にはファイルをマークしてから、最上位の統合ビューレイヤーを調べることです。このファイルがマークされている場合は、ファイルが表示され、ファイルが削除されたと見なされます。これをマークするには2つの方法があります。
- 1つはホワイトアウトメソッドです。
- 2つ目は、ディレクトリの拡張アクセス権を設定し、拡張パラメータを設定して、ディレクトリを削除することです。
操作手順
次に、実際にdocker runを使用してbusyboxを開始するコンテナーを見てみましょう。オーバーレイマウントポイントはどのように見えますか?
2番目の画像はマウントです。コンテナーrootfsのマウントを確認できます。マウントとしてのオーバーレイタイプです。これには、upper、lower、workdirの3つのレベルが含まれます。
次に、コンテナー内の新しいファイルの書き込みを確認します。docker execは新しいファイルを作成します、diffは上から見ることができ、それはその上位ディレクトリです。upperdirでこのファイルを確認すると、ファイルの内容もdocker execによって書き込まれます。
最後に、一番下のmergedirを見てください。mergedirに統合されたupperdirとlowerdirの内容は、私たちが書いたデータも見ることができます。
3. Container Engine
詳細なコンテナー化コンテナーアーキテクチャ
次に、CNCFのコンテナーエンジンのcontainerdに基づいて、コンテナーエンジンの一般的な構成について説明します。次の図は、containerdの公式Webサイトから取得したアーキテクチャー図であり、このアーキテクチャー図に基づいて、containerdのアーキテクチャーの概要を最初に紹介します。
上記の図を左右に分割すると、containerdは2つの主要な機能を提供すると見なすことができます。
1つ目はランタイムの管理、つまりコンテナのライフサイクルであり、左側のストレージ部分は実際にはイメージストレージの管理です。containerdは、プルとイメージの保管を担当します。
レベルに関して:
- 最初の層はGRPCです。上位層の場合、containerdはGRPC serveを介して上位層にサービスを提供します。メトリックこのセクションでは、主にcgroupメトリックのいくつかのコンテンツを提供します。
- 下のレイヤーの左側はコンテナイメージのストレージです。正中線のイメージとコンテナはメタデータの下にあります。メタデータのこの部分は、bootfsを介してディスクに保存されます。右側のタスクは、コンテナを管理するコンテナ構造です。イベントとは、コンテナの一部の操作でイベントが上位層に送信され、上位層がこのイベントをサブスクライブして、コンテナの状態にどのような変化があったかを知ることです。
- 最下層はランタイム層で、ランタイムはrunCやセキュアコンテナーなどのタイプで区別できます。
シムv1 / v2とは
次に、ランタイム側のコンテナー化の一般的なアーキテクチャーについて説明します。次の画像は、kataの公式Webサイトから取得したもので、上部が元の画像で、下部にいくつかの拡張された例が追加されています。この画像に基づいて、実行時のコンテナー化のアーキテクチャーを見てみましょう。
図に示すように、左から右のシーケンスに従って、上位層から最終ランタイムまで実行されるプロセス。
最初に左端のCRIクライアントを見てみましょう。一般に、kubeletはCRIリクエストを介してコンテナにリクエストを送信します。containerdがコンテナーリクエストを受信すると、コンテナー化されたシムを通過します。containerdシムは、コンテナのライフサイクルを管理します。主に次の2つの側面を担当します。
- 1つ目はioを転送することです。
- 2つ目は、信号を渡すことです。
図の上部は安全なコンテナ、つまり型のプロセスを描いています。これは詳細には展開されません。後半はシムの種類が違うことがわかります。以下にコンテナシムの構造を紹介します。
最初は、containerdにシムが1つだけありました。これは、青いボックスで囲まれたcontainerd-shimです。このプロセスが意味することは、それがkataコンテナー、runcコンテナー、またはgvisorコンテナーのいずれであっても、上記で使用されたシムはすべてコンテナー化されているということです。
その後、containerdはさまざまなタイプのランタイム用の拡張を行いました。この拡張は、shim-v2インターフェースを介して行われます。つまり、shim-v2インターフェースが実装されている限り、ランタイムごとに異なるshimをカスタマイズできます。たとえば、runCは、shim-runcと呼ばれるそれ自体でシムを作成できます; gvisorは、shim-gvisorと呼ばれるそれ自体でシムを作成できます;上記のkataのように、自分でshim-kata shimを作成することもできます。これらのシムは、上の青いボックスのコンテナー化されたシムを置き換えることができます。
そうすることには多くの利点があります。より鮮明な例を挙げてください。カタの写真をご覧ください。shim-v1を使用した場合、実際には3つのコンポーネントがあります。3つのコンポーネントがある理由は、カタ自体の制限のためですが、shim-v2アーキテクチャを使用した後、3つのコンポーネントバイナリ、つまり元の3つのコンポーネントにできますが、今ではシムカタコンポーネントに変換できます。
コンテナー化されたコンテナーアーキテクチャー-コンテナープロセスの例の詳細な説明
次に、2つの例を使用して、コンテナープロセスのしくみを詳しく説明します。次の2つの図は、コンテナーアーキテクチャに基づくコンテナーワークフローです。
開始プロセス
最初にコンテナーの開始プロセスを確認します。
この画像は3つの部分で構成されています。
- 最初の部分はコンテナエンジンの部分です。コンテナエンジンはドッカーまたはその他の部分です。
- 2つの破線のボックスで囲まれたContainerdおよびContainerd-Shim。どちらもContainerdアーキテクチャの一部です。
- 下の部分はコンテナー部分で、この部分はランタイムによってプルアップされ、runCコマンドを操作するためにshimによって作成されたコンテナーと見なすことができます。
このプロセスの仕組みを見てみましょう。図には、1、2、3、および4も示されています。この1、2、3、4は、containerdがコンテナを作成する方法です。
最初に、それはmatadataを作成し、次にコンテナーを作成する要求をタスクサービスに送信します。中央の一連のコンポーネントを介して、リクエストは最終的にシムに送信されます。containerdとshimの間の相互作用は実際にはGRPCを介して行われます。containerdが作成リクエストをshimに送信した後、shimはランタイムを呼び出してコンテナを作成します。上記はコンテナの開始の例です。
実行プロセス
次に、この画像がどのようにコンテナーを実行するかを確認します。
これは開始プロセスと非常によく似ており、構造もおそらく同じですが、実際には、containerdがプロセスのこの部分を処理する方法が異なります。上の図のように、図でも1、2、3、4とマークしました。これらの手順は、execdを実行するためのcontainerdのシーケンスを表しています。
上の図からわかるように、execの操作は引き続きcontainerd-shimに送信されます。コンテナーの場合、コンテナーの開始とコンテナーの実行の間に本質的な違いはありません。
最後の違いは、コンテナーで実行されているプロセスの名前空間を作成するかどうかだけです。
- 実行するときは、このプロセスを既存の名前空間に追加する必要があります。
- 開始時に、コンテナープロセスの名前空間を具体的に作成する必要があります。
この記事は要約します
最後に、この記事を読んだ後は、Linuxコンテナーについて理解を深めていただければ幸いです。ここにすべての人のための簡単な要約があります:
- コンテナーがリソースの分離に名前空間を使用し、リソースの制限にcgroupを使用する方法。
- オーバーレイファイルシステムに基づくコンテナーイメージストレージを簡単に紹介しました。
- コンテナエンジンの仕組みを紹介する例として、docker + containerdを取り上げます。
「AlibabaクラウドネイティブWeChatパブリックアカウント(ID:Alicloudnative)は、マイクロサービス、サーバーレス、コンテナ、サービスメッシュなどの技術分野に焦点を当て、クラウドネイティブの一般的なテクノロジートレンド、およびクラウドネイティブの大規模なランディングプラクティスに焦点を当てています。技術公開アカウント。」