Docker ネットワーク設計の理念

Docker 1.7 での実験的なネットワーキングから Docker 1.9 での最初のリリースまで、コミュニティからの歓迎は素晴らしいものでした。 まず第一に、すべての議論、評価、PR、および提出された問題に感謝します。 ネットワーク機能はリリースごとに進化しているため、設計の背後にある基本原則を説明するために時間をかけたいと考えました。

ユーザーファースト Docker_networking

Dockerの哲学は、優れたユーザーエクスペリエンスとインフラストラクチャ全体でのシームレスなアプリケーション移植性を備えたツールを構築することです。 新機能は常に継続的に洗練され、反復されるため、最終製品は可能な限り最高のユーザーエクスペリエンスを提供します。 ネットワーキングは同じ哲学に従い、ユーザーに適した抽象化を見つけるために何度か繰り返しました。

ネットワークに関しては、次の 2 種類のユーザーがいます。

  • Dockerプラットフォーム上に分散アプリケーションスタックを作成してデプロイするアプリケーション開発者
  • インフラストラクチャを構成および管理するネットワーク IT チーム

私たちは、これらの種類のユーザーに適切な種類のツールを提供して、目標を簡単に達成できるようにし、 @arungupta@allingeek@Yoanis_GilなどのDockerコミュニティの経験の一部について読むことができるようにしたいと考えていました。

Dockerの主な焦点は、ユーザーがアプリケーションチームであろうとIT運用であろうと、ユーザーにあります。 これは、ユーザーエクスペリエンスとシームレスなアプリケーションの移植性という同じアーキテクチャ目標をサポートするエコシステムパートナーをサポートすることも意味します。 そのことを念頭に置いて、すべてのAPIとUIはエンドユーザーに公開する必要があり、それ以外のものはコアバリューを損なうと考えています。 Dockerをサポートまたは含めると主張するエコシステム内の人は、ユーザーエクスペリエンスと移植性の維持を順守する必要があります。

ユーザー: アプリケーション開発者

アプリケーション開発者は、アプリケーションが相互に通信することを望んでいますが、ほとんどの開発者は、それがどのように正確に達成されるかの詳細を理解したり、関与したりすることを望んでいません。 実際、彼らはアプリケーションがバインドされているIPアドレスを知りたくありません。 アプリケーション開発者の関心事は、通常、アプリケーションがバインドされているレイヤー 4 サービス層で終わります。

Docker ネットワーク設計の基本原則の 1 つは、アプリケーション開発者がネットワーク配管の詳細を気にする必要がないようにすることです。 私たちは、ネットワーク接続とサービス検出がどのように実現されるかという悲惨な詳細を単純なAPIとUIの背後に隠すことで、アプリケーション開発者が分散アプリケーションスタックをより自由に開発できるようにすると考えています。 アプリケーション開発者がモノリシック アプリケーションを一連のマイクロサービスに変換することを妨げる接続/検出可能性の頭痛の種と移植性の懸念を排除する必要があります。 開発者は、いくつかの簡単な "ネットワーク作成" コマンドと "ネットワーク接続" コマンドを使用して、マイクロサービスを 1 つの分散アプリケーションにバインドできるようにしたいと考えています。

もう 1 つの指針となる原則は、Docker コンテナーの移植性エクスペリエンスをネットワークに拡張することです。 イメージを使用して作成された Docker コンテナーは、同じイメージが使用されている限り、実行場所に関係なく同じように動作します。 同様に、アプリケーション開発者がアプリケーションスタックを一連の分散アプリケーションとして定義する場合、実行されるインフラストラクチャに関係なく、同じように機能する必要があります。 これは、アプリケーション開発者に公開する抽象化、さらに重要なことに、アプリケーション開発者に公開しない抽象化に大きく依存します。

このようにして、Dockerの「ネットワーク」抽象化(CNM)が生まれました。 これは、アプリケーション開発者がアプリケーション サービスの接続性と検出可能性のニーズについて考え、推論するための適切なリファレンスを提供し、これを正確に実現する方法のすべての複雑さに気を取られることはありません。 ある意味では、"ネットワーク" 抽象化は、ユーザーがトポロジを物理的に構築する "方法" を指示するのではなく、アプリケーションが必要とする "どのような" 種類のトポロジを伝えることができるため、宣言型です。

CNM モデル
たとえば、従来の 3 層 Web アプリケーション スタックでは、Web サーバーとアプリケーション サーバーが 1 つのネットワーク内にあり、同じアプリ サーバーがデータベース サーバーを持つ別のネットワークに接続されます。 アプリ開発者は、物理ネットワークやファイアウォールなどでどのように実装されているかを気にする必要はありません。インフラストラクチャをアプリケーションから切り離すと、分散アプリケーションの移植性が大幅に向上します。 これは、開発者がアプリケーショントポロジを正確に定義する方法についてより自由になることも意味します。

ユーザー: ネットワーク IT

アプリケーション開発者はインフラストラクチャの詳細から解放され、ポータブルなアプリケーション展開エクスペリエンスを望んでいますが、ネットワーク IT チームは、インフラストラクチャに展開されたすべてのアプリケーションがスムーズに実行され、アプリケーションの SLA とビジネス ルールに準拠していることを確認したいと考えています。 これは、アプリケーションの機能と意図を損なうことなく、ネットワーク構成やプロバイダーを変更できることを意味します。 アジャイルとは、開発者にとってはスピードを意味し、ネットワークITにとっては異なる種類のスピードを意味し、変化するニーズに迅速に対応し、他の何かを壊すことなく調整を行うことができます。

方程式の「方法」の部分は、「ドライバー」の抽象化によって実現されます。 抽象ネットワーク トポロジの定義が与えられた場合、そのトポロジを具体的にどのように実現するかは、使用されるドライバーによって異なります。 すべてのドライバーが簡単に準拠できる Docker Networking プラグイン API を定義することで、あるドライバーを別のドライバーに置き換えることで、まったく同じアプリケーション駆動型ネットワーク トポロジを任意のインフラストラクチャに簡単にデプロイできます。

プラグイン API は、次の場合にドライバーにフックを提供します。

  • ネットワークが作成されます
  • コンテナーがネットワークに接続されている
  • コンテナにはIPアドレスが必要です

これらは、アプリケーション ネットワーク トポロジのネットワーク接続を実現するために最も重要なフックです。 Docker は、使用するドライバーに関係なく、アプリケーションに同じネットワーク接続保証を提供します。 同時に、ネットワークITチームは、インフラストラクチャ内のアプリケーショントポロジを容易にする任意のドライバを自由に選択できます。

「プラグイン」と呼ばれる特別な種類のドライバーがいくつかあります。 すべてのプラグインはドライバーです。 ただし、プラグインはDockerエンジンバイナリには組み込まれていません。 これらは独立した外部プログラムであり(ほとんどの場合、それ自体がDockerコンテナです)、組み込みドライバーと同じドライバーAPIを使用します。 したがって、本質的には、組み込みドライバーを外部プラグインに交換して、任意のネットワークトポロジを実現できます。 これは、「バッテリーは含まれているが交換可能」というDockerの哲学を反映しています。 プラグインは、ネットワークITの移植性と選択をサポートする上で重要です。

Dockerネットワーキングの強化について最初に考え始めたとき、プラグインは第一級の市民であるべきであることは明らかでした。 どのインフラストラクチャでも、アプリケーションの接続性と検出可能性のニーズは幅広く多様です。 すべてのユーザーとアプリケーションを満足させるこの問題に対する単一の解決策はありません。 したがって、プラグインは最初からDockerネットワーキング設計の重要な部分でした。 新しいDockerネットワーキングの最初のバージョンをリリースしたときに、「バッテリーを交換する」機能をユーザーが利用できると判断しました。 結局、それはまさに私たちがDocker 1.9でDockerネットワーキングをリリースした方法です。

プラグイン API の設計

アプリケーションネットワークトポロジとネットワークの抽象化はアプリケーション開発者に重点を置いていますが、ドライバー/プラグインの構成はIT管理者に重点を置いています。 ネットワークITは、アプリケーションを導入するインフラストラクチャと関連するサービス・レベルに重点を置いています。 ただし、アプリケーションのネットワーク接続の意図を満たすことができることを確認する必要があります。

彼らは次のことを確実にしたいと考えています。

  • ネットワーク パスを組み込むための適切なソリューションが使用されます
  • ネットワーク リソースを管理するための適切なソリューションが使用されている
  • アプリケーション・サービスを検出するための適切なソリューションが使用されている
  • 彼らは上記のすべてについて別々の独立した選択をすることができます

ネットワーク構成のさまざまな要素に対してさまざまなソリューションを選択するネットワークITに柔軟性を提供することで、最高の運用エクスペリエンスが得られます。

1 つの包括的なプラグイン API/拡張ポイントを提供する代わりに、プラグイン API を論理構成グループに対応する個別の拡張ポイントに分割しました。

このデザインは、構成可能性を促進するために機能ごとに1つの「インターフェイス」を定義することを提唱するgolangインターフェイス哲学からインスピレーションを得ています。 これは、ネットワークITがさまざまなニーズに合わせてさまざまなソリューションを構成するための強力な機能です。

プラグインAPI設計の別の側面は、コンテナが異なるプラグインによってサポートされる複数のネットワークに参加するときに発生する可能性のある競合を解決するために、Docker Networkingがブローカーであり続けるようにすることです。 たとえば、2 つの異なるドライバーが、同じルート プレフィックスでネクスト ホップ IP が異なる静的ルートを plumb する場合があります。 これが発生した場合、これらのドライバーがユーザーエクスペリエンスを犠牲にすることなく、誰のルートが勝つかを個別に選択することはできません。 したがって、プラグインAPIの一部として、特定のドライバーがこれらの競合を単独で解決する方法がないため、libnetworkはコンテナのネットワーク名前空間へのドライバーのアクセスを提供しません。 これは、組み込みのドライバーとプラグインに当てはまります。 CNIのような他のプラグインフレームワークは、そのドライバへの名前空間アクセスを提供するため、コンテナ名前空間内で互いに踏みつけるこれらのドライバに対処する必要がある場合があります。 それが起こると、ユーザーエクスペリエンスと移植性が低下します。

このプラグイン設計のもう1つの理由は、さまざまなレイヤー(IPアドレス管理、サービス検出、負荷分散など)できめ細かいネットワークプラグ可能性を提供し、ユーザーが包括的で意見のあるネットワークプラグインに依存するのではなく、機能を満たすために最適なドライバーを選択できるようにすることです。 たとえば、ネットワーク事業者が特定の IPAM ソリューション ( Infoblox など) を別のネットワーク プラグイン (シスコの contiv など) と組み合わせて使用するシナリオなどです。 libnetwork ™ はコンテナのネットワーク名前空間を管理するため、必要なDocker UXを実装し、異なるプラグインのそのような組み合わせを保証できます。したがって、ネットワーク設計を制御するために必要な保証をネットワークオペレーターに提供します。

ドッカー API とユーザーインタラクション

Docker ネットワークでは、2 人の異なるユーザーの懸念事項を分離できるため、Docker UI で 2 つの異なるコマンドを設計するのは自然なことでした。 UI と API は、ネットワーク IT がアプリケーション開発者との調整をできるだけ少なくしてインフラストラクチャを構成できるように設計されています。 これにより、アプリケーション開発者とネットワークITチーム間のロックステップワークフローを回避できます。

たとえば、アプリケーション開発者がネットワーク IT に特定の名前のネットワークを作成するように要求した場合、ネットワーク IT は独立して、特定のインフラストラクチャに適した構成オプションを適用してネットワークの作成を開始できます。 同時に、アプリケーション開発者は、参照された名前を持つネットワークが、アプリケーションに必要なネットワーク トポロジを実現するために利用できることを前提として、アプリケーションの作成に取り組むことができます。

これを念頭に置いて、UIとAPIのブランチはおおよそ次のようになります。

  • ネットワーク IT は、ネットワークに使用するネットワーク ドライバーと IPAM ドライバーの組み合わせを作成、管理し、正確に制御できます。 また、サブネット、ゲートウェイ、IP範囲などのさまざまなネットワーク固有の構成を指定したり、ドライバー固有の構成がある場合はそれを渡すこともできます。
  • 構成は、作成されたネットワークに任意のコンテナを接続することです。 これは、主に接続性と発見可能性の1つであるため、アプリケーション開発者に焦点を当てています。

アプリケーション開発者がアプリケーションを構成する一般的な方法は、アプリケーションの一部であるすべてのアプリケーションサービスと、ネットワークITによって事前にプロビジョニングされる可能性のあるネットワークを参照するアプリケーション定義トポロジで相互に接続する方法を指定できる「Docker Compose」ファイルを使用することです。

実際、開発者は、アプリケーショントポロジを本質的に定義するDocker Composeファイルを使用してアプリケーションを構築します。 まったく同じ作成ファイルを使用して任意のインフラストラクチャにアプリケーションをデプロイできるようになり、ネットワーク IT チームはインフラストラクチャの要件に基づいてネットワーク (作成ファイルで参照される) を事前にプロビジョニングできます。 その重要な側面は、アプリケーション開発者が別の環境にデプロイされるたびにComposeファイルを再訪する必要がないことです。

この懸念の分離により、開発者とネットワークITが、必要に応じて異なるプラグインを使用して、ネットワークのプロビジョニングとアプリケーションの展開において独立して作業できるワークフローが可能になります。

例として、次の Compose v2 アプリケーションを考えてみましょう。

$ cat docker-compose.yml
    バージョン: "2"
    サービス:
    投票アプリ:
    画像:ドッカー/例-投票-アプリ-投票-アプリ
    ポート:
    - "80"
    ネットワーク:
    - 投票ネット
    結果アプリ:
    画像:ドッカー/例-投票-アプリ-結果-アプリ
    ポート:
    - "80"
    ネットワーク:
    - 投票ネット
    勤労者:
    画像:ドッカー/例-投票-アプリ-ワーカー
    ネットワーク:
    - 投票ネット
    レディス:
    画像:レディス
    ネットワーク:
    - 投票ネット
    .db:
    画像:投稿:9.4
    ボリューム:
    - "db-data:/var/lib/postgresql/data"
    ネットワーク:
    - 投票ネット
    ボリューム:
    データベースデータ:
    ネットワーク:
    投票ネット:

既定では、compose v2 は既定のドライバーを使用して、このアプリケーションの Docker ネットワークを作成します。 docker-engine に対して実行した場合、既定のドライバーはブリッジ ドライバーです。 したがって、アプリケーションを起動すると、ネットワークが「デフォルトドライバー」を使用して作成されていることがわかります。

$ docker-compose up -d
    デフォルトドライバでネットワーク「voteapp_votenet」を作成する
    データベースの開始
    レディスの開始
    voteapp_worker_1の開始
    voteapp_voting-app_1の開始
    voteapp_result-app_1の開始

アプリケーションは単一のホストで問題なく動作し、アプリケーション開発者はネットワーク固有の構成を処理することなく作業を完了できます。

詳細を調べると、

$ ドッカーネットワーク検査 - voteapp_votenet
    [
    {
    "名前": "- voteapp_votenet",
    "Id": "7be1879036b217c072c824157e82403081ec60edfc4f34599674444ba01f0c57",
    "スコープ": "ローカル",
    "ドライバ": "ブリッジ"、
    "IPAM": {
    "ドライバ": "デフォルト",
    "オプション": ヌル、
    "設定": [
    {
    "サブネット": "172.19.0.0/16",
    "ゲートウェイ": "172.19.0.1/16"
    }
    ]
    },
    ...
    ...
    ...
    ]

アプリケーションを停止させましょう。

$ ドッカー-作曲ダウン

ここで、アプリケーションが運用チームに引き渡され、ステージングでデプロイされると仮定します。 ネットワーク IT は、 docker network コマンドを使用して事前にネットワークを事前にプロビジョニングすることにより、ネットワークを管理します。 例えば:

$ docker network create -d overlay --subnet=70.28.0.0/16 --gateway=70.28.5.254 voteapp_votenet
    6d215748f300a0eda3878e76fe99e717c8ef85a87de0779e379c92af5d615b88

または、ネットワークITは、別の作成ファイルを追加することで、拡張機能(この作成機能の詳細を読む)を使用して、上記のdocker-composeアプリケーションのネットワーク構成を制御できます。
"docker-compose.override.yml" アプリケーションで何も変更する必要はありません。

$ cat docker-compose.override.yml
    バージョン : "2"
    ネットワーク:
    投票ネット:
    ドライバー:オーバーレイ
    IPAM:
    設定:
    - サブネット: 70.28.0.0/16
    ゲートウェイ: 70.28.5.254

この例では、ステージングで使用されるネットワーク ドライバーは、マルチホスト ネットワーク接続を提供する "オーバーレイ" であり、ネットワーク IT チームはこのネットワークに優先する IPAM 設定を使用できます。

$ docker-compose up -d
    ドライバ「オーバーレイ」を使用したネットワーク「-voteapp_votenet」の作成
    voteapp_worker_1の開始
    レディスの開始
    データベースの開始
    voteapp_voting-app_1の開始
    voteapp_result-app_1の開始

同じアプリケーションを実行すると、今度は、マルチホストネットワーク接続を提供する「overlay」という名前の別のドライバーを使用して作成されたネットワークが作成されます。 これで、「docker network inspect」コマンドを使用してネットワークを深く掘り下げると、ネットワークの構成に使用されている構成済みのIPAMもわかり、このネットワーク内のすべてのコンテナーがこのサブネットにIPアドレスを持つようになります。

$ ドッカーネットワーク検査 - voteapp_votenet
    [
    {
    "名前": "- voteapp_votenet",
    "Id": "b510c0affb2289548a07af7cc7e3f778987fc43812ac0603c5d01b7acf6c12be",
    "スコープ": "グローバル",
    "ドライバ": "オーバーレイ"、
    "IPAM": {
    "ドライバ": "デフォルト",
    "オプション": ヌル、
    "設定": [
    {
    "
    サブネット": "70.28.0.0/16",
        "ゲートウェイ": "70.28.5.254"
    }
    ]
    },
    ...
    ...
    ...
    ]

この Compose アプリケーションが Docker Swarm で実行されている場合、コンテナーはホスト間でスケジュールされますが、オーバーレイ ドライバーはコンテナー間のシームレスな接続を提供します。 これらはすべて、このブログ投稿で説明されているDockerネットワーキングの設計原則によって可能になります。

アプリケーションはまだ王様です

前に言及しなかった場合、すべての操作に焦点を当てた構成ノブで、アプリケーションは依然として王様のままです。 したがって、最初に述べたように、できるだけ多くのネットワークアーティファクトを非表示にしたかったのですが、最後に非表示にする必要があるのはIPアドレス自体です。 IP アドレスは、基になるインフラストラクチャに関する何かを公開し、これによりアプリケーションの移植性エクスペリエンスが低下します。 アプリケーションがコンパイル時に知っている名前を使用して相互に検出できる場合は、移植性の話が完了します。 これはまさに、組み込みDNSサーバーを使用して暗黙的なコンテナ検出を提供することで達成したものです。 コンテナの「リンク」機能と「エイリアシング」機能により、コンテナはコンパイル時に知っていた名前のピアコンテナを検出できます。

Docker ネットワーキングを自分で試してみたい場合は、次のリソースを確認してください。


ドッカーについてもっと知る

フィードバック

「Dockerネットワーキング設計哲学」に関する0つの考え