本記事では、
Dockerのネットワークについて解説します。
Dockerのネットワークは、
やや高度な話題なので、
正直基礎と言えるか微妙ではありましたが、
実務に入ると高確率で使うことが多いので、
取り上げます。
Dockerの基礎については、
ある程度知っていることを前提に解説しますので、
Dockerの基礎が不安な方は、
こちらの記事などもご参考ください。
Dockerネットワークの種類
Dockerネットワークはコンテナ間の通信を管理し、
異なる環境や要件に応じて柔軟な設定を可能にします。
以下では、主要なネットワークタイプの概要とその利用例、メリットとデメリットを説明します。
docker network ls
現在利用可能なDockerネットワークの一覧を表示するには、docker network lsコマンドを使用します。
これにより、bridge、host、noneなどのデフォルトネットワークと、カスタムで作成されたネットワークが表示されます
docker network ls
bridgeネットワーク
Dockerのデフォルトネットワークタイプです。
異なるコンテナが同じbridgeネットワークに属している場合、
互いに通信できます。
メリットは、シンプルで理解しやすいことで、
後で詳しく触れますが、
コンテナ名での通信など、
異なるコンテナ間の分離を保ちつつ通信を許可してくれます。
デメリットは、パフォーマンスの観点から、
大規模なアプリケーションには適していない場合があるという感じでしょうか。
NATの処理が重くなってしまったり、多数のコンテナが同じbridgeネットワークを共有する場合は、
ネットワーク帯域幅が飽和する可能性があるので、
大規模アプリケーションとかだとこの点がネックになることはありえるかもしれないですね。
ちなみに、ネットワーク帯域幅は、一定時間内にネットワークを介して送受信できるデータの量を指します。
通常はMbps(メガビット毎秒)やGbps(ギガビット毎秒)で測定されるやつですね。
よく光回線の速度とかで計測している、あれです。
brigeネットワークが、
パフォーマンスに影響が出ていないかを
ピンポイントで特定するのは、
高度なトピックだと思うので、
詳細には触れませんが、こういうときに使えるものとして、
docker stats
コマンドなどがあります。
https://docs.docker.jp/engine/reference/commandline/stats.html
また、MacOS自体のネットワークを監視したいときは、
nettopなども使えるかもしれません。
nettop
ただ、上記のようなパフォーマンス上の懸念がないとはいえ、
デフォルトのネットワークであり、
おそらく一番使用頻度は多いかなと思います。
なんかdocker重いなっていうときに、
上記のbridgeネットワークの特徴を思い出して、
チューニングするのが良いかなと思います。
hostネットワーク
Dockerのhostネットワークモードでは、コンテナがホストマシンのネットワークスタックを直接使用します。
これにより、コンテナはホストと同じIPアドレスとポートを共有し、ネットワークのオーバーヘッドを回避することができます。
docker run -d --name nginx --network host nginx
このコマンドにより、nginxコンテナはホストマシンと同じネットワークスタックを使用します。
これにより、ホストマシン上で利用可能なポートはコンテナから直接アクセス可能になります。
bridgeネットワークでは、コンテナはホストから分離されたネットワークスタックを持ち、
NATを通じて外部ネットワークと通信します。一方、hostネットワークでは、この分離がありません。
またNATによる処理がないため、
hostネットワークはbridgeネットワークよりも高いパフォーマンスを提供できることが多いかと思います。
ただ、デメリットとしては、コンテナとホストのネットワーク分離がないため、
悪意のあるコンテナがホストシステムに影響を与えるリスクが高まることや、
ホストのポートを直接使用するため、ポートの競合が発生しがちということでしょうか。
hostネットワークだと、docker psとかを使ったときに、
PORTSが空になっていることがほとんどだと思います。
まあ正直、そんなに頻繁に使うたぐいのものではない気もします。
ホストマシンのポートをそのまま使えるっていうのは、
dockerの仮想化のメリットが薄まってしまう気もするなと
個人的には感じるので。
noneネットワーク
このネットワークは、コンテナにネットワーキング機能を提供しません。
こうなると、それはネットワークなのかというツッコミはさておき、
ネットワークから分離されるのでセキュリティが向上するのがメリットです。
デメリットとしては非常にわかりやすいですが、
他のコンテナやサービスと通信できなくなります。
Dockerのnoneネットワークは、コンテナにネットワークインターフェースを割り当てず、
ネットワークの分離を最大限に行う設定なので、
コンテナが外部ネットワークや他のコンテナと通信することを完全に防ぎます。
なので、noneネットワークの指定と、
ネットワーク設定を何もしない場合とは異なります。
ネットワーク設定を何も指定しない場合、Dockerはデフォルトでbridgeネットワークを使用します。
これは、Dockerが提供する標準的なネットワークで、コンテナ間の通信を可能にし、
ホストマシンとの間にも仮想ネットワークブリッジを作成します。
したがって、ネットワーク設定を何もしない場合、コンテナは外部ネットワークや他のコンテナと通信できる状態になります。
対照的に、noneネットワークを明示的に指定すると、コンテナはネットワークから完全に切り離されます。
この設定は、コンテナが外部と通信する必要がない、
またはネットワーク分離を最大限にしたい特定のセキュリティが求められる環境で有用です。
この状態では、コンテナは自身のプロセスやファイルシステムにアクセスできますが、
外部のネットワークリソースにはアクセスできません。
要するに、普段何もネットワーク設定していなくとも、
bridgeが設定されていたが、noneをすると、
明示的にネットワークに接続できなくするという感じですかね。
コンテナのIPアドレスを確認する方法
DockerコンテナのIPアドレスを確認するには、複数の方法があります。
以下では、各方法をサンプルコードと共に解説します。
コンテナ内でipやifconfigコマンドを使う
コンテナ内部から直接、ipやifconfigコマンドを使用してIPアドレスを確認することができます。
# コンテナに入る
docker exec -it [コンテナ名] bash
# コンテナ内でIPアドレスを確認
ip addr
# または
ifconfig
ただ、この方法は、
コンテナの種類によっては、
そもそもipコマンドやifconfigコマンドがなかったりすることもあるので、
いつでも使えるかというと微妙ではあります。
nginxコンテナとかでは使えませんでした。
docker container inspect
docker container inspectでコンテナの詳細情報を調べることができます。
これのNetworkSettingsを確認すると、IPアドレスがわかります。
docker container inspect [コンテナ名]
このコマンドは、JSON形式で多くの情報を出力します。
その中からネットワーク関連の情報を見つけることができます。
formatオプションで特定の項目だけ取得する
docker container inspectの出力から特定の情報だけを取得するためには、--formatオプションを使用します。
これにより、必要な情報だけを簡単に取得できます。
docker container inspect --format '{{ .NetworkSettings.IPAddress }}' [コンテナ名]
このコマンドは、指定されたコンテナのIPアドレスのみを出力します。
おそらく、このやり方が一番合理的なのかなとは個人的には思います。
docker network inspect bridge
docker network inspectコマンドを使用して、
特定のネットワーク(この場合はbridge)に接続されているコンテナの情報を確認できます。
docker network inspect bridge
このコマンドは、bridgeネットワークに接続されているすべてのコンテナの詳細情報を提供します。
IPマスカレードについて
IPアドレスに関連して、
IPマスカレードという技術がありますが、
そもそもIPマスカレードってなんだっけって私は最初なりました。
IPマスカレードは、DockerホストのIPアドレスを使用してコンテナからのアウトバウンド接続を可能にする
NAT(ネットワークアドレス変換)の一形態です。
これにより、コンテナはDockerホストのIPアドレスを使用して外部と通信できます。
うん?どういうことって感じだと思うので、
IPマスカレードの例えを出してみます。
アパートの部屋をコンテナとし、そこに一つの大きな郵便受けがあるとして、
それをDockerホストとします。
アパートの部屋(コンテナ)から手紙(データパケット)を送るとき、
部屋から出た手紙はまずアパートの郵便受けに集められ、そこから外部の世界(インターネット)に送られます。
この手紙はアパートの住所(DockerホストのIPアドレス)でマークされます。
つまり、外部の世界では、この手紙がどの部屋から来たのかはわかりません。
これに対して、手紙がアパートに戻ってくるときは、郵便受け(Dockerホスト)に届いた手紙は、
どの部屋(コンテナ)宛てであるかに基づいて適切な部屋に配達されます。
このように、DockerのIPマスカレードは、
コンテナから外部への通信がDockerホストを介して行われることを意味します。
コンテナ自身のIPアドレスは外部には露見せず、外部から見るとすべての通信がDockerホストから来ているように見えることです。
この設定は特にbridgeネットワークで重要であり、
コンテナがDockerホストを介して外部ネットワークと通信する際に用いられます。
このプロセスは自動的に行われるため、ユーザーが手動で設定する必要はありません。
これらの方法を使用して、DockerコンテナのIPアドレスとネットワーク設定を効率的に確認し、管理することができます。
これにより、ネットワークのトラブルシューティングや構成の最適化が容易になります。
NATって何だっけ?
そもそも、NATって何だっけ?
ネットワークまじよくわからん。
っていう感じの人もいるかもしれないので、
一応補足します。(というか私が最初そうだった)
NAT(ネットワークアドレス変換)は、インターネットネットワーキングの重要な概念で、
一つのネットワークアドレスを別のアドレスに変換する技術です。
この技術により、複数のデバイスが一つのIPアドレスを共有してインターネットにアクセスすることが可能になります。
NATの基本的な役割は、プライベートIPアドレス(ローカルネットワーク内で使用されるアドレス)を
公共IPアドレス(インターネット上で一意のアドレス)に変換することです。
これにより、ネットワーク内の多くのデバイスが、一つの公共IPアドレスを共有してインターネットに接続できます。
例えば、自宅やオフィスのルーターがNATを使用しています。
複数のコンピューター、スマートフォン、タブレットなどがローカルネットワークに接続されている場合、
これらのデバイスはプライベートIPアドレスを持ちます。
インターネットにアクセスする際、ルーターがこれらのプライベートIPアドレスをルーター自身の公共IPアドレスに変換します。
インターネットから見ると、これらのリクエストはすべて同じ公共IPアドレスから来ているように見えます。
IPアドレスでのコンテナ間の通信
Dockerコンテナ間でIPアドレスを用いた通信は、ネットワークの基本的な操作です。
ここでは、異なるNginxコンテナを2つ立てて、それらの間で通信する方法をサンプルコードを交えて解説します。
ipコマンドでIPアドレスを確認
まず、2つのNginxコンテナを立てます。
# Nginxコンテナ1の作成
docker run -d --name nginx1 nginx
# Nginxコンテナ2の作成
docker run -d --name nginx2 nginx
次に、これらのコンテナのIPアドレスを確認します。
docker container inspectコマンドを使用して、各コンテナのIPアドレスを取得します。
# Nginxコンテナ1のIPアドレスを取得
docker container inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' nginx1
# Nginxコンテナ2のIPアドレスを取得
docker container inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' nginx2
pingコマンドの基本的な使い方
IPアドレスでのコンテナ間での疎通に際し、
pingコマンドを使うのですが、意外とpingって、
使い方忘れがちな気がするので、おさらいも兼ねて、
軽く概要を説明しておきます。
pingコマンドは、ネットワーク上の他のコンピューターやデバイスとの接続を確認するために使用されるコマンドです。
このコマンドは、インターネットプロトコル(IP)アドレスまたはホスト名を指定して、そのデバイスへの接続をテストします。
よく使うオプションとしては、-c(回数)や-t(応答を待つ最大時間)などがあげられます
ping -c 4 google.com # 4回送信する
ping -t 10 google.com # 10秒待つ
自分のルーターにpingを送信する
pingの活用例として、
自分のルーターにpingを送って、
ネットワークの遅延(レイテンシ)を測定してみましょう。
まず、macで自分のルーターのIPアドレスを調べるには、
netstat -nr | grep default
を実行して表示されたIPアドレスです。
早速おくります。
ping ルーターのipアドレス
だいたい、1ms-30msぐらいなら、
良い応答時間かと思います。
pingで疎通する
取得したIPアドレスを使用して、コンテナ間の疎通を確認します。
docker execコマンドを使用して、一方のコンテナから他方のコンテナへのpingテストを実行します。
# Nginx1からNginx2へのpingテスト
docker exec nginx1 ping -c 4 [Nginx2のIPアドレス]
# Nginx2からNginx1へのpingテスト
docker exec nginx2 ping -c 4 [Nginx1のIPアドレス]
curlでコンテンツが取得できるか
最後に、curlコマンドを使用して、
一方のコンテナが他方のコンテナのWebサービス(Nginx)にアクセスできるかを確認します。
# Nginx1からNginx2のWebページを取得
docker exec nginx1 curl [Nginx2のIPアドレス]
# Nginx2からNginx1のWebページを取得
docker exec nginx2 curl [Nginx1のIPアドレス]
コンテナ名でのコンテナ間通信
dockerでは、コンテナ間での通信を容易にするためにコンテナ名を利用できます。
ここでは、nginxコンテナを例に、コンテナ名を使用した通信方法とそれに関連するオプションについて説明します。
linkオプション
linkオプションは、一方のコンテナを別のコンテナにリンクするために使用されます。
これにより、リンクされたコンテナは、他のコンテナの名前で通信できるようになります。
# Nginxコンテナ1を作成
docker run -d --name nginx1 nginx
# Nginxコンテナ2を作成し、nginx1にリンクする
docker run -d --name nginx2 --link nginx1 nginx
/etc /hostsが書き換わる
linkオプションを使用すると、リンクされたコンテナの/etc/hostsファイルが自動的に更新され、
リンク先のコンテナ名とIPアドレスが追加されます。これにより、コンテナ名での通信が可能になります。
docker network create
Dockerでは、カスタムネットワークを作成してコンテナ間の通信を管理することができます。
カスタムネットワーク内では、コンテナは互いの名前で直接通信できます。
# カスタムネットワークを作成
docker network create my-network
# Nginxコンテナをカスタムネットワークに接続
docker run -d --name nginx1 --network my-network nginx
docker run -d --name nginx2 --network my-network nginx
--network(または-net)オプションを使用して、コンテナが接続するネットワークを指定できます。
カスタムネットワークを使用すると、コンテナ名での通信が簡単になります。
connectとdisconnectコマンド
既存のコンテナをネットワークに接続したり、
ネットワークから切断したりするためにdocker network connectおよびdocker network disconnectコマンドを使用できます。
# コンテナをカスタムネットワークに接続
docker network connect my-network nginx1
# コンテナをネットワークから切断
docker network disconnect my-network nginx1
Dockerネットワークでのコンテナ名での通信の仕組み
Dockerネットワークでは、コンテナ間の通信にコンテナ名を使用することができることがわかりました。
この機能の背後には、Dockerの内部DNSサーバーと特定の設定ファイルが関与しています。
DNSサーバーが使われている
Dockerでは、デフォルトで内部DNSサーバーが組み込まれており、これがコンテナ間の名前解決を担当します。
Dockerネットワーク内では、各コンテナはそのコンテナ名でアクセス可能です。
この内部DNSサーバーによって、コンテナ名が対応するIPアドレスに変換され、コンテナ間での通信が実現されます。
Dockerのデフォルトの内部DNSサーバーを確認する方法は、
実際にコンテナ内でネットワーク関連の設定を調べることになります。
具体的には、コンテナ内の/etc/resolv.confファイルを確認することで、
どのDNSサーバーが使用されているかを見ることができます。
/ etc/resolve.confとは
/etc/resolv.confは、UNIX系オペレーティングシステムにおいてDNSサーバーの設定を管理するファイルです。
Dockerコンテナ内でも、このファイルがDNS解決のための設定情報を持っています。
Dockerはコンテナを起動する際に、このファイルに適切なDNS設定を自動的に注入します。
そもそもDNSってなんだっっけ?
DNS(ドメインネームシステム)は、
インターネット上のリソースに対応するIPアドレスを人間が読みやすいドメイン名(例:www.example.com)
に変換するためのシステムです。
DNSサーバーは、これらのドメイン名をIPアドレスに変換する役割を担っています。
このプロセスにより、ユーザーはウェブブラウザなどで直接IPアドレスを入力する代わりに、
覚えやすいドメイン名を使用してインターネット上のリソースにアクセスできます。