Dockerのネットワーク構成

こんにちは、サイオステクノロジー技術部 武井です。Dockerのネットワークが気になったのでちょっと調べてみました。

以下のコマンドで簡単なコンテナを起動して、内部のネットワークを調べてみました。PHPが動作するWebサーバーを立ち上げて、-pオプションで80番をポートフォワードします。

# docker run -d -p 80:80  --name php70-apache  php:7.0-apache

こんな構成になっているようです。

Screen Shot 2018-09-13 at 11.51.45

仮想ブリッジが内部にあり、veth(Virtual Ethernet Pair)が仮想ブリッジにつながっていて、そのペアにコンテナ側のインターフェースがいます。 vethは仮想的なネットワークインターフェースで、異なるnamespaceにあるインターフェース同士をつなぐことが出来ます。

つまり、仮想ブリッジを介して、コンテナ同士がL2のレイヤーでつながっています。

試しに見てみました。

 

# ip addr show
...
4: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP 
    link/ether 02:42:68:de:b6:2a brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
       valid_lft forever preferred_lft forever
    inet6 fe80::42:68ff:fede:b62a/64 scope link 
       valid_lft forever preferred_lft forever
6: vethca38e86@if5: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP 
    link/ether 22:35:bb:aa:3d:15 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet6 fe80::2035:bbff:feaa:3d15/64 scope link 
       valid_lft forever preferred_lft forever
...

docker0という仮想ブリッジがあるのが見えました。仮想ブリッジは172.17.0.1というIPアドレスを持っていました。

また、vethca38e86というのが、vethのインターフェースで、コンテナ側のネットワークインターフェースとケーブルで繋がっているようなイメージです。

こちらも以下のコマンドで見てみました。

# brctl show
bridge name bridge id       STP enabled interfaces
docker0     8000.024268deb62a   no      vethca38e86

仮想ブリッジに先程のvethca38e86のインターフェースが接続されているのがわかります。

物理NICと仮想ブリッジは通信は、OSの機能でルーティングされます。以下のコマンドで見てみましたが、172.17.0.0/16宛の通信がdocker0(仮想ブリッジのインターフェース)にルーティングされているのがわかります。

# ip route
default via 10.0.2.2 dev enp0s3  proto static  metric 100 
10.0.2.0/24 dev enp0s3  proto kernel  scope link  src 10.0.2.15  metric 100 
172.17.0.0/16 dev docker0  proto kernel  scope link  src 172.17.0.1 
192.168.56.0/24 dev enp0s8  proto kernel  scope link  src 192.168.56.38  metric 100 

iptablesの設定も見てみました。

# Generated by iptables-save v1.4.21 on Mon Sep 10 22:38:05 2018
*nat
:PREROUTING ACCEPT [11:1858]
:INPUT ACCEPT [9:706]
:OUTPUT ACCEPT [115:8648]
:POSTROUTING ACCEPT [115:8648]
:DOCKER - [0:0]
-A PREROUTING -m addrtype --dst-type LOCAL -j DOCKER
-A OUTPUT ! -d 127.0.0.0/8 -m addrtype --dst-type LOCAL -j DOCKER
-A POSTROUTING -s 172.17.0.0/16 ! -o docker0 -j MASQUERADE
-A POSTROUTING -s 172.17.0.2/32 -d 172.17.0.2/32 -p tcp -m tcp --dport 80 -j MASQUERADE
-A DOCKER -i docker0 -j RETURN
-A DOCKER ! -i docker0 -p tcp -m tcp --dport 80 -j DNAT --to-destination 172.17.0.2:80
COMMIT
# Completed on Mon Sep 10 22:38:05 2018
# Generated by iptables-save v1.4.21 on Mon Sep 10 22:38:05 2018
*filter
:INPUT ACCEPT [1127:114395]
:FORWARD DROP [0:0]
:OUTPUT ACCEPT [701:70242]
:DOCKER - [0:0]
:DOCKER-ISOLATION-STAGE-1 - [0:0]
:DOCKER-ISOLATION-STAGE-2 - [0:0]
:DOCKER-USER - [0:0]
-A FORWARD -j DOCKER-USER
-A FORWARD -j DOCKER-ISOLATION-STAGE-1
-A FORWARD -o docker0 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -o docker0 -j DOCKER
-A FORWARD -i docker0 ! -o docker0 -j ACCEPT
-A FORWARD -i docker0 -o docker0 -j ACCEPT
-A DOCKER -d 172.17.0.2/32 ! -i docker0 -o docker0 -p tcp -m tcp --dport 80 -j ACCEPT
-A DOCKER-ISOLATION-STAGE-1 -i docker0 ! -o docker0 -j DOCKER-ISOLATION-STAGE-2
-A DOCKER-ISOLATION-STAGE-1 -j RETURN
-A DOCKER-ISOLATION-STAGE-2 -o docker0 -j DROP
-A DOCKER-ISOLATION-STAGE-2 -j RETURN
-A DOCKER-USER -j RETURN
COMMIT
# Completed on Mon Sep 10 22:38:05 2018

以下のPREROUTINGチェインで、物理NICの80番ポート宛への通信の宛先を、コンテナのIPアドレスの80番あてへとDNATしているようです。

-A PREROUTING -m addrtype --dst-type LOCAL -j DOCKER
-A DOCKER -i docker0 -j RETURN
-A DOCKER ! -i docker0 -p tcp -m tcp --dport 80 -j DNAT --to-destination 172.17.0.2:80

ローカルのインターフェース宛に届いたパケットは、独自定義のチェインDOCKERに飛んで、2番めのチェインでは、送信元のインターフェースがdoker0(仮想ブリッジのインターフェース)ではないので、そのまま3番目のチェインに飛んで、そこで宛先が80/tcpの通信は、コンテナのIPアドレスの80番にDNATしているという感じだと思います、多分。

こんな感じで、コンテナまでパケットが届くんだということがわかりました。

物理的に以下のようなネットワークを、仮想ブリッジやiptablesなどの機能でエミュレートしているのだと思います、多分。

Screen Shot 2018-09-13 at 11.51.31

以上です。今回は備忘録というかメモ的な感じですみません(´・ω・`)

ご覧いただきありがとうございます! この投稿はお役に立ちましたか?

役に立った 役に立たなかった

0人がこの投稿は役に立ったと言っています。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です