LoginSignup
11
7

More than 5 years have passed since last update.

Dockerとホストのネットワーク on EC2

Last updated at Posted at 2017-07-23

全然理解していなかったのでちゃんと勉強してみました。

試した環境

AMIは Amazon Linux AMI amzn-ami-hvm-2017.03.1 (ami-3bd3c45c) を使用しています。
インスタンスタイプは t2.micro です。
ポートは :22 (ssh) だけ開けました。

予め、docker をインストールします。

$ sudo yum install -y docker
$ sudo service docker start

ブリッジを操作するコマンド brctl をインストールします。

$ sudo yum install -y bridge-utils

本投稿では sudo は省略 (alias) しています。

$ vi ~/.bash_profile

# これを追加
alias docker='sudo docker'
alias ip='sudo ip'
alias brctl='sudo brctl'

$ source ~/.bash_profile

コンテナが2つある時のネットワーク

図にするとこんな感じです

default.png

まずはコンテナ2つを立ち上げる

Container 1, Continer 2 を立ち上げます。実行するプロセスは sleep 1000000

$ docker run -d --name container1 alpine sleep 1000000
$ docker run -d --name container2 alpine sleep 1000000

ちゃんと動いてるか確認します。

$ docker ps

CONTAINER ID     IMAGE     COMMAND           CREATED           STATUS          PORTS   NAMES
ac2ece448844     alpine    "sleep 1000000"   5 seconds ago     Up 4 seconds            container2
e1147e5ec006     alpine    "sleep 1000000"   14 seconds ago    Up 13 seconds           container1

ホストのネットワークを見てみる

ホスト側のネットワークを見てみます。↑図と大体同じような感じになっています。

$ ifconfig

# "veth0000001", "veth0000002" のブリッジ
docker0   Link encap:Ethernet  HWaddr 02:42:DE:AF:0E:4C  
          inet addr:172.17.0.1  Bcast:0.0.0.0  Mask:255.255.0.0
          inet6 addr: fe80::42:deff:feaf:e4c/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:28 errors:0 dropped:0 overruns:0 frame:0
          TX packets:14 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:1744 (1.7 KiB)  TX bytes:1068 (1.0 KiB)

eth0      Link encap:Ethernet  HWaddr 06:AC:37:4A:1A:AD  
          inet addr:172.30.1.211  Bcast:172.30.1.255  Mask:255.255.255.0
          inet6 addr: fe80::4ac:37ff:fe4a:1aad/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:9001  Metric:1
          RX packets:45727 errors:0 dropped:0 overruns:0 frame:0
          TX packets:22649 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:63486801 (60.5 MiB)  TX bytes:1659723 (1.5 MiB)

...

# 図中の "veth0000001" に該当
veth2b8058a Link encap:Ethernet  HWaddr F2:BD:7F:6A:C2:88  
          inet6 addr: fe80::f0bd:7fff:fe6a:c288/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:14 errors:0 dropped:0 overruns:0 frame:0
          TX packets:42 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:1068 (1.0 KiB)  TX bytes:3204 (3.1 KiB)

# 図中の "veth0000002" に該当
vethd2804f4 Link encap:Ethernet  HWaddr B6:2C:76:4A:0B:DD  
          inet6 addr: fe80::b42c:76ff:fe4a:bdd/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:14 errors:0 dropped:0 overruns:0 frame:0
          TX packets:28 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:1068 (1.0 KiB)  TX bytes:2048 (2.0 KiB)

ホストの routing table はこう↓です。

$ route -n

Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         172.30.1.1      0.0.0.0         UG    0      0        0 eth0
169.254.169.254 0.0.0.0         255.255.255.255 UH    0      0        0 eth0    # これはEC2 metadata用.
172.17.0.0      0.0.0.0         255.255.0.0     U     0      0        0 docker0
172.30.1.0      0.0.0.0         255.255.255.0   U     0      0        0 eth0

ホストのブリッジ情報を表示してみます。docker0 ブリッジにvethが2つ接続されています。それぞれのvethの先に Container 1, Container 2 のネットワーク名前空間があります。

$ brctl show

bridge name   bridge id           STP enabled   interfaces
docker0       8000.0242deaf0e4c   no            veth2b8058a
                                                vethd2804f4

コンテナの名前空間を見てみる

Dockerはプロセスの実行環境をホストOSや他コンテナと分離をするサービスです。Linuxの ネットワーク名前空間 / マウント名前空間 / PID名前空間 / etc... 機能を利用して実現しています。

各コンテナの名前空間を探す為に、まずホスト側からコンテナプロセスのPIDを探します。 PID 3100, 3211 がそれですね。

$ ps auxf

USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
...
root      2810  0.0  4.1 435916 42528 pts/0    Sl   03:31   0:01 /usr/bin/dockerd --default-ulimit nofile=1024:4096
root      2816  0.0  0.9 228760  9912 ?        Ssl  03:31   0:00  \_ docker-containerd -l unix:///var/run/docker/libcontainerd/...
root      3084  0.0  0.2 135792  2568 ?        Sl   03:40   0:00      \_ docker-containerd-shim ... /var/run/docker/libcontainerd/...
root      3100  0.0  0.0   1524     4 ?        Ss   03:40   0:00      |   \_ sleep 1000000
root      3188  0.0  0.2 201328  2504 ?        Sl   03:40   0:00      \_ docker-containerd-shim ... /var/run/docker/libcontainerd/...
root      3211  0.0  0.0   1524     4 ?        Ss   03:40   0:00          \_ sleep 1000000

この PID=3100 sleep 1000000 プロセスが実行されている名前空間は↓で確認できます。このうち net がネットワーク名前空間になります。

$ sudo ls -l /proc/3100/ns/

total 0
lrwxrwxrwx 1 root root 0 Jul 23 04:08 cgroup -> cgroup:[4026531835]
lrwxrwxrwx 1 root root 0 Jul 23 04:08 ipc -> ipc:[4026532159]
lrwxrwxrwx 1 root root 0 Jul 23 04:08 mnt -> mnt:[4026532157]
lrwxrwxrwx 1 root root 0 Jul 23 03:40 net -> net:[4026532162]
lrwxrwxrwx 1 root root 0 Jul 23 04:08 pid -> pid:[4026532160]
lrwxrwxrwx 1 root root 0 Jul 23 04:08 user -> user:[4026531837]
lrwxrwxrwx 1 root root 0 Jul 23 04:08 uts -> uts:[4026532158]

コンテナのネットワークを見てみる

次に ip コマンドを使って、コンテナのネットワーク名前空間上で bash プロセスを立ち上げてみます。

ip コマンドは /var/run/netns/ 以下のネットワーク名前空間しか扱えないので、まずはシンボリックリンクを貼ってやります。

$ sudo mkdir -p /var/run/netns/
$ sudo ln -s /proc/3100/ns/net /var/run/netns/container1

ネットワーク名前空間 container1 上で bash プロセスを立ち上げます。

$ ip netns exec container1 bash

root#

"$ ip netns exec {ネットワーク名前空間名} {実行したいコマンド}"

コンテナ側のネットワークを盗み見る事ができました。

root# ifconfig

eth0      Link encap:Ethernet  HWaddr 02:42:AC:11:00:02  
          inet addr:172.17.0.2  Bcast:0.0.0.0  Mask:255.255.0.0
          inet6 addr: fe80::42:acff:fe11:2/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:45 errors:0 dropped:0 overruns:0 frame:0
          TX packets:15 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:3414 (3.3 KiB)  TX bytes:1138 (1.1 KiB)

...

コンテナの routing table も見てみます。

root# route -n

Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         172.17.0.1      0.0.0.0         UG    0      0        0 eth0
172.17.0.0      0.0.0.0         255.255.0.0     U     0      0        0 eth0

コンテナにNICを手動で追加してみる

図にするとこんな感じです

2nic.png

準備

まず、 Container 2 は邪魔なので落としておきます

$ docker stop container2
$ docker rm container2

Container 2 のNICへのブリッジも自動で削除されています。

$ brctl show

bridge name   bridge id           STP enabled   interfaces
docker0       8000.0242deaf0e4c   no            veth2b8058a

veth (Virtual Ethernet) を追加する

veth (1ケーブルで接続済の仮想NICのペア) を追加します。ホスト側のブリッジ docker0 と接続する方を veth-host, コンテナ側を veth-con とします。

$ ip link add name veth-host type veth peer name veth-con
$ ip link set veth-host up

ホスト側NIC veth-host をブリッジ docker0 に接続します。

$ brctl addif docker0 veth-host
$ brctl show

bridge name   bridge id           STP enabled   interfaces
docker0       8000.0242deaf0e4c   no            veth2b8058a
                                                veth-host

この時はまだ veth-host, veth-con 共にホスト側のネットワーク名前空間に属している為、ホスト側から両方とも見えます。

$ ifconfig veth-host

veth-host Link encap:Ethernet  HWaddr 3A:D3:41:66:58:F8  
          UP BROADCAST MULTICAST  MTU:1500  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:0 (0.0 b)  TX bytes:0 (0.0 b)

$ ifconfig veth-con

veth-con Link encap:Ethernet  HWaddr 5E:98:45:07:48:00  
          BROADCAST MULTICAST  MTU:1500  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:0 (0.0 b)  TX bytes:0 (0.0 b)

コンテナ側NIC veth-con のネットワーク名前空間を container1 に変更します。

$ ip link set veth-con netns container1

ホスト側からは見えなくなります。

$ ifconfig veth-con

veth-con: error fetching interface information: Device not found

逆にコンテナ側は見える様になります。

$ ip netns exec container1 ifconfig veth-con

veth-con  Link encap:Ethernet  HWaddr B2:45:A8:96:1B:AA  
          BROADCAST MULTICAST  MTU:1500  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:0 (0.0 b)  TX bytes:0 (0.0 b)

コンテナ側NICの設定

まずはNIC名を veth-coneth1 に変えてやります。

$ ip netns exec container1 ip link set veth-con name eth1

"$ ip netns exec container1 ..." → コンテナ側 (netns) でコマンド実行している

NIC eth1 にIP 172.17.0.99/24 を割り当てます。

$ ip netns exec container1 ip addr add 172.17.0.99/24 dev eth1
$ ip netns exec container1 ip link set eth1 up

コンテナ側からIPが見れる様になります。

$ ip netns exec container1 ifconfig eth1

eth1      Link encap:Ethernet  HWaddr B2:45:A8:96:1B:AA  
          inet addr:172.17.0.99  Bcast:0.0.0.0  Mask:255.255.255.0
          inet6 addr: fe80::b045:a8ff:fe96:1baa/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:5714 errors:0 dropped:0 overruns:0 frame:0
          TX packets:4448 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:121496019 (115.8 MiB)  TX bytes:309958 (302.6 KiB)

コンテナ側 routing table の変更

せっかく追加したNIC eth1 が全く使われていないので、routing table を変更してやります。

$ ip netns exec container1 ip route delete default
$ ip netns exec container1 ip route add default via 172.17.0.1 dev eth1

この通り、外部アクセスが新規追加したNIC eth1 経由となりました。

$ ip netns exec container1 route -n

Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         172.17.0.1      0.0.0.0         UG    0      0        0 eth1
172.17.0.0      0.0.0.0         255.255.255.0   U     0      0        0 eth1
172.17.0.0      0.0.0.0         255.255.0.0     U     0      0        0 eth0

eth0 で入って来たのが eth1 から出てしまいますが、今回は無視します

コンテナに侵入して確認してみる

実際にコンテナに侵入して、意図したとおりに動いているか見てみます。

$ docker exec -it container1 sh

/ # ps aux
PID   USER     TIME   COMMAND
    1 root       0:00 sleep 1000000
    5 root       0:00 sh
   10 root       0:00 ps aux

元からあった eth0 (172.17.0.2) と、追加した eth1 (172.17.0.99) が見えます。

# ifconfig

eth0      Link encap:Ethernet  HWaddr 02:42:AC:11:00:02  
          inet addr:172.17.0.2  Bcast:0.0.0.0  Mask:255.255.0.0
          inet6 addr: fe80::42:acff:fe11:2/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:2040 errors:0 dropped:0 overruns:0 frame:0
          TX packets:1320 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:48591073 (46.3 MiB)  TX bytes:97477 (95.1 KiB)

eth1      Link encap:Ethernet  HWaddr B2:45:A8:96:1B:AA  
          inet addr:172.17.0.99  Bcast:0.0.0.0  Mask:255.255.255.0
          inet6 addr: fe80::b045:a8ff:fe96:1baa/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:5714 errors:0 dropped:0 overruns:0 frame:0
          TX packets:4448 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:121496019 (115.8 MiB)  TX bytes:309958 (302.6 KiB)
...

routing table も先程設定したとおりです。

# route -n

Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         172.17.0.1      0.0.0.0         UG    0      0        0 eth1
172.17.0.0      0.0.0.0         255.255.255.0   U     0      0        0 eth1
172.17.0.0      0.0.0.0         255.255.0.0     U     0      0        0 eth0

curl をインストールしてみます。

apkAlpine Linux のパッケージ管理システム

/ # apk update

fetch http://dl-cdn.alpinelinux.org/alpine/v3.6/main/x86_64/APKINDEX.tar.gz
fetch http://dl-cdn.alpinelinux.org/alpine/v3.6/community/x86_64/APKINDEX.tar.gz
v3.6.2-40-gf1c202674f [http://dl-cdn.alpinelinux.org/alpine/v3.6/main]
v3.6.2-32-g6f53cfcccd [http://dl-cdn.alpinelinux.org/alpine/v3.6/community]
OK: 8436 distinct packages available

/ # apk add curl

(1/3) Installing libssh2 (1.8.0-r1)
(2/3) Installing libcurl (7.54.0-r0)
(3/3) Installing curl (7.54.0-r0)
Executing busybox-1.26.2-r5.trigger
OK: 231 MiB in 41 packages

google.com にアクセスしてみます。

/ # curl google.com

<HTML><HEAD><meta http-equiv="content-type" content="text/html;charset=utf-8">
<TITLE>302 Moved</TITLE></HEAD><BODY>
<H1>302 Moved</H1>
The document has moved
<A HREF="http://www.google.co.jp/?gfe_rd=cr&amp;ei=3UN0WduOBrGL8QfG9JGIBQ">here</A>.
</BODY></HTML>
11
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
11
7