Dockerは、コンテナというコンパクトで強固な仮想環境を提供してくれるのですが、ネットワークに関しても、他の仮想化技術に負けない仮想ネットワーク機能が実装されてます。
Dockerを利用するメリットの一つにスケーラビリティの高さが挙げられますが、それを最大限に活用するためには、Dockerの仮想ネットワークの理解が必要になります。
本記事では、Dockerのネットワーク機能をご紹介すると共に、実際にその作り方について解説していきます。
Dockerネットワークのデフォルト構成
Dockerネットワークとは、Docker環境内の仮想ネットワークのことを指します。
Dockerコンテナが、他のコンテナや外部ホスト、外部クライアントなどと通信を行うためには、Dockerネットワークを利用することが必要です。
実はDocker本体のインストール時に、Dockerホスト内に以下の3つのDockerネットワークがデフォルトで作成されます。
- bridge
- host
- none
まずは、この3つのDockerネットワークについて解説していきます。
bridge
bridgeネットワークは、Dockerホスト内のブリッジ用ネットワークインターフェースdocker0と接続されたDockerネットワークです。
docker0はDockerインストール時に自動的に作成されます。
コンテナをbridgeネットワークに接続することで、ブリッジ用ネットワークインターフェースdocker0を介して、Dockerホスト内外のノードと通信できるようになります。
host
hostネットワークに参加したコンテナは、Dockerホストの物理ネットワークインターフェースを直接利用することになります。
つまり、コンテナ内からDockerホストの物理ネットワークインターフェースが丸見えの状態になります。
もちろんIPアドレスもDockerホストと同じものを使用することになります。
none
noneネットワークに参加したコンテナは、外部向けのネットワークインターフェースを持たない状態になります。つまりループバックインターフェースのみの状態です。
ネットワーク的に外部と完全に切り離したいコンテナは、noneネットワークに参加させます。
bridgeネットワークについてもう少し解説
前項の3つのネットワークの中で最も利用頻度の高いbridgeネットワークについてもう少し詳細に解説します。
bridgeネットワーク環境を図にしてみました。
bridgeネットワークの実体であるdocker0インターフェイスの前後には、各コンテナ用の仮想ネットワークインターフェイス(仮想nic部分)、コンテナ用の仮想ネットワークインターフェイスの実体(vethxx部分)、Dockerホストの物理インターフェイスeth0が存在します。
docker0とeth0は、DockerホストのOS機能であるiptablesによるIPマスカレードが行われています。
コンテナ内の仮想ネットワークインターフェースの実体は、Dockerホスト上のネットワークインターフェース(vethxx部分)でして、そのインターフェイスはコンテナを仮想ネットワークに参加させることで自動的に作成されます。
コンテナは、各コンテナ用の仮想ネットワークインターフェイスvethxxをブリッジdocker0に接続することで通信できるようになります。
実際に見てみましょう。
まず、現在のDockerホスト上のネットワークインターフェースの状態です。
$ ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
link/ether xx:xx:xx:xx:xx:xx brd ff:ff:ff:ff:ff:ff
inet 192.168.1.154/24 brd 192.168.1.255 scope global eth0
valid_lft forever preferred_lft forever
3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN
link/ether xx:xx:xx:xx:xx:xx brd ff:ff:ff:ff:ff:ff
inet 172.17.0.1/16 scope global docker0
valid_lft forever preferred_lft forever
この状態で、Ubuntuイメージを使用してDockerコンテナを起動してみます。
$ docker run -dit --init --name testvm ubuntu
このときのDockerホスト上のネットワークインターフェースの状態を見てみましょう。
$ ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
link/ether xx:xx:xx:xx:xx:xx brd ff:ff:ff:ff:ff:ff
inet 192.168.1.154/24 brd 192.168.1.255 scope global eth0
valid_lft forever preferred_lft forever
3: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP
link/ether xx:xx:xx:xx:xx:xx brd ff:ff:ff:ff:ff:ff
inet 172.17.0.1/16 scope global docker0
valid_lft forever preferred_lft forever
5: veth7cbc9a1@if4: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP
link/ether xx:xx:xx:xx:xx:xx brd ff:ff:ff:ff:ff:ff link-netnsid 0
「veth7cbc9a1@if4」というインターフェースが追加されてます。これが、今起動したコンテナの仮想ネットワークインターフェースになります。
このインターフェースはブリッジdocker0と接続されています。brctlコマンドで確認してみましょう。
Dockerホスト上で以下のコマンドを実行します。
$ brctl show
bridge name bridge id STP enabled interfaces
docker0 8000.024223c4193a no veth7cbc9a1
接続されていることが確認できました。
独自ネットワークの作成方法
コンテナ作成時にDockerネットワークを指定しない場合は、デフォルトでbridgeネットワークに自動的に参加します。
同じDockerネットワークに所属するコンテナは、お互いに通信可能な状態になります。よって、Dockerネットワークを指定せずに起動したコンテナは全てbridgeネットワークに参加することになるため、お互いに通信可能です。
しかし場合によっては、ネットワークを別にして、ネットワーク的に隔離したいコンテナもあると思います。
その場合は、手動で新規にDockerネットワークを作成して、そのネットワークを利用します。
早速作成してみましょう。
まず、現状のDockerネットワークの状態です。Dockerのデフォルトのネットワークのみの状態です。
$ docker network ls
NETWORK ID NAME DRIVER SCOPE
8b2a7b193570 bridge bridge local
76436c8075b5 host host local
825a5633a688 none null local
※docker network lsはDockerネットワークの一覧を出力するコマンドです
この状態で新規にネットワークtestnet01を追加します。
$ docker network create -d bridge testnet01
※docker network createはDockerネットワークを作成するコマンドです
docker network lsコマンドで確認します。
$ docker network ls
NETWORK ID NAME DRIVER SCOPE
8b2a7b193570 bridge bridge local
76436c8075b5 host host local
825a5633a688 none null local
15400500e201 testnet01 bridge local
testnet01が追加されていることが確認できました。
このときのDockerホスト上のネットワークインターフェースの状態を見てみましょう。
$ ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
link/ether 00:15:5d:01:46:07 brd ff:ff:ff:ff:ff:ff
inet 192.168.1.154/24 brd 192.168.1.255 scope global eth0
valid_lft forever preferred_lft forever
3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN
link/ether 02:42:f2:98:cb:47 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.1/16 scope global docker0
valid_lft forever preferred_lft forever
4: br-15400500e201: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN
link/ether 02:42:86:27:2d:c8 brd ff:ff:ff:ff:ff:ff
inet 172.18.0.1/16 scope global br-15400500e201
valid_lft forever preferred_lft forever
「br-15400500e201」が追加されてます。これが、今追加したtestnet01用のインターフェースなのですが、念のためdockerネットワークの詳細情報を確認するコマンド「docker network inspect」でtestnet01の情報を見てみましょう。
$ docker network inspect testnet01
[
{
"Name": "testnet01",
"Id": "15400500e201c6e3d5b5f0e4b7ad74d44c59d051a6a549326b42a4fb37ad28cc",
"Created": "2017-03-29T12:02:47.450216744+09:00",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": {},
"Config": [
{
"Subnet": "172.18.0.0/16",
"Gateway": "172.18.0.1"
(以下略)
「Gateway」のIPアドレスとして172.18.0.1が設定されていることが確認できます。先ほどネットワークインターフェースの状態を確認した際に出力された「br-15400500e201」に設定されていたIPアドレスと同じです。
また、testnet01の情報の中のIdの先頭から12文字がインターフェース名の「br-」の後に付けられています。これはDockerの仕様です。
以上より、手動でDockerネットワークを追加しますと、Dockerホスト上に自動的にブリッジインターフェースが作成されることがわかります。
まとめ
今回はDockerの仮想ネットワークの解説と、実際にDockerネットワークを作成しました。
LinuxコマンドやDockerのコマンドなどで実際の環境情報をご覧いただきましたので、より具体的にご理解いただけたのではないでしょうか。
Dockerホストを個人で使用している場合は、仮想ネットワークはそれほど必要性を感じないかもしれません。
しかし、複数人で多様なサービスを使用するような環境では、仮想ネットワークを使用してコンテナのネットワークを分ける必要性が出てくると思います。
また場合によっては、1つのコンテナを複数のネットワークに参加させた方が都合の良いこともあると思います。
Dockerネットワークは、構成がシンプルですので、このような様々なニーズに柔軟に対応できるように作られてます。
最後までお読みいただきありがとうございました。
コメント