I. 容器
単一の物理マシンから多数の仮想マシンを仮想化することは、リソースの作成において一定の柔軟性を実現する方法です。しかし同時に、仮想化のアプローチはまだ非常に複雑であることがわかります。これはちょっと似ていて、子会社を設立しに行くようなもので、会社は小さいですが、結局のところ、それはいくつかの独立した会社であり、スパローズであり、すべての臓器であり、したがって、前の章で見たように、CPU、メモリ、ネットワーク、ハードディスクはすべて仮想化する必要があり、1つは怠ることはできません。では、多くのハードウェアを仮想化する手間をかけずに、リソースの一部を特定のプロセス専用に分離する、より柔軟な方法はないのでしょうか?結局のところ、最終的に私が実行したいのは、Linuxシステム全体ではなく、1つのプログラムだけなのです。
Linuxオペレーティング・システムには、それを実現するコンテナと呼ばれる新技術があります。
コンテナは英語でContainerと呼ばれ、コンテナ別の意味は「容器」です。実際には、コンテナは、異なる商品と船の異なるコンテナのようなものです、隔離の一定程度がありますが、隔離はそれほど良いではありません、ちょうど単純なパッケージを行います。もちろん、包装も利点をもたらし、一つは包装であり、第二は標準です。
コンテナは、主に2つの技術によって閉じた環境を達成するために、1つは、名前空間と呼ばれる分離技術の外観は、アプリケーション内の各名前空間で表示するには、別のIPアドレス、ユーザー空間、プロセスIDなどです。もう1つは、マシン全体のCPUとメモリの多くを持っていることを意味cgroupと呼ばれる技術ですが、アプリケーションは、その一部のみを使用することができます。
いわゆるイメージとは、容器を溶接した瞬間の保存状態のことです。孫悟空が「セット!」と言った時のようなものです。その瞬間のコンテナの状態を「確定」し、その状態を一連のファイルに保存します。このImageをどこで実行しても、その瞬間に起こったことの全体像が得られます。
ネームスペース技術
異なるタイプのリソースを分離するために、Linuxカーネルは以下の異なるタイプのネームスペースを実装しています。
- User の場合、対応するマクロは CLONE_NEWUSER で、異なるネームスペースを異なるユーザとグループで構成できることを示しています。
- マウントの場合、対応するマクロはCLONE_NEWNSで、異なるネームスペースのファイルシステムのマウント・ポイントが分離されていることを示します。
- マクロ CLONE_NEWPID に対応する PID は、異なるネームスペースが完全に独立した pid を持つことを意味します。
- Network の場合、対応するマクロは CLONE_NEWNET で、異なるネームスペースが別々のネットワーク・スタックを持つことを示します。
III.CGグループの技術
コンテナは、主に2つの技術によって閉じた環境を実現します。1つは「一見孤立しているように見える」技術のNamespaceで、もう1つは技術のCGroupを孤立させるために使用されます。
前のセクションでは "一見孤立している "テクノロジーNamespaceについて説明しましたが、このセクションでは "孤立するために使用される "テクノロジーCGroupについて説明します。
CGroupの正式名称はControl Groupで、その名の通り「コントロール」するためのものです。コントロールするものとは?もちろんリソースの使用です。どんなリソースをコントロールできるの?
まず、cgroups は以下のサブシステムを定義します。
- 主にプロセスの CPU 使用量を制限する CPU サブシステム。
- cpuacct サブシステムは、cgroups 内のプロセスの cpu 使用量レポートを可能にします。
- cpuset サブシステムは、cgroups 内のプロセスに別々の cpu ノードやメモリノードを割り当てることができます。
- プロセスのメモリ使用量を制限するメモリサブシステム。
- プロセスのブロックデバイスioを制限できるblkioサブシステム。
- デバイス・サブシステムは、プロセスが特定のデバイスにアクセスする能力を制御することができます。
- net_clsサブシステムは、cgroups内のプロセスに対してネットワーク・パケットをマークし、tcモジュールを使ってパケットを制御することができます。
- cgroups 内のプロセスをサスペンドまたはレジュームできるフリーザーサブシステム。
IV.データセンターのオペレーティングシステム
アセンブリ言語を使い始めたころは、プログラムで使用するハードウェア・リソースを指定する必要がありました。例えば、どのレジスタを使用するか、メモリのどこに置くか、どのシリアル・ポートに書き込むか、またはどのシリアル・ポートから読み込むかなどです。これらのリソースの使い方はプログラマーの頭の中で非常に明確である必要があり、そうでなければ間違った場所にジャンプした場合、プログラムは実行されません。
プログラマをハードウェアの直接操作から解放し、プログラミングの効率を向上させるために、オペレーティング・システム層を用いてハードウェア資源の一元管理を実現します。あるプログラムが、CPUのどの部分、メモリのどの部分、ハードディスクのどの部分を使うかは、オペレーティング・システム自身が割り当て、管理するAPIを呼び出すことで実現できます。
実際、オペレーティング・システムが行う最も包括的なことはスケジューリングです。そのため、プロセス管理サブシステム、メモリ管理サブシステム、ファイルサブシステム、デバイスサブシステム、ネットワークサブシステムといったモジュールがカーネルの状態で生成されます。
これらのモジュールは、システムコールとしても知られる統一APIを通じて、トップにサービスを提供します。これらのAPIに基づいて、ユーザーランドには、ユーザー管理、ソフトウェアのインストール、ソフトウェアの操作、定期的なプロセス、ファイル管理、ネットワーク管理、ストレージ管理など、Linuxオペレーティングシステムの使用を支援するツールが多数用意されています。
しかし今のところ、管理できるのは数台のマシンだけです。データセンターで何千台ものマシンに直面したとき、それはまだ非常に「痛い」です。もしデータセンターの運用と保守がまだ前任者の物理的なマシンの運用と保守のようであれば、毎日、どのマシンにどのプログラムを置き、どれだけのメモリを搭載し、どれだけのハードディスクドライブを搭載し、各マシンにどれだけのメモリとハードディスクドライブの合計があり、どれだけのメモリとハードディスクドライブが残っているかを気にしていれば、頭は大きくなるでしょう。
データセンターでは、運用担当者を物理マシンや仮想マシンの割り当て作業から解放し、物理リソースの統合管理を可能にするスケジューラが求められており、それがKubernetesです。
運用スタッフを解放するKubernetesの具体的な機能とは?なぜデータセンターのOSになれるのか?
データセンターのオペレーティングシステムとしてのKubernetesは、現在もデータセンター内の4つの主要なハードウェアリソース(CPU、メモリ、ストレージ、ネットワーク)を管理しています。
CPUとメモリリソースの管理は、Dockerテクノロジーによって行うことができます。名前空間とcgroupによってCPUとメモリリソースを大規模なリソースプールから分離し、Image技術によってデータセンター内のコンピューティングリソースのフリードリフトを実現します。
前述したように、オペレーティング・システムがなかった当時、アセンブラ・プログラマーは、プログラムが実行されるCPUとメモリの物理アドレスを指定する必要がありました。同様に、データセンターの管理者は、プログラムが実行されているサーバーと、それが使用しているCPUとメモリを指定する必要があります。現在、KubernetesにはSchedulerというスケジューラーがあり、4コア8GのJavaプログラムを10個実行したいと伝えるだけで、サーバー上でこれらのプログラムを実行するのに十分な空きリソースを自動的に選択してくれます。
オペレーティングシステム上のプロセスには、主な処理を行うメインスレッドと、副次的な処理を行う他のスレッドがあります。Kubernetesは複数のDockerをPodという概念に組み立て、多くの場合1つのDockerを主、複数のDockerを従とします。Podの中には、多くの場合、プライマリとして1つのDockerがあり、セカンダリとして複数のDockerがあります。
オペレーティング・システム上のプロセスがCPUに入ったり出たりし、使用するメモリも入ったり出たりします。データセンター内では、これらの実行中のプログラムをマシン間で移行できますか?あるサーバーが故障した場合、別のサーバーを選んで実行できるのでしょうか?とにかく、私は10個の4コア8GのJavaプログラムを実行することに関心があり、それらがどこで実行されているかは気にしませんが、Kubernetesにはコントローラという概念があり、Podの状態とそれらが消費するリソースを制御します。
例えば、より効率的に実行するためにCPUを切り替えることなく特定のCPU上で再度実行したい場合や、2つのスレッドがロックなしでCPUごとの変数を使用できるように1つのCPU上にある必要があり、相互作用や共同作業が容易になる場合などです。Kubernetes Schedulerにはアフィニティ機能もあり、2つのPodを常に1つの物理マシン上で実行するように選択して、ローカル通信がうまくいくようにすることもできますし、2つのPodを同じ物理マシン上では決して実行しないように選択して、片方がハングアップしてもう片方に影響を与えないようにすることもできます。または、2つのPodが同じ物理マシン上で実行されることがないようにして、片方がハングアップしてももう片方に影響を与えないようにすることもできます。
DockerはCPUメモリリソースを抽象化してサーバ間でマイグレーションできるけど、データはどうすればいいの?データを各サーバーに置くと、実は海に散らばったようなもので、使うときに見つからないので、統一されたストレージが必要です。OS上で複数のプロセスが永続的なデータを保存し、ファイルシステムを通じて共有しなければならないように、データセンターにもそのようなインフラが必要なのです。
ユニファイド・ストレージには3つの形態があります。
オブジェクトストレージ。その名の通り、ファイルを完全なオブジェクトとして保存する方法です。各ファイルのペアは、オブジェクトを一意に識別するキーを持ち、ファイルの内容が値となります。オブジェクトは、フォルダのようなもので、ストレージスペースと呼ばれる場所に別々のカテゴリで保存することができます。
どのファイルオブジェクトでも、HTTP RESTful API を介してリモートからオブジェクトを取得することができます。シンプルなキー・バリュー・モデルのため、大量のデータを保存する必要がある場合、一意のキーに基づいて水平方向に拡張することが容易であるため、オブジェクト・ストレージは多くの場合、非常に大量のデータを保持することができます。ドキュメントやビデオなどをデータセンターに保存するには最適な方法ですが、もちろん、ファイルのように操作できないのが欠点で、値を全体として扱わなければなりません。分散ファイルシステム。ネットワーク経由でリモートファイルシステムにアクセスすることを除けば、ローカルファイルシステムを使うのとほとんど区別がつかないからです。複数のコンテナから統一ファイルシステムを見ることができ、あるコンテナがファイルシステムに書き込んだものを別のコンテナも見ることができるため、共有が可能になります。欠点は、分散ファイルシステムのパフォーマンスとスケールが矛盾していることで、大規模なパフォーマンスを確保するのは難しく、スケールはあまり大きくならないので、オブジェクトストレージのように大量のデータを維持できるわけではありません。
分散ブロックストレージ。これは、ディスクが仮想マシンではなくコンテナにマウントされることを除けば、クラウドハードドライブ、すなわちストレージの仮想化です。ブロックストレージは、分散ファイルシステムの層を持っていない、一度コンテナにマウントされ、ローカルファイルシステムを持つことができますので、欠点は、一般的に、異なるコンテナは、ブロックストレージが共有されていないマウントされていることですが、利点は、同じサイズの場合には、相対的な分散ファイルシステムのパフォーマンスが優れていることです。コンテナがあるサーバーから別のサーバーに移行する際に、保存されたデータをどのように保持するかという問題を解決するには、ブロックストレージが良い選択です。複数のコンテナ間でデータを共有するという問題を解決する必要はありません。
この3つのうち、オブジェクトストレージはHTTPを使ってアクセスするため、もちろんどのコンテナからもアクセスでき、Kubernetesが管理する必要はありません。一方、分散ファイルシステムと分散ブロックストレージは、Kubernetesが管理できるように、Kubernetesとのインターフェースが必要です。Kubernetesが提供するContainer Storage Interfaceは、デバイスドライバとは異なり、さまざまなストレージシステムがKubernetesとのインターフェイスとして実装できる標準インターフェイスです。オペレーティングシステムは統一インターフェースを定義するだけでよく、さまざまなストレージデバイスドライバがこれらのインターフェースを実装してオペレーティングシステムで使用できます。
ストレージの問題が解決されたら、次はネットワークです。異なるサーバー上のDockerはまだ互いに通信する必要があるからです。異なるサーバー上のDockerは依然として互いに通信する必要があるため、Kubernetesには独自のネットワークモデルがあり、このように定義されています。
- IP-per-Pod、各Podは個別のIPアドレスを持ち、Pod内のすべてのコンテナはネットワーク名前空間を共有します。
- クラスタ内のすべてのPodは直接接続されたフラットネットワーク上にあり、IP経由で直接アクセスできます。
- すべてのコンテナは、NATなしで互いに直接アクセスできます。
- すべてのノードとすべてのコンテナは、NATなしで相互に直接アクセスできます。
- コンテナ自体には、他のコンテナと同じIPが表示されます。
これが本当に意味するのは、そこにある各Dockerが別のDockerにアクセスすることで、それがフラットなネットワーク上にあるように感じられるということです。例えば、Kubernetesは独自のCalico、Flannel、そしてもちろんOpenvswitchのような仮想スイッチ、brctlのような伝統的なブリッジ、またはハードウェアスイッチを提供しています。
どのような方法でネットワークモデルを実装しても、この統一インターフェースにインターフェースしさえすれば、kubernetesはコンテナのネットワークを管理することができます。
この時点で、データセンターのオペレーティングシステムとしてKubernetesを使用することで、カーネルの問題は解決されます。
次に来るのは、ユーザー状態のためのツールの問題です。データセンターをサーバーのように運用することは可能でしょうか?
オペレーティングシステムを使用するには、いくつかのソフトウェアをインストールする必要があるため、yumのようなパッケージ管理システムが必要です。yumは、ソフトウェアのユーザーとソフトウェアのコンパイラを分離します。KubernetesにはHelmというパッケージ管理ソフトウェアがあり、これを使えばデータベースやキャッシュ、メッセージキューなど、データセンターでよく使われるソフトウェアを簡単にインストール、アップグレード、スケールすることができます。
オペレーティング・システムでは、プロセスの実行が最も一般的な要件です。プロセスの最初のタイプは対話型のコマンドラインで、タスクを実行して終了次第結果を返します。Kubernetesでは、Jobと呼ばれる同等の概念があり、短い単発タスク、つまり1回だけ実行されるタスクのバッチ処理を担当し、バッチタスクの1つ以上のPodが正常に終了することを保証します。
2つ目のタイプのプロセスは、nohupロングランプロセスです。Kubernetesでこれに相当する概念はDeploymentで、バックグラウンドでポッドを作成するReplicaSetを作成するために使用されます。つまり、Doploymentでは、あるプロセスをポッドのN個のコピーとして実行し、長時間実行し、少なくなったら自動的にコピーを追加するようにします。コピー数が少なくなると
3番目のプロセスはシステムサービスです。Kubernetesで対応する概念はDaemonSetで、コンテナのコピーが各ノードで実行されていることを保証し、クラスタのロギング、監視、その他のシステム管理アプリケーションの一部をデプロイするために一般的に使用されます。
プロセスの4番目のタイプは、周期的なタスクの設定によく使用される周期的プロセス(crontab)です。Kubernetesで対応する概念はCronJob timed taskで、これはLinuxシステムのcrontabに似ており、指定されたタスクを指定された時間に実行します。
Podが削除されると、Volumeはクリーンアップされます。データが失われるかどうかは、Volumeの特定のタイプに依存します。Volumeの概念は、ext4ファイルシステムを使用する際にベースとなるハードドライブが重要でないのと同様に、特定のストレージデバイスを抽象化したものです。
ネットワークについては、Kubernetesは独自のDNSとServiceの概念を持っています。 Kubernetes Serviceは、ServiceによってアクセスできるPodの論理的なグループ化です。各Serviceには名前があり、KubernetesはServiceの名前を仮想クラスタIPとして知られるドメイン名として解決し、ロードバランシングを通してバックエンドのPodに転送します。
Linuxオペレーティングシステムのiptablesに対応するKubernetesには、ポリシーベースのネットワーク制御を提供してアプリケーションを分離し、攻撃対象領域を縮小するNetwork Policyというコンセプトがあります。従来のセグメント化されたネットワークをエミュレートするためにラベルセレクタを使用し、それらの間のトラフィックと外部からのトラフィックを制御するためのポリシーを使用します。
ほら、すごいでしょう?Kubernetesを使えば、データセンターをLinuxサーバーのように管理できます。