■debian stretch上のdockerでbridgeネットワークを使ってみる。
ユーザ定義NWを作成したときの要件の確認方法にもなるはず。
debian stretchにdockerを導入する。
http://labunix.hateblo.jp/entry/20171230/1514570030
$ lsb_release -a
No LSB modules are available.
Distributor ID: Debian
Description: Debian GNU/Linux 9.3 (stretch)
Release: 9.3
Codename: stretch
$ uname -a
Linux vmx-rdebian 4.9.0-4-amd64
$ sudo docker version
Client:
Version: 17.05.0-ce
API version: 1.29
Go version: go1.7.5
Git commit: 89658be
Built: Thu May 4 22:09:06 2017
OS/Arch: linux/amd64
Server:
Version: 17.05.0-ce
API version: 1.29 (minimum version 1.12)
Go version: go1.7.5
Git commit: 89658be
Built: Thu May 4 22:09:06 2017
OS/Arch: linux/amd64
Experimental: false
■ホストのネットワークを確認
$ sudo brctl show
bridge name bridge id STP enabled interfaces
br0 8000.b888e30e05ab no eth0
tap0
docker0 8000.02427f0e6490 no veth6994522
$ ip a | awk '/^[0-9]/&&/docker|veth/{gsub(":|@.*","",$2);print "ip a show dev "$2}' | sh
5: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:7f:0e:64:90 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.1/16 scope global docker0
valid_lft forever preferred_lft forever
inet6 fe80::42:7fff:fe0e:6490/64 scope link
valid_lft forever preferred_lft forever
19: veth6994522@if18: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default
link/ether 0a:62:de:b4:cd:0c brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet6 fe80::862:deff:feb4:cd0c/64 scope link
valid_lft forever preferred_lft forever
■コンテナネットワークの設定を確認
Docker コンテナ・ネットワークの理解
http://docs.docker.jp/engine/userguide/networking/dockernetworks.html
$ sudo docker network ls
[sudo] labunix のパスワード:
NETWORK ID NAME DRIVER SCOPE
f680c6aff70a bridge bridge local
8adb60e19794 host host local
8c8319c9eba2 none null local
■bridge、host、noneの三種類のコンテナネットワークがある。
$ sudo docker network ls | awk '/[a-z]/{print "docker network inspect "$2}' | sudo sh
[
{
"Name": "bridge",
"Id": "f680c6aff70a3f21e186de1b7acdd78fdd97412cea74f0ff5b29774cbcb371ec",
"Created": "2017-12-30T02:02:27.2509216+09:00",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": null,
"Config": [
{
"Subnet": "172.17.0.0/16",
"Gateway": "172.17.0.1"
}
]
},
"Internal": false,
"Attachable": false,
"Ingress": false,
"Containers": {},
"Options": {
"com.docker.network.bridge.default_bridge": "true",
"com.docker.network.bridge.enable_icc": "true",
"com.docker.network.bridge.enable_ip_masquerade": "true",
"com.docker.network.bridge.host_binding_ipv4": "0.0.0.0",
"com.docker.network.bridge.name": "docker0",
"com.docker.network.driver.mtu": "1500"
},
"Labels": {}
}
]
[
{
"Name": "host",
"Id": "8adb60e197949aa0bf906f49d89a28b553a001ccbcbc383445021e8219435636",
"Created": "2017-12-30T01:22:14.977704593+09:00",
"Scope": "local",
"Driver": "host",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": null,
"Config": []
},
"Internal": false,
"Attachable": false,
"Ingress": false,
"Containers": {},
"Options": {},
"Labels": {}
}
]
[
{
"Name": "none",
"Id": "8c8319c9eba242568c52267309b721d01a858bcdc3105281ecd81dc179791bae",
"Created": "2017-12-30T01:22:14.772088895+09:00",
"Scope": "local",
"Driver": "null",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": null,
"Config": []
},
"Internal": false,
"Attachable": false,
"Ingress": false,
"Containers": {},
"Options": {},
"Labels": {}
}
]
■上記を元にNW構成を描くと以下のようになる。
「docker0 <--> br0」間はdockerネットワークで自動生成されるホストのIPマスカード/DNAT機能を使用する。
$ echo "[container1(eth0)],[container2(eth0)] -- [veth...1],[veth...2] -- [docker0] -- [br0]" | \
graph-easy --dot | grep -v "1.*2\|2.*1" | graph-easy
+------------------+ +----------+ +---------+ +-----+
| container1(eth0) | --> | veth...1 | --> | docker0 | --> | br0 |
+------------------+ +----------+ +---------+ +-----+
^
|
|
+------------------+ +----------+ |
| container2(eth0) | --> | veth...2 | ------+
+------------------+ +----------+
■以下のように直接「br0」に接続することも出来るようだが、
ホストのNWに干渉しては困るので、この方式は見送るものとする。
Dockerコンテナをブリッジ接続で使う
https://www.agilegroup.co.jp/technote/docker-network-in-bridge.html
$ echo "[container1(eth0)],[container2(eth0)] -- [veth...1],[veth...2] -- [br0]" | \
graph-easy --dot | grep -v "1.*2\|2.*1" | graph-easy
+------------------+ +----------+ +-----+
| container1(eth0) | --> | veth...1 | --> | br0 |
+------------------+ +----------+ +-----+
^
|
|
+------------------+ +----------+ |
| container2(eth0) | --> | veth...2 | ------+
+------------------+ +----------+
■デフォルトでコンテナはbridgeに接続、ホストはgateway側なので、
以下のようにpingで疎通確認ができる。
$ sudo docker network inspect bridge | awk '/Gateway|Subnet/'
"Subnet": "172.17.0.0/16",
"Gateway": "172.17.0.1"
$ sudo docker run -ti httpd /bin/bash
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1
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
20: eth0@if21: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.2/16 scope global eth0
valid_lft forever preferred_lft forever
default via 172.17.0.1 dev eth0
172.17.0.0/16 dev eth0 proto kernel scope link src 172.17.0.2
PING 172.17.0.1 (172.17.0.1): 56 data bytes
64 bytes from 172.17.0.1: icmp_seq=0 ttl=64 time=0.156 ms
64 bytes from 172.17.0.1: icmp_seq=1 ttl=64 time=0.118 ms
64 bytes from 172.17.0.1: icmp_seq=2 ttl=64 time=0.075 ms
--- 172.17.0.1 ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max/stddev = 0.075/0.116/0.156/0.033 ms
exit
■コンテナをポート転送で起動、動作確認、停止、削除する。
$ docker run --help | awk '/-[dpv],/'
-d, --detach Run container in background and print container ID
-p, --publish list Publish a container's port(s) to the host
-v, --volume list Bind mount a volume
$ test -d /tmp/mypage || sudo mkdir /tmp/mypage ;echo "Hello World" | sudo tee /tmp/mypage/index.html >/dev/null
$ sudo docker run -d -p 8000:80 -v "/tmp/mypage/:/usr/local/apache2/htdocs/" httpd
69c1b74c1e81ed4a73e7be0934ca297e8d4756d6c947461e9b6d61fed41a0f12
$ sudo docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
69c1b74c1e81 httpd "httpd-foreground" 22 seconds ago Up 20 seconds 0.0.0.0:8000->80/tcp admiring_lumiere
$ w3m -no-proxy -dump http://172.17.0.2/
Hello World
$ sudo docker ps | awk '/httpd/{print "docker stop "$1}' | sudo sh
69c1b74c1e81
$ sudo docker ps;sudo docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
69c1b74c1e81 httpd "httpd-foreground" 17 minutes ago Exited (0) 21 seconds ago admiring_lumiere
$ sudo docker ps -a | awk '/httpd/{print "docker rm "$1}' | sudo sh
69c1b74c1e81
$ sudo docker ps;sudo docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
■dockerのNATはホスト側のiptablesに自動追加されている。
docker0以外のインターフェイス宛で送信元がbridgeのサブネット内ならIPマスカレードする。
$ cat /proc/sys/net/ipv4/conf/all/forwarding
1
$ sudo iptables -L -t nat -v -n
[sudo] labunix のパスワード:
Chain PREROUTING (policy ACCEPT 454 packets, 113K bytes)
pkts bytes target prot opt in out source destination
2 144 DOCKER all -- * * 0.0.0.0/0 0.0.0.0/0 ADDRTYPE match dst-type LOCAL
Chain INPUT (policy ACCEPT 454 packets, 113K bytes)
pkts bytes target prot opt in out source destination
Chain OUTPUT (policy ACCEPT 32329 packets, 1960K bytes)
pkts bytes target prot opt in out source destination
2 120 DOCKER all -- * * 0.0.0.0/0 !127.0.0.0/8 ADDRTYPE match dst-type LOCAL
Chain POSTROUTING (policy ACCEPT 32329 packets, 1960K bytes)
pkts bytes target prot opt in out source destination
1 60 MASQUERADE all -- * !docker0 172.17.0.0/16 0.0.0.0/0
Chain DOCKER (2 references)
pkts bytes target prot opt in out source destination
1 84 RETURN all -- docker0 * 0.0.0.0/0 0.0.0.0/0
■「-p」オプションでコンテナを起動するとDNATルールが追加される。
$ sudo docker run -d -p 8000:80 -v "/tmp/mypage/:/usr/local/apache2/htdocs/" httpd
f1dfb6c3b7d2094ce21d16ea5dc63f078b18360eef8ea3259c18ec3ac706995e
$ sudo docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
f1dfb6c3b7d2 httpd "httpd-foreground" 7 seconds ago Up 4 seconds 0.0.0.0:8000->80/tcp wizardly_stallman
$ w3m -no-proxy -dump http://172.17.0.2/
Hello World
$ w3m -no-proxy -dump http://vm-host:8000/
Hello World
$ sudo iptables -L -t nat -v -n
Chain PREROUTING (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
3 204 DOCKER all -- * * 0.0.0.0/0 0.0.0.0/0 ADDRTYPE match dst-type LOCAL
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
Chain OUTPUT (policy ACCEPT 11 packets, 746 bytes)
pkts bytes target prot opt in out source destination
3 180 DOCKER all -- * * 0.0.0.0/0 !127.0.0.0/8 ADDRTYPE match dst-type LOCAL
Chain POSTROUTING (policy ACCEPT 13 packets, 866 bytes)
pkts bytes target prot opt in out source destination
1 60 MASQUERADE all -- * !docker0 172.17.0.0/16 0.0.0.0/0
0 0 MASQUERADE tcp -- * * 172.17.0.2 172.17.0.2 tcp dpt:80
Chain DOCKER (2 references)
pkts bytes target prot opt in out source destination
1 84 RETURN all -- docker0 * 0.0.0.0/0 0.0.0.0/0
2 120 DNAT tcp -- !docker0 * 0.0.0.0/0 0.0.0.0/0 tcp dpt:8000 to:172.17.0.2:80
■ここでは「!docker0(br0) -- (DNAT) --> docker0」なので、
自ホスト以外からのHTTPリクエストがあればカウントアップする。
$ sudo iptables -L -v -n | grep -v f2b
Chain INPUT (policy ACCEPT 3414 packets, 7527K bytes)
pkts bytes target prot opt in out source destination
Chain FORWARD (policy DROP 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
10 1089 DOCKER-ISOLATION all -- * * 0.0.0.0/0 0.0.0.0/0
4 506 ACCEPT all -- * docker0 0.0.0.0/0 0.0.0.0/0 ctstate RELATED,ESTABLISHED
1 60 DOCKER all -- * docker0 0.0.0.0/0 0.0.0.0/0
5 523 ACCEPT all -- docker0 !docker0 0.0.0.0/0 0.0.0.0/0
0 0 ACCEPT all -- docker0 docker0 0.0.0.0/0 0.0.0.0/0
Chain OUTPUT (policy ACCEPT 3454 packets, 192K bytes)
pkts bytes target prot opt in out source destination
Chain DOCKER (1 references)
pkts bytes target prot opt in out source destination
1 60 ACCEPT tcp -- !docker0 docker0 0.0.0.0/0 172.17.0.2 tcp dpt:80
Chain DOCKER-ISOLATION (1 references)
pkts bytes target prot opt in out source destination
10 1089 RETURN all -- * * 0.0.0.0/0 0.0.0.0/0
pkts bytes target prot opt in out source destination
0 0 RETURN all -- * * 0.0.0.0/0 0.0.0.0/0