コンテナ、VM、Dockerの初心者向けの紹介

プログラマーや技術者であれば、少なくともDockerについて聞いたことがあるでしょう。Dockerは、「コンテナー」内でアプリケーションをパック、出荷、実行するための便利なツールです開発者やシステム管理者から同様に、最近注目を集めているので、そうしないのは難しいでしょう。グーグル、ヴイエムウェア、アマゾンのような大物でさえ、それをサポートするサービスを構築しています。

Dockerの即時のユースケースを念頭に置いているかどうかに関係なく、「コンテナー」とは何か、および仮想マシン(VM)との比較に関する基本的な概念のいくつかを理解することが重要だと思います。インターネットにはDockerの優れた使用ガイドがたくさんありますが、特にコンテナーの構成について、初心者向けの概念ガイドは多くありませんでした。だから、うまくいけば、この投稿はその問題を解決するでしょう:)

まず、VMとコンテナが何であるかを理解することから始めましょう。

「コンテナ」と「VM」とは何ですか?

コンテナーとVMの目標は似ています。つまり、アプリケーションとその依存関係を、どこでも実行できる自己完結型のユニットに分離することです。

さらに、コンテナとVMは物理ハードウェアの必要性を排除し、エネルギー消費と費用対効果の両方の観点から、コンピューティングリソースのより効率的な使用を可能にします。

コンテナとVMの主な違いは、アーキテクチャのアプローチにあります。よく見てみましょう。

仮想マシン

VMは基本的に、実際のコンピューターのようにプログラムを実行する実際のコンピューターのエミュレーションです。VMは、「ハイパーバイザー」を使用して物理マシン上で実行されます。次に、ハイパーバイザーは、ホストマシンまたは「ベアメタル」のいずれかで実行されます。

専門用語を開梱しましょう:

ハイパーバイザーは、仮想マシンが上で実行することを、ソフトウェア、ファームウェア、またはハードウェアの一部です。ハイパーバイザー自体は、「ホストマシン」と呼ばれる物理コンピューター上で実行されます。ホストマシンは、RAMやCPUなどのリソースをVMに提供します。これらのリソースはVM間で分割され、必要に応じて分散できます。したがって、1つのVMがよりリソースの多いアプリケーションを実行している場合、同じホストマシンで実行されている他のVMよりも多くのリソースをそのVMに割り当てることができます。

ホストマシン上で(ここでもハイパーバイザーを使用して)実行されているVMは、「ゲストマシン」とも呼ばれます。このゲストマシンには、アプリケーションと、そのアプリケーションを実行するために必要なもの(システムバイナリやライブラリなど)の両方が含まれています。また、仮想化ネットワークアダプター、ストレージ、CPUなど、独自の仮想化ハードウェアスタック全体を搭載しています。つまり、独自の本格的なゲストオペレーティングシステムも備えています。内部からは、ゲストマシンは、専用のリソースを備えた独自のユニットとして動作します。外部からは、それがVMであることがわかります—ホストマシンによって提供されるリソースを共有します。

上記のように、ゲストマシンは、ホスト型ハイパーバイザーまたはベアメタルハイパーバイザーのいずれかで実行できます。それらの間にはいくつかの重要な違いがあります。

まず、ホストされた仮想化ハイパーバイザーがホストマシンのオペレーティングシステムで実行されます。たとえば、OSXを実行しているコンピューターでは、そのOSの上にVM(VirtualBoxやVMware Workstation 8など)をインストールできます。VMはハードウェアに直接アクセスできないため、ホストオペレーティングシステム(この場合はMacのOSX)を経由する必要があります。

ホスト型ハイパーバイザーの利点は、基盤となるハードウェアの重要性が低くなることです。ホストのオペレーティングシステムは、ハイパーバイザー自体ではなくハードウェアドライバーを担当するため、より「ハードウェアの互換性」があると見なされます。一方、ハードウェアとハ​​イパーバイザーの間にあるこの追加のレイヤーは、より多くのリソースオーバーヘッドを作成し、VMのパフォーマンスを低下させます。

ベアメタルハイパーバイザー環境は、ホストマシンのハードウェアにインストールして実行することにより、パフォーマンスの問題に対処します。基盤となるハードウェアと直接インターフェースするため、実行するためにホストオペレーティングシステムは必要ありません。この場合、オペレーティングシステムとしてホストマシンのサーバーに最初にインストールされるのはハイパーバイザーです。ホスト型ハイパーバイザーとは異なり、ベアメタルハイパーバイザーには独自のデバイスドライバーがあり、I / O、処理、またはOS固有のタスクのために各コンポーネントと直接対話します。これにより、パフォーマンス、スケーラビリティ、および安定性が向上します。ここでのトレードオフは、ハイパーバイザーに組み込むことができるデバイスドライバーの数が非常に多いため、ハードウェアの互換性が制限されることです。

ハイパーバイザーについてこのすべての話をした後、VMとホストマシンの間にこの追加の「ハイパーバイザー」レイヤーが必要なのはなぜか疑問に思われるかもしれません。

VMには独自の仮想オペレーティングシステムがあるため、ハイパーバイザーは、このゲストオペレーティングシステムを管理および実行するためのプラットフォームをVMに提供する上で重要な役割を果たします。これにより、ホストコンピューターは、その上でゲストとして実行されている仮想マシン間でリソースを共有できます。

図からわかるように、VMは、新しいVMごとに、仮想ハードウェア、カーネル(つまり、OS)、およびユーザースペースをパッケージ化します。

コンテナ

ハードウェア仮想化を提供するVMとは異なり、コンテナは「ユーザースペース」を抽象化することでオペレーティングシステムレベルの仮想化を提供します。コンテナという用語を解凍すると、私が何を意味するのかがわかります。

すべての意図と目的において、コンテナーはVMのように見えます。たとえば、処理用のプライベートスペースがあり、rootとしてコマンドを実行でき、プライベートネットワークインターフェイスとIPアドレスがあり、カスタムルートとiptableルールを許可し、ファイルシステムをマウントできます。

コンテナとVMの大きな違いの1つは、コンテナがホストシステムのカーネルを他のコンテナと*共有*することです。

この図は、コンテナーがユーザースペースのみをパッケージ化し、VMのようにカーネルや仮想ハードウェアをパッケージ化しないことを示しています。各コンテナは独自の分離されたユーザースペースを取得して、複数のコンテナを単一のホストマシンで実行できるようにします。すべてのオペレーティングシステムレベルのアーキテクチャがコンテナ間で共有されていることがわかります。ゼロから作成される唯一のパーツは、ビンとライブラリです。これがコンテナを非常に軽量にする理由です。

Dockerはどこからやってくるのですか?

Dockerは、Linuxコンテナーに基づくオープンソースプロジェクトです。名前空間やコントロールグループなどのLinuxカーネル機能を使用して、オペレーティングシステム上にコンテナを作成します。

コンテナは決して新しいものではありません。Googleは何年もの間独自のコンテナテクノロジーを使用してきました。その他のLinuxコンテナテクノロジーには、Solarisゾーン、BSD jail、LXCなどがあります。これらは長年にわたって使用されてきました。

では、なぜDockerが突然勢いを増しているのでしょうか。

1.使いやすさ: Dockerにより、開発者、システム管理者、アーキテクトなど、誰でも簡単にコンテナーを利用して、ポータブルアプリケーションをすばやく構築およびテストできます。これにより、誰でもラップトップにアプリケーションをパッケージ化でき、パブリッククラウド、プライベートクラウド、さらにはベアメタルでも変更せずに実行できます。マントラは、「一度構築すれば、どこでも実行できる」です。

2.速度: Dockerコンテナは非常に軽量で高速です。コンテナはカーネル上で実行される単なるサンドボックス環境であるため、使用するリソースが少なくなります。毎回完全な仮想オペレーティングシステムを起動する必要があるために時間がかかる可能性があるVMと比較して、Dockerコンテナを数秒で作成して実行できます。

3. Docker Hub: Dockerユーザーは、Docker Hubのますます豊富なエコシステムからも恩恵を受けます。これは、「Dockerイメージのアプリストア」と考えることができます。 Docker Hubには、コミュニティによって作成された何万ものパブリックイメージがあり、すぐに使用できます。ニーズに合った画像を検索するのは信じられないほど簡単で、プルダウンしてほとんど変更を加えずに使用できます。

4.モジュール性とスケーラビリティ: Dockerを使用すると、アプリケーションの機能を個々のコンテナーに簡単に分割できます。たとえば、Node.jsアプリが別のコンテナにあるときに、Postgresデータベースを1つのコンテナで実行し、Redisサーバーを別のコンテナで実行しているとします。Dockerを使用すると、これらのコンテナーをリンクしてアプリケーションを作成することが容易になり、将来的にコンポーネントを個別にスケーリングまたは更新することが容易になります。

最後になりましたが、Dockerクジラを愛していないのは誰ですか?;)

Dockerの基本的な概念

全体像を把握できたので、Dockerの基本的な部分を1つずつ見ていきましょう。

Dockerエンジン

Dockerエンジンは、Dockerが実行されるレイヤーです。これは、コンテナー、イメージ、ビルドなどを管理する軽量のランタイムおよびツールです。Linuxシステムでネイティブに実行され、次のもので構成されます。

1.ホストコンピューターで実行されるDockerデーモン。

2.次に、Dockerデーモンと通信してコマンドを実行するDockerクライアント。

3. DockerDaemonとリモートで対話するためのRESTAPI。

Dockerクライアント

Dockerクライアントは、Dockerのエンドユーザーとして通信するものです。DockerのUIと考えてください。たとえば、あなたがするとき…

Dockerクライアントと通信し、Dockerクライアントは指示をDockerデーモンに通信します。

Dockerデーモン

Dockerデーモンは、コンテナーの構築、実行、配布など、Dockerクライアントに送信されたコマンドを実際に実行するものです。Dockerデーモンはホストマシン上で実行されますが、ユーザーとしてデーモンと直接通信することはありません。Dockerクライアントはホストマシンでも実行できますが、必須ではありません。別のマシンで実行し、ホストマシンで実行されているDockerデーモンと通信できます。

Dockerfile

Dockerfileは、Dockerイメージを構築するための手順を記述する場所です。これらの手順は次のとおりです。

  • apt-get y install some-packageを実行します:ソフトウェアパッケージをインストールします
  • EXPOSE 8000:ポートを公開する
  • ENV ANT_HOME / usr / local / apache-antは、環境変数を渡します

などなど。あなたはDockerfileセットアップを持ってたら、使用することができるドッキングウィンドウのビルド、そこからイメージを構築するためのコマンドを。Dockerfileの例を次に示します。

Dockerイメージ

イメージは、Dockerfileに記述された一連の命令から作成する読み取り専用テンプレートです。イメージは、パッケージ化されたアプリケーションとその依存関係をどのように見せたいか、および起動時に実行するプロセスの両方を定義します。

Dockerイメージは、Dockerfileを使用して構築されます。Dockerfileの各命令は、画像に新しい「レイヤー」を追加します。レイヤーは、その下のレイヤーに追加または置換する画像ファイルシステムの一部を表します。レイヤーは、Dockerの軽量でありながら強力な構造の鍵です。Dockerは、Unionファイルシステムを使用してこれを実現します。

ユニオンファイルシステム

Dockerは、Union FileSystemsを使用してイメージを構築します。ユニオンファイルシステムは、スタック可能なファイルシステムと考えることができます。つまり、個別のファイルシステム(ブランチと呼ばれる)のファイルとディレクトリを透過的にオーバーレイして、単一のファイルシステムを形成できます。

オーバーレイされたブランチ内で同じパスを持つディレクトリの内容は、単一のマージされたディレクトリとして表示されるため、各レイヤーの個別のコピーを作成する必要がありません。代わりに、それらすべてに同じリソースへのポインターを与えることができます。特定のレイヤーを変更する必要がある場合は、コピーを作成してローカルコピーを変更し、元のレイヤーは変更しません。これが、ファイルシステムが実際に書き込みを許可せずに書き込み可能に*表示*できる方法です。(言い換えれば、「コピーオンライト」システムです。)

階層化システムには、2つの主な利点があります。

1.複製なし:レイヤーは、イメージを使用して新しいコンテナーを作成および実行するたびにファイルの完全なセットが複製されるのを防ぎ、Dockerコンテナーのインスタンス化を非常に高速かつ安価にします。

2.レイヤーの分離:変更を行う方がはるかに高速です。イメージを変更すると、Dockerは変更されたレイヤーにのみ更新を伝達します。

ボリューム

ボリュームはコンテナの「データ」部分であり、コンテナの作成時に初期化されます。ボリュームを使用すると、コンテナのデータを永続化して共有できます。データボリュームは、デフォルトのユニオンファイルシステムとは別のものであり、ホストファイルシステム上の通常のディレクトリおよびファイルとして存在します。そのため、コンテナを破棄、更新、または再構築しても、データボリュームは変更されません。ボリュームを更新する場合は、ボリュームに直接変更を加えます。(追加のボーナスとして、データボリュームを複数のコンテナー間で共有および再利用できるため、非常に便利です。)

Dockerコンテナ

上記で説明したように、Dockerコンテナーは、アプリケーションのソフトウェアを、アプリケーションの実行に必要なすべてのものを含む非表示のボックスにラップします。これには、オペレーティングシステム、アプリケーションコード、ランタイム、システムツール、システムライブラリなどが含まれます。DockerコンテナはDockerイメージから構築されます。イメージは読み取り専用であるため、Dockerはイメージの読み取り専用ファイルシステムの上に読み取り/書き込みファイルシステムを追加して、コンテナーを作成します。

さらに、コンテナーを作成すると、Dockerはコンテナーがローカルホストと通信できるようにネットワークインターフェイスを作成し、使用可能なIPアドレスをコンテナーにアタッチし、イメージの定義時にアプリケーションを実行するために指定したプロセスを実行します。

コンテナが正常に作成されると、変更を加えることなく、任意の環境でコンテナを実行できます。

「コンテナ」をダブルクリックする

ふぅ!それは多くの可動部分です。常に興味を持ったのは、コンテナーが実際にどのように実装されているかということでした。特に、コンテナーの周囲に抽象的なインフラストラクチャの境界がないためです。たくさん読んだ後、それはすべて理にかなっているので、これがあなたにそれを説明する私の試みです!:)

「コンテナ」という用語は、実際には、いくつかの異なる機能がどのように連携して「コンテナ」を視覚化するかを説明するための抽象的な概念にすぎません。それらを実際にすばやく実行してみましょう。

1)名前空間

名前空間は、基盤となるLinuxシステムの独自のビューをコンテナーに提供し、コンテナーが表示およびアクセスできるものを制限します。コンテナーを実行すると、Dockerは特定のコンテナーが使用する名前空間を作成します。

Dockerが使用するカーネルには、いくつかの異なるタイプの名前空間があります。次に例を示します。

a。NET:システムのネットワークスタックの独自のビュー(たとえば、独自のネットワークデバイス、IPアドレス、IPルーティングテーブル、/ proc / netディレクトリ、ポート番号など)をコンテナに提供します。

b。PID: PIDはプロセスIDの略です。あなたが今まで走ってきた場合は、PS AUXのプロセスがシステム上で実行されているかどうか確認するために、コマンドラインで、あなたは「PID」という名前の列を見てきましたよ。PID名前空間は、「すべてのプロセスの祖先」である独立したinit(PID 1)を含め、コンテナーが表示および対話できるプロセスの独自のスコープビューをコンテナーに提供します。

c。MNT:システム上の「マウント」の独自のビューをコンテナに提供します。したがって、異なるマウント名前空間のプロセスは、ファイルシステム階層の異なるビューを持ちます。

d。UTS: UTSはUNIX TimesharingSystemの略です。これにより、プロセスはシステム識別子(つまり、ホスト名、ドメイン名など)を識別できます。UTSを使用すると、コンテナは、他のコンテナやホストシステムから独立した独自のホスト名とNISドメイン名を持つことができます。

e。IPC: IPCはInterProcessCommunicationの略です。IPC名前空間は、各コンテナ内で実行されているプロセス間でIPCリソースを分離する役割を果たします。

f。ユーザー:この名前空間は、各コンテナー内のユーザーを分離するために使用されます。これは、ホストシステムと比較して、コンテナーがuid(ユーザーID)とgid(グループID)の範囲の異なるビューを持つことを可能にすることによって機能します。その結果、プロセスのuidとgidは、ユーザー名前空間の内部と外部で異なる可能性があります。これにより、プロセスは、コンテナー内のroot特権を犠牲にすることなく、コンテナーの外部に非特権ユーザーを持つことができます。

Dockerは、コンテナーを分離して作成を開始するために、これらの名前空間を一緒に使用します。次の機能はコントロールグループと呼ばれます。

2)コントロールグループ

コントロールグループ(cgroupとも呼ばれます)は、一連のプロセスのリソース使用量(CPU、メモリ、ディスクI / O、ネットワークなど)を分離し、優先順位を付け、説明するLinuxカーネル機能です。この意味で、cgroupは、Dockerコンテナーが必要なリソースのみを使用することを保証し、必要に応じて、コンテナーが使用できるリソースに制限を設定します。Cgroupはまた、単一のコンテナーがこれらのリソースの1つを使い果たして、システム全体をダウンさせないようにします。

最後に、ユニオンファイルシステムは、Dockerが使用するもう1つの機能です。

3)分離されたUnionファイルシステム:

上記のDockerイメージセクションで説明されています:)

Dockerコンテナに必要なのはこれだけです(もちろん、さまざまなコンポーネント間の相互作用を管理する方法など、実装の詳細に悪魔がいます)。

Dockerの未来:DockerとVMは共存します

Dockerは確かに大きな勢いを増していますが、VMにとって本当の脅威になるとは思いません。コンテナは今後も普及していきますが、VMの方が適しているユースケースは数多くあります。

たとえば、複数のサーバーで複数のアプリケーションを実行する必要がある場合は、VMを使用するのが理にかなっています。一方、単一のアプリケーションの多くの*コピー*を実行する必要がある場合、Dockerにはいくつかの魅力的な利点があります。

さらに、コンテナーを使用すると、アプリケーションをより機能的な個別のパーツに分割して関心の分離を作成できますが、管理するパーツの数が増え、扱いにくくなる可能性もあります。

Dockerコンテナーでは、セキュリティも懸念事項になっています。コンテナーは同じカーネルを共有しているため、コンテナー間の障壁は薄くなっています。フルVMはホストハイパーバイザーに対してのみハイパーコールを発行できますが、Dockerコンテナーはホストカーネルに対してsyscallを実行できるため、攻撃の表面積が大きくなります。セキュリティが特に重要な場合、開発者は抽象化されたハードウェアによって分離されたVMを選択する可能性が高く、相互の干渉がはるかに困難になります。

もちろん、セキュリティや管理などの問題は、コンテナが本番環境でより多くの露出を持ち、ユーザーからさらに精査されるにつれて進化することは確実です。今のところ、コンテナーとVMについての議論は、毎日それらを生きて呼吸しているDevOpsの人々にとって本当に最善です!

結論

Dockerについてさらに学び、いつかプロジェクトで使用するために必要な知識を身に付けたことを願っています。

いつものように、私が何か間違いをしたか、とにかく役立つことができるならば、コメントに私に一行ドロップしてください!:)