🌐

【初学者向け】Dockerネットワークの基礎

2024/07/06に公開

はじめに

今回は、Dockerのネットワークについて説明します。

私の動作環境

  • Docker Desktop 4.30.0 (149282)
  • Docker Engine 26.1.1
  • Docker Compose v2.27.0-desktop.2
  • MacOS Sonoma 14.5

Dockerコマンド一覧

Dockerのコマンド一覧は、以下のサイトに記載されています。このサイトは、Docker公式ドキュメントを有志の方々が日本語に翻訳してくれているものです。

https://docs.docker.jp/engine/reference/commandline/index.html

公式による最新のドキュメントを確認したい人は、以下のリンクから飛ぶことができます。

https://docs.docker.com/

Dockerネットワーク

私たちはDockerを扱う際に仮想的なネットワークを作ることで、Dockerホストとコンテナ、もしくはコンテナ間で通信することができます。

ここで、docker networkコマンドを用いることでDocker上のネットワークの各種設定をすることができます。

まず、Dockerが管理するネットワークの確認をしてみます。Dockerが管理するネットワークは、docker network lsコマンドで確認できます。

docker network ls


Dockerが管理するネットワーク

実行画面から分かるように、「bridge」「host」「none」という三つのネットワークが表示されました。デフォルトでDockerは三つのネットワークを自動的に作成するようになっています

それぞれどんな役割を持つのか確認してみます。

bridgeネットワーク

bridgeネットワークはDockerのデフォルトネットワークモードで、ネットワークオプションを指定しない場合に使用されます。このモードでは、各コンテナのネットワークは独立しており、-pオプションを使用して通信するコンテナを指定します。Dockerホストやコンテナは、1つの仮想的なbridgeネットワークで接続され、IPアドレスが割り当てられます。

コンテナに割り当てられているIPアドレスの確認

コンテナに対して、どのようなIPアドレスが割り当てられるのかを確認してみます。

コンテナの作成

ここでは、2つのhttpdコンテナを起動し、そのコンテナに割り当てられるIPアドレスを確認します。httpdの使い方は以下のサイトに記載されています。

https://hub.docker.com/_/httpd

以下のコマンドでポート番号8080に割り当てた「web01」とポート番号8081に割り当てた「web02」という名前のコンテナをそれぞれ作成します。

docker run -dit --name web01 -p 8080:80 httpd:2.4
docker run -dit --name web02 -p 8081:80 httpd:2.4


二つのhttpdコンテナを作成

IPアドレスの確認

コンテナが起動したらIPアドレスを確認します。
この際に、Dockerの詳細情報を取得するためのコマンドであるdocker inspectコマンドを用いてコンテナの情報を抜き出し、さらに--formatオプションを用いてIPアドレスの部分だけを表示させるようにします。

docker container inspect --format="{{.NetworkSettings.IPAddress}}" web01
docker container inspect --format="{{.NetworkSettings.IPAddress}}" web02

これにより、web01には「172.17.0.2」、web02には「172.17.0.3」のIPアドレスが設定されていることが判明しました。

IPアドレスを利用したDockerコンテナ同士の通信

コンテナはそれぞれ異なるIPアドレスを持ち、bridgeネットワークに接続されています。そのため、コンテナ同士はこのネットワークを通じて互いに自由に通信を行うことができます。

ここで注意が必要です。Dockerコンテナ間で通信する際は-pオプションを設定する必要がないということです。-pオプションはDockerホスト側で受信したデータをそれぞれのDockerコンテナの特定のポートに転送する設定ですが、Dockerホストを経由しない通信の場合には必要ありません。

1. 三つ目のコンテナの作成

実際にコンテナ間で通信できるのか試してみます。
ここでは、三つ目のコンテナを作成し、そのコンテナからweb01とweb02に通信可能かどうかを確認します。

以下のコマンドで新しいubuntuコンテナを作成し、シェルを起動します。実行するとプロンプトが表示され、コンテナ内でコマンド入力ができるようになります。

docker run --rm -it ubuntu /bin/bash


コマンド入力できるように

2. 必要なものをインストール

コマンド入力できるようになったら、以下のコマンドをそれぞれ入力することでネットワーク関連の操作を可能にします。

apt update
apt -y upgrade
apt install -y iproute2 iputils-ping curl
  • apt update
    パッケージリストを最新の状態に更新します。これにより、システムは最新の利用可能なパッケージ情報を取得します。

  • apt -y upgrade
    インストールされているすべてのパッケージを最新バージョンにアップグレードします。-yオプションは、すべての質問に対して自動的に「yes」と答えるため、ユーザーの確認を省略します。

  • apt install -y iproute2 iputils-ping curl
    iproute2iputils-ping、およびcurlパッケージをインストールします。

    • iproute2: ネットワークインターフェイスやルーティングを管理するためのツールセットであり、ipコマンドなどが含まれています。
    • iputils-ping: ネットワークの接続性を確認するための pingコマンドを提供します。
    • curl: URLからデータを取得するためのコマンドラインツールであり、HTTP、HTTPS、FTPなどのプロトコルをサポートしています。

3. IPアドレスを確認する

ipコマンドでIPアドレスを確認します。

ip address

画像の最後の部分に表示されているeth0インターフェイスのinetの部分を確認すると、IPアドレスは「172.17.0.4」であることが確認できました。

4. pingで疎通確認

既に確認してあるweb01やweb02のIPアドレスに対してpingを3回送信して疎通確認をします。

ping -c 3 172.17.0.2


web01へのping送信

ping -c 3 172.17.0.3


web02へのping送信

結果が「0% packet loss」となっていることから、通信できていることがわかります。

5. コンテンツを取得

次に、curlコマンドを使用してweb01やweb02に接続することで、公開されているWebコンテンツを取得できるかを確認します。

curl http://172.17.0.2/
curl http://172.17.0.3/

「It works!」と表示されていることから、Webコンテンツを取得できていることがわかります。

6. IPアドレス以外で接続確認

ここで、コンテナ名で接続しようとすると、どうなるでしょうか。
web01を指定して、ipコマンドやcurlコマンドを使用してみます。

ping -c 3 web01
curl http://web01/


実行画面

どちらも同様に、web01が見つからないというエラーが発生します。

7. 作業終了

exitと入力して終了します。

exit

Dockerネットワークを作成してコンテナ名を指定できるようにする

今までの作業で、コンテナはそれぞれ割り当てられたIPアドレスを利用して、互いに通信できることがわかりました。同時に、IPアドレスの代わりとしてコンテナ名を使って通信することはできないということもわかりました。
コンテナに対して、どのようなIPアドレスが割り当てられるのかはコンテナを起動するまでわからないため、コンテナ名で通信相手を指定できないのはとても不便です。また、コンテナを破棄して作り直した場合に、IPアドレスが変わる恐れがあるのも問題です。

ここで、IPアドレスではなくコンテナ名で通信相手を指定できるようにする方法として、Dockerネットワークを新規に作成する方法が存在します。
Dockerネットワークを新規に作成することにより、同じネットワーク内のコンテナはコンテナ名で通信できるようになります。

1. Dockerネットワークの新規作成

実際に確認してみます。
Dockerネットワークはdocker network createコマンドを用いて作成することができます。以下のコマンドで「mynetwork」という名前のDockerネットワークを新規作成します。

docker network create mynetwork


Dockerネットワークを新規作成

docker network lsコマンドで確認すると、「mynetwork」が作成されていることが確認できました。


「mynetwork」が存在している

ここで、ネットワークの情報を表示するdocker network inspectコマンドを利用して、「mynetwork」の情報を確認してみます。

docker network inspect mynetwork

この情報から、ネットワークのサブネットが「172.18.0.0/16」であり、ゲートウェイのIPアドレスが「172.18.0.1」であることが確認できました。

2. Dockerネットワーク上でコンテナを作成

新規作成したネットワークに参加するコンテナを作ってみます。また、この際に、稼働しているweb01とweb02を破棄し、「mynetwork」に接続するようにして作り直すことにします。


web01及びweb02の停止と破棄

ネットワークに接続させるには、docker runの実行時に--netオプションで接続したいネットワークを指定する必要があります。

docker run -dit --name web01 -p 8080:80 --net mynetwork httpd:2.4
docker run -dit --name web02 -p 8081:80 --net mynetwork httpd:2.4


接続完了

docker network inspectコマンドでネットワークの情報を確認してみると、web01とweb02が「mynetwork」に接続されていることがわかります。

3. コンテナ名で接続確認

では、同じネットワーク内のコンテナは本当にコンテナ名で通信できるようになっているのか確認してみます。
今回も三つ目のコンテナを作成し、そのコンテナからweb01とweb02に通信可能かどうかを確認します。この際に--netオプションで「mynetwork」を指定してコンテナを作成します。

docker run --rm -it --net mynetwork ubuntu /bin/bash

コマンド入力できるようになったら、以下のコマンドをそれぞれ入力することでネットワーク関連の操作を可能にします。

apt update
apt -y upgrade
apt install -y iproute2 iputils-ping curl

入力したら、web01やweb02に対してpingを送信してみます。ここでは、先ほどとは違い、IPアドレスではなくコンテナ名を指定してpingを送信してみます。

ping -c 3 web01
ping -c 3 web02


コンテナ名を指定したping送信

結果が「0% packet loss」となっていることから、通信できていることがわかります。

また、curlコマンドを使用してweb01やweb02に接続することで、公開されているWebコンテンツを取得できるかを確認します。ここでも、IPアドレスではなくコンテナ名を指定します。

curl http://web01/
curl http://web02/

「It works!」と表示されていることから、Webコンテンツを取得できていることがわかります。

コンテナ名で通信できる仕組み

ここまでの流れで、Dockerネットワークを新規に作成することにより、コンテナ名で通信できるようになることがわかりました。
では、なぜコンテナ名で通信できるようになっているのでしょうか?

それは、Dockerネットワークで内蔵DNSサーバが提供されるからです。

Docker公式ドキュメント日本語訳を確認すると、以下のように説明されていました。

Dockerデーモンは内蔵DNSサーバを動かし、ユーザ定義ネットワーク上でコンテナがサービス・ディスカバリを自動的に行えるようにします。コンテナから名前解決のリクエストがあれば、内部DNSサーバを第一に使います。リクエストがあっても内部DNSサーバが名前解決できなければ、外部のDNSサーバにコンテナからのリクエストを転送します。割り当てできるのはコンテナの作成時だけです。内部DNSサーバが到達可能なのは127.0.0.11のみであり、コンテナのresolv.confに書かれます。

catコマンドでコンテナのresolv.confを実際に確認してみると、以下のように表示されました。

cat /etc/resolv.conf


/etc/resolv.conf」ファイルの中身

Docker公式ドキュメント日本語訳にも記載されている通り、nameserver 127.0.0.11はDockerがコンテナ用に提供する内部DNSサーバーのIPアドレスです。この内部DNSサーバーを使うことで、同じDockerネットワーク内のコンテナ名を名前解決できます。

また、ExtServers: [192.168.65.7]から、外部DNSサーバーのIPアドレスが「192.168.65.7」であることもわかりました。

この設定により、Dockerネットワーク内のコンテナはコンテナ名でお互いに通信できるようになります。

Dockerネットワークの削除

作成した「mynetwork」を削除します。
まず、「mynetwork」を利用しているコンテナを停止した後に破棄します。


web01及びweb02の停止と破棄

コンテナを破棄したら、docker network rmコマンドを用いて「mynetwork」を削除します。

docker network rm mynetwork


「mynetwork」を削除

docker network lsコマンドで確認すると、「mynetwork」が作成されていることが確認できました。


「mynetwork」が存在していない

ここで、使い終わったイメージも削除しておきます。docker image lsでイメージ一覧を表示します。


イメージ一覧

確認したら本当に消しても良いかどうかをよく確認して、問題がなければイメージを一括削除しましょう。

hostネットワーク

hostネットワークは、コンテナがホストのネットワークスタックを直接使用するネットワークモードです。
DockerホストのIPアドレスを全Dockerコンテナで共有して使うことができるため、ネットワーク性能が重要なアプリケーションやホストのIPアドレスをそのまま使用したい場合に適しています。これにより、ネットワークのオーバーヘッドが少なくなるため、通信速度の向上が見込めます。また、コンテナがホストのネットワークを直接使用するため、ネットワークの設定が簡素化されるというメリットもあります。

noneネットワーク

noneネットワークは、コンテナがネットワークに接続しないネットワークモードです。
ネットワーク通信を必要としないため、バッチ処理やデータ処理タスクなど、外部と通信させたくないコンテナを完全に独立した環境で作成できるというメリットがあります。

さいごに

ざっくりまとめてみます。

  1. bridgeネットワーク
    bridgeネットワークははDockerのデフォルトネットワークモードであり、ネットワークオプションを指定しない場合に使用されます。Dockerホストやコンテナは、1つの仮想的なbridgeネットワークで接続され、IPアドレスが割り当てられます。また、Dockerホスト同士はIPアドレスで接続できます。IPアドレスは、docker inspectコマンドで確認できます。

  2. Dockerコンテナ間の通信では-pオプションは必要ない
    Dockerコンテナ間の通信では、-pオプションを指定する必要がありません。コンテナ上の実際のポート番号で通信します。

  3. 名前を指定して通信したい場合はDockerネットワークを作る
    コンテナ間の通信をする際に、コンテナ名でアクセスしたい場合にはdocker network createで新しいDockerネットワークを作りましょう。docker runを行う際に--netオプションでそのネットワークにコンテナを参加させることにより、コンテナ名でアクセスできるようになります。

  4. hostネットワーク
    hostネットワークはDockerホストのIPアドレスを全Dockerコンテナで共有して使うネットワークモードです。

  5. noneネットワーク
    noneネットワークはネットワークに接続しないネットワークモードです。

ここまで記事を読んでくださり、ありがとうございました!
今後も、Dockerを理解するために突き進んでいきたいと思います!

皆さんも素敵なハッピーDockerライフを!!!🌸

GitHubで編集を提案

Discussion