Docker ネットワークの基礎 |仮想ネットワークデバイスペア(Veth)の原理

Docker ネットワークの基礎 |仮想ネットワークデバイスペア(Veth)の原理

[[402397]]

この記事はWeChatの公開アカウント「Linux Kernel Things」から転載したもので、著者はsongsong001です。この記事を転載する場合は、Linux Kernel Matters パブリック アカウントにご連絡ください。

コンテナ化が普及しつつある今日、Docker はコンテナ界の寵児と言えるでしょう。かさばる仮想マシンと比較すると、Docker はツバメのように軽量です。もちろん、この記事では仮想マシンと Docker の長所と短所を紹介するのではなく、Docker ネットワークの重要なコンポーネントの 1 つを紹介します。

仮想ネットワークデバイスペア: veth

veth を紹介する前に、まずネットワーク名前空間を紹介しましょう。

ネットワーク名前空間

ネットワーク名前空間は、Linux カーネルによって、異なるコンテナ間のネットワーク リソースを分離するために使用されます (各 Docker コンテナには独立したネットワーク名前空間があります)。ネットワーク名前空間は主に次のリソースを分離します。

  • iptables ルールテーブル
  • ルーティングルールテーブル
  • ネットワークデバイスリスト

次の図に示すように、システム内に 3 つのネットワーク名前空間がある場合:

異なるネットワーク名前空間は互いに分離されているため、直接通信することはできません。たとえば、IP アドレスが 172.17.42.1 のデバイスはネットワーク名前空間 A に設定されていますが、次の図に示すように、ネットワーク名前空間 B ではアクセスできません。

2 台のコンピューターの場合と同様に、ネットワーク ケーブルで接続されていないと、コンピューター同士は通信できません。そのため、Linux カーネルは、異なるネットワーク名前空間間の通信を解決するために、仮想ネットワーク デバイス ペア (veth) 機能を提供します。

仮想ネットワークデバイスペア (veth)

仮想ネットワーク デバイス ペアは、異なるネットワーク名前空間間の通信を解決するために使用され、ネットワーク ケーブルで接続された 2 つのネットワーク カードとして表示できます。次の図に示すように、ネットワーク カードの 1 つがネットワーク名前空間 A に配置され、もう 1 つのネットワーク カードがネットワーク名前空間 B に配置されている限り、2 つの異なるネットワーク名前空間は通信できます。

上図に示すように、veth0 と veth1 は仮想ネットワーク デバイス ペアを形成します。仮想ネットワーク デバイス ペアはパイプのようなものです。データが一方の端に送信されれば、もう一方の端からデータを受信できます。

Docker は仮想ネットワーク デバイスを使用して、異なるコンテナー間の通信を実装します。原則は次のとおりです。

上の図からわかるように、各コンテナは仮想ネットワークデバイスペアを介して直接接続されていません。代わりに、ホスト上に docker0 という名前のブリッジが作成され、各コンテナは仮想ネットワーク デバイス ペアを介してブリッジに接続されます。ブリッジは、実際のスイッチと同様に、複数のネットワーク デバイスを接続する機能を備えています。

もちろん、この記事のテーマは veth の実装であり、ブリッジの実態ではないので、ブリッジの紹介はここで終わります。ご興味がございましたら、「Linux Bridge の動作原理と実装」の記事を参照してください。

仮想ネットワークデバイスペアの実装

Linux カーネルでは、ネットワーク デバイスは net_device オブジェクトによって表されます。 veth は双方向通信を提供するため、これを実装するには 2 つの net_device オブジェクトが必要です。 net_device オブジェクトは非常に大きいため、この記事に関連するフィールドのみをここにリストします。

  1. 構造体net_device
  2. {
  3. 文字 名前[IFNAMSIZ];
  4. ...
  5. 定数構造体net_device_ops *netdev_ops;
  6. ...
  7. }

これら 2 つのフィールドの機能について次に説明します。

  • name: eth0 などのデバイス名を保存するために使用されます。
  • netdev_ops: デバイスを初期化するためのインターフェース、デバイスをシャットダウンするためのインターフェース、データを送信するためのインターフェースなど、デバイス関連の操作インターフェースのリスト。

veth は 2 つの net_device オブジェクトで構成されているため、これら 2 つの net_device オブジェクトは互いへのポインターを持つ必要があります。しかし、コードを調べても、お互いを指すポインターは見つかりませんでした。カーネルは veth をどのように実装するのでしょうか?

Linux カーネルは、net_device オブジェクトを使用してネットワーク デバイスを表しますが、異なるメーカーのネットワーク デバイスは互いに異なる場合があります。 Linux カーネルをさまざまなネットワーク デバイスに適応させるために、さまざまなネットワーク デバイスにプライベート データ用のストレージ スペースが提供されます。

つまり、ネットワーク デバイスには、net_device 部分に加えてプライベート データ部分があります。ネットワーク デバイスごとにプライベート データ部分が異なり、ネットワーク デバイスのプライベート データ部分は通常、次の図に示すように、net_device オブジェクトの最後に保存されます。

上図は、PCMCIA ネットワーク カードと RTL-8139 ネットワーク カードに対応するプライベート データ部分の保存場所を示しています。 PCMCIA ネットワーク カードのプライベート データ部分は pcnet_dev_t 構造体に対応し、RTL-8139 ネットワーク カードのプライベート データ部分は rtl8139_private 構造体に対応します。

話題に戻ると、仮想ネットワーク デバイス ペアのプライベート データ部分は、次のように定義される veth_priv 構造体によって表されます。

  1. 構造体veth_priv{
  2. 構造体net_device *ピア;
  3. 構造体 veth_net_stats *統計;
  4. ...
  5. };

veth_priv 構造体の各フィールドの機能について次に説明します。

  • peer: 仮想ネットワーク デバイス ペアはネットワーク デバイスのペアで構成されるため、このフィールドはペア内のもう一方のデバイスを指すために使用されます。
  • 統計: 統計情報を保存するために使用されます。

veth_priv 構造から、次の図に示すように、仮想ネットワーク デバイス ペアに属する 2 つのデバイス オブジェクトが peer フィールドによって関連付けられていることがわかります。

1. 仮想ネットワークデバイスペアを作成する

ip コマンドを使用して仮想ネットワーク デバイスのペアを作成すると、作成を完了するために veth_newlink 関数が呼び出されます。実装は次のとおりです。

  1. 静的 整数 
  2. veth_newlink(構造体net_device *dev、構造体nlattr *tb[]、構造体nlattr *data[])
  3. {
  4. 整数エラー;
  5. 構造体net_device *ピア;
  6. 構造体 veth_priv *priv;
  7. char ifname[IFNAMSIZ];
  8. ...
  9.  
  10. // 仮想ネットワークデバイスペアは2つのネットワークデバイスで構成されているため、
  11. // dev は仮想ネットワークデバイスペアのネットワークデバイスの 1 つです。
  12. // したがって、rtnl_create_link() を呼び出して別のネットワーク デバイスを作成し、それをピア変数に保存する必要があります。
  13. ピア = rtnl_create_link(dev_net(dev), ifname, &veth_link_ops, tbp);
  14. ...
  15.  
  16. priv = netdev_priv(dev); // devのプライベートデータ部分を取得する
  17. priv->peer = ピア; // ピアフィールドをピアにポイントする
  18.  
  19. priv = netdev_priv(ピア); // ピアのプライベートデータ部分を取得する
  20. priv->peer = dev; // ピアフィールドをdevに向ける
  21.  
  22. 0を返します
  23. }

上記のコードは合理化された後もメインロジックを保持するため、veth_newlink は主に次のタスクを実行します。

  • 仮想ネットワーク デバイス ペアは 2 つのネットワーク デバイスで構成されており、dev は仮想ネットワーク デバイス ペアのネットワーク デバイスの 1 つであるため、rtnl_create_link 関数を呼び出して別のネットワーク デバイスを作成し、それを peer 変数に保存する必要があります。
  • dev デバイス オブジェクトの peer フィールドをピア デバイス オブジェクトにポイントします。
  • ピア デバイス オブジェクトの peer フィールドを dev デバイス オブジェクトにポイントします。

このようにして、仮想ネットワークデバイスのペアの作成が完了します。

2. 仮想ネットワークデバイスペアを初期化する

もちろん、仮想ネットワークデバイスペアを作成する場合は、初期化も必要です。初期化プロセスは、次のように実装される veth_setup 関数によって完了します。

  1. 静的定数構造体net_device_ops veth_netdev_ops = {
  2. ...
  3. .ndo_start_xmit = veth_xmit、
  4. ...
  5. };
  6.  
  7. 静的void veth_setup(構造体 net_device *dev)
  8. {
  9. ...
  10. dev->netdev_ops = &veth_netdev_ops;
  11. ...
  12. }

仮想ネットワークデバイスペアを初期化する際に最も重要なことは、その操作機能セットを設定することです。 net_device_ops 構造体は、ネットワーク デバイスの操作機能セット構造体です。デバイスにデータが送信されると、デバイス操作機能セットの ndo_start_xmit メソッドがトリガーされます。

veth_setup 関数はこのメソッドを veth_xmit に設定します。つまり、仮想ネットワーク デバイス ペアの一方の端にデータを送信するときに、veth_xmit 関数が呼び出されてデータが送信されます。

3. 仮想ネットワークデバイスペアにデータを送信する

仮想ネットワーク デバイス ペアの一方の端にデータを送信する場合、送信プロセスを完了するために veth_xmit 関数が呼び出されます。これは次のように実装されます。

  1. 静的netdev_tx_t veth_xmit(構造体 sk_buff *skb、構造体 net_device *dev)
  2. {
  3. 構造体net_device *rcv = NULL ;
  4. 構造体 veth_priv *priv、*rcv_priv;
  5. ...
  6.  
  7. // データを送信するデバイスのピアデバイスを取得します
  8. priv = netdev_priv(dev);
  9. rcv = priv->peer;
  10. ...
  11.  
  12. skb->tstamp.tv64 = 0;
  13. skb->pkt_type = PACKET_HOST;
  14. // データパケットの受信デバイスをピアデバイスに設定する
  15. skb->プロトコル = eth_type_trans(skb, rcv);
  16. ...
  17.  
  18. // データパケットをカーネルプロトコルスタックに送信する
  19. netif_rx(skb);
  20.  
  21. NETDEV_TX_OK を返します
  22. }

まず、veth_xmit 関数の各パラメータの意味を紹介します。

  • skb: 送信するパケット オブジェクト。
  • dev: データを送信するデバイス。

veth_xmit 関数の実装は比較的単純で、主に次のタスクを実行します。

  • データを送信するデバイスのピア デバイスを取得します。
  • データ パケットの受信デバイスをピア デバイスに設定します。
  • データ パケットをカーネル プロトコル スタックに送信します。

データ送信のプロセスを示すために次の図を使用します。

上図に示すように、仮想ネットワーク デバイス ペアの一方の端からデータ パケットが送信されると、もう一方の端で受信され、カーネル プロトコル スタックに送信されて処理されます。

要約する

仮想ネットワーク デバイス ペアの出現により、コンテナー間の通信の問題が解決されます。この記事では、主に仮想ネットワーク デバイス ペアの実装原理を分析しますが、一部の詳細については詳細に分析されていません。ご質問がある場合は、WeChat で私を追加して話し合うことができます。

<<:  アリ・ジア・ヤンチン:ビッグデータとAI機能を通じて企業にアップグレードの力を提供する

>>:  5種類のサーバー仮想化を理解する

推薦する

李佳琦のライブ放送を見るとき、何を見ますか?

毎晩8時15分、李佳琦の生放送室を視聴している人は約500万人。休日にはさらに増える。4時間の生放送...

無印良品の年間売上高100億円の秘密:完璧な商品作り

はじめに:ロゴ、広告、スポークスマン、複雑な色やスタイルなしで、無印良品の業績は急上昇しました。無印...

2012年の中国の検索エンジン市場の分析

2012 年は中国の検索エンジン業界にとって順風満帆というわけではなかった。競争が激化するなか、壮大...

ウェブサイトの重みを高めるために、ウェブサイトの後の段階で外部リンクを構築するにはどうすればよいでしょうか?

ウェブサイトの外部リンクはウェブサイトのランキングに影響を与える鍵です。これはあまり説明しなくても誰...

クラウドネイティブ アプリケーションを構築するための 6 つのセキュリティのベスト プラクティス

翻訳者 |劉望洋レビュー |チョンロウクラウドネイティブ アーキテクチャにより、ソフトウェアの開発、...

2021 年のクラウド コンピューティングのトップ 10 トレンド

クラウド コンピューティング テクノロジーは、コロナウイルスのパンデミックの間、世界経済、サプライ ...

アメリカのソーシャルエンターテイメントウェブサイトGetGlueが1200万ドルを調達

新浪科技報、北京時間1月12日朝のニュースによると、米国のソーシャルエンターテイメントウェブサイトG...

6月22日の百度Kステーション事件の分析

私は百度のことを語る時、いつも愛憎入り混じった感情を抱いています。この複雑な感情の理由は、百度のアッ...

5 月の世界 Web サーバー市場シェア: Microsoft のみが市場シェアを 33.41% に増加

IDC Review Network (idcps.com) は 5 月 13 日に次のように報告し...

クラウドネイティブのモダナイゼーションが増加中

昨年、Enterprise Strategy Group は、分散クラウド コンピューティングに関連...

再分析:NetEase と Snowball がテストした画面を一掃するミニゲームの背後にある戦術!

この記事では、2 つの類似した運用アクティビティ (Snowball Investment Scho...

Pacificrack: 米国向けに最適化されたライン VPS、年間 7.5 ドルから、注文時に 10 個の B セグメント IP を無料で選択できます。

QNデータセンターは先月、CEO/CFOをはじめとする人事の交代を完了しました。直下のPacific...

小規模融資会社は、AIテレマーケティングロボットを活用して、いかにして市場を迅速に獲得できるのでしょうか?

2018年最もホットなプロジェクト:テレマーケティングロボットがあなたの参加を待っています競争が激化...

Dockerが残したギャップ:イメージ配布の現状と考察

より効率的なクラウド サービスを実現するために、コンテナ テクノロジーは登場以来、業界から幅広い支持...

Linodeはどうですか?インドのチェンナイデータセンタークラウドサーバーレビュー

Linode は Akamai に統合された後、現在ではインドのチェンナイとムンバイに 2 つのデー...