Docker: Docker Networking

Somprasong Damyos
6 min readFeb 14, 2017

--

ในบทความนี้จะอธิบายว่า Docker networks มีกี่ประเภท แต่ละประเภทต่างกันอย่างไร และมีวิธีการที่จะสร้าง network ขึ้นมาเอง รวมถึงวิธีการที่จะใช้งานมันด้วย

Default Networks

เมื่อเราติดตั้ง Docker นั้น Docker จะสร้าง default networks ขึ้นมาให้เรา 3 ตัวด้วยกัน ซึ่งดูได้จากคำสั่ง docker network ls

$ docker network ls

NETWORK ID NAME DRIVER
7fca4eb8c647 bridge bridge
9f904ee27bf5 none null
cf03ee007fb4 host host

ซึ่งสามารถดูรายละเอียดของแต่ละ network โดยใช้คำสั่ง docker network inspect <network>

ส่วนวิธีการว่าเราจะเลือกใช้งาน network ตัวไหนนั้น ให้ใส่ --network=<NETWORK> option ตอนที่สั่งรัน image แต่ถ้าไม่ระบุ Docker daemon จะเลือกให้เป็น bridge network (docker0) โดยอัตโนมัติ

แล้ว Docker Networks มีกี่ประเภท ?

Docker Networks มีอยู่ 4 ประเภท

  • Closed Network/None Network
  • Host Network
  • Bridge Network
  • Overlay Network

None Network

จะเป็น network แบบปิด คือไม่ต้องการเชื่อมต่อ Internet และไม่สามารถ network access จาก Host ได้ ดังนั้น none network จึงถือว่ามี network security สูงสุด เพราะมี network แค่ตัวเดียว คือ Loopback interface

$ docker run -itd --network=none busybox
ec233bf230eb4655dfab2cd8f6852d78bba6ef8fe1592a2ae0a74e23264dd924
$ docker exec -it ec23 /bin/ash
/ # ping 8.8.8.8
PING 8.8.8.8 (8.8.8.8): 56 data bytes
ping: sendto: Network is unreachable
/ # ifconfig
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
inet6 addr: ::1/128 Scope:Host
UP LOOPBACK RUNNING MTU:65536 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:1
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)

Host Network

ถ้าจัดระดับความปลอดภัยในการเข้าถึง container จัดได้ว่า host network นี้มีความปลอดภัยน้อยที่สุด เพราะ container จะรันอยู่บน host network เลย ซึ่งสามารถ full access ได้จาก host interface ดังนั้นจะเรียก containers พวกนี้ว่า open containers

$ docker run --rm -it --network=host busybox ifconfig
docker0 Link encap:Ethernet HWaddr 02:42:C4:C9:61:42
inet addr:172.17.0.1 Bcast:0.0.0.0 Mask:255.255.0.0
inet6 addr: fe80::42:c4ff:fec9:6142/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:113 errors:0 dropped:0 overruns:0 frame:0
TX packets:18 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:7416 (7.2 KiB) TX bytes:1356 (1.3 KiB)
eth0 Link encap:Ethernet HWaddr 08:00:27:73:7C:6D
inet addr:10.0.2.15 Bcast:10.0.2.255 Mask:255.255.255.0
inet6 addr: fe80::a00:27ff:fe73:7c6d/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:58460 errors:0 dropped:0 overruns:0 frame:0
TX packets:23042 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:53728571 (51.2 MiB) TX bytes:1506684 (1.4 MiB)
eth1 Link encap:Ethernet HWaddr 08:00:27:71:17:74
inet addr:192.168.99.100 Bcast:192.168.99.255 Mask:255.255.255.0
inet6 addr: fe80::a00:27ff:fe71:1774/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:6303 errors:0 dropped:0 overruns:0 frame:0
TX packets:4813 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:1028416 (1004.3 KiB) TX bytes:3894599 (3.7 MiB)
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
inet6 addr: ::1/128 Scope:Host
UP LOOPBACK RUNNING MTU:65536 Metric:1
RX packets:32 errors:0 dropped:0 overruns:0 frame:0
TX packets:32 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1
RX bytes:2752 (2.6 KiB) TX bytes:2752 (2.6 KiB)
veth70f3840 Link encap:Ethernet HWaddr 7E:22:90:EF:4C:4C
inet6 addr: fe80::7c22:90ff:feef:4c4c/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:15 errors:0 dropped:0 overruns:0 frame:0
TX packets:19 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:1222 (1.1 KiB) TX bytes:1502 (1.4 KiB)
vethaa3a7cd Link encap:Ethernet HWaddr 36:55:95:9B:A0:72
inet6 addr: fe80::3455:95ff:fe9b:a072/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:23 errors:0 dropped:0 overruns:0 frame:0
TX packets:31 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:1894 (1.8 KiB) TX bytes:2542 (2.4 KiB)

Bridge Network

เป็น default network ของ Docker สามารถ access จาก host ได้ และใช้งาน Internet จากภายใน container ได้ ลองใช้คำสั่ง docker network inspect เพื่อดูข้อมูลของ bridge network

$ docker network inspect bridge
[
{
"Name": "bridge",
"Id": "fab9cf679aff5ac735833dfa6ebacafc26eddb81e357d6edd3d2491991504559",
"Created": "2017-02-14T02:19:46.404729004Z",
"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,
"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": {}
}
]

Docker Engine จะสร้าง Subnet และ Gateway ของ network นี้ให้อัตโนมัติ ซึ่งเมื่อรัน image แบบปกติ container ที่ถูกสร้างใหม่นั้นจะถูกกำหนดให้อยู่ใน network โดยอัตโนมัติ

$ docker run -itd --name container1 busybox
8f51ff057a7fea23b4883b5a8b5f244beae0e265b7545e2729494cedbd88190e
$ docker run -itd --name container2 busybox
a5ebfe085f9f8c3a7d1fd752bdf6f66292606edded26ad6a5a194f043e65e165
$ docker network inspect bridge
[
{
"Name": "bridge",
...
"Containers": {
"8f51ff057a7fea23b4883b5a8b5f244beae0e265b7545e2729494cedbd88190e": {
"Name": "container1",
"EndpointID": "6a9c47ff9792dbb75e91468ff94042a0aae89dc61f7fcff4218cf51771fc8720",
"MacAddress": "02:42:ac:11:00:02",
"IPv4Address": "172.17.0.2/16",
"IPv6Address": ""
},
"a5ebfe085f9f8c3a7d1fd752bdf6f66292606edded26ad6a5a194f043e65e165": {
"Name": "container2",
"EndpointID": "3e5dd60a3b14a4c7c2a32eaeb7dfa1b3951739203e2128ce7e01dcc7a4aae57d",
"MacAddress": "02:42:ac:11:00:03",
"IPv4Address": "172.17.0.3/16",
"IPv6Address": ""
}
},
...
}
]

จากตัวอย่างข้างบน เมื่อลอง docker network inspect ดูจะพบว่า ทั้ง 2 containers จะอยู่ใน bridge network และกำหนด IP address (172.17.0.0 ถึง 172.17.255.255)ให้อัตโนมัติ

ซึ่งถ้าดูภายใน container แต่ละตัว จะมีอยู่ 2 network interfaces คือ loopback interface (lo) และ private interface (eth0)

$ docker exec -it container1 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:24 errors:0 dropped:0 overruns:0 frame:0
TX packets:16 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:1968 (1.9 KiB) TX bytes:1320 (1.2 KiB)
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
inet6 addr: ::1/128 Scope:Host
UP LOOPBACK RUNNING MTU:65536 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:1
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)

และทั้ง 2 containers สามารถสื่อสารหากันได้ผ่านทาง IP address แต่ถ้าต้องการอ้างอิงโดยใช้ชื่อของ container จะต้องใช้ docker run --link option ทำให้รู้จักชื่อกันก่อน แต่ถ้า containers อยู่คนละ bridge network กัน โดย default จะไม่สามารถเชื่อมต่อหากันได้

$ docker exec -it container2 ping -c 5 172.17.0.2
PING 172.17.0.2 (172.17.0.2): 56 data bytes
64 bytes from 172.17.0.2: seq=0 ttl=64 time=0.111 ms
64 bytes from 172.17.0.2: seq=1 ttl=64 time=0.096 ms
64 bytes from 172.17.0.2: seq=2 ttl=64 time=0.088 ms
64 bytes from 172.17.0.2: seq=3 ttl=64 time=0.095 ms
64 bytes from 172.17.0.2: seq=4 ttl=64 time=0.088 ms
--- 172.17.0.2 ping statistics ---
5 packets transmitted, 5 packets received, 0% packet loss
round-trip min/avg/max = 0.088/0.095/0.111 ms

สรุปแล้ว Bridge network นี้เหมาะสำหรับการสร้าง network เล็กๆ ที่อยู่บน host ตัวเดียวกัน แต่ถ้าต้องการระบบ network ที่ใหญ่กว่านี้ต้องใช้ Overlay network แทน

วิธีการสร้าง Network เอง

ใน Docker เราสามารถสร้าง network ขึ้นมาใช้งานเองได้นอกเหนือจาก default network โดยใช้คำสั่ง docker network create --driver <driver name> <new network name>ในตัวอย่างนี้จะแสดงการสร้าง bridge network ซึ่ง network ที่ได้จะเหมือนกับ default bridge network เลย

$ docker network create --driver bridge my_bridge_network
ca4b288edb119528a6af4d74f68098ec4449ff90fdcf817cd55f23dd2bbebb75
$ docker network list
NETWORK ID NAME DRIVER SCOPE
fab9cf679aff bridge bridge local
f12a3eb75802 host host local
ca4b288edb11 my_bridge_network bridge local
b93d2d4a546b none null local

ส่วนการใช้งานก็ใช้คำสั่ง docker run --network=<network name>

$ docker run --network=my_bridge_network -itd --name container3 busybox
c3aad8eb0bbdb347cdd172f3caaa860d718930f57b75d67df715880b281d2969
$ docker network inspect my_bridge_network
[
{
"Name": "my_bridge_network",
"Id": "ca4b288edb119528a6af4d74f68098ec4449ff90fdcf817cd55f23dd2bbebb75",
"Created": "2017-02-14T10:26:11.807052192Z",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": {},
"Config": [
{
"Subnet": "172.18.0.0/16",
"Gateway": "172.18.0.1"
}
]
},
"Internal": false,
"Attachable": false,
"Containers": {
"c3aad8eb0bbdb347cdd172f3caaa860d718930f57b75d67df715880b281d2969": {
"Name": "container3",
"EndpointID": "252399f3c29080ee999ba5ba9ca7acc021142c8ae6e2fefaf36c449998b4a7a2",
"MacAddress": "02:42:ac:12:00:02",
"IPv4Address": "172.18.0.2/16",
"IPv6Address": ""
}
},
"Options": {},
"Labels": {}
}
]

ลอง ping จาก container3 ไปหา container1 (ip: 172.17.0.2) ที่อยู่ใน default bridge network จะพบว่าไม่สามารถเชื่อมต่อกันได้

$ docker exec -it container3 ping -c 5 172.17.0.2
PING 172.17.0.2 (172.17.0.2): 56 data bytes
--- 172.17.0.2 ping statistics ---
5 packets transmitted, 0 packets received, 100% packet loss

แต่ใน Docker มี feature ที่อนุญาตให้ container เชื่อมต่อไปอีก network นึงได้ ผ่านคำสั่ง docker network connect

$ docker network connect bridge container3$ docker exec -it container3 ifconfig
eth0 Link encap:Ethernet HWaddr 02:42:AC:12:00:02
inet addr:172.18.0.2 Bcast:0.0.0.0 Mask:255.255.0.0
inet6 addr: fe80::42:acff:fe12:2/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:17 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:1338 (1.3 KiB) TX bytes:2552 (2.4 KiB)
eth1 Link encap:Ethernet HWaddr 02:42:AC:11:00:04
inet addr:172.17.0.4 Bcast:0.0.0.0 Mask:255.255.0.0
inet6 addr: fe80::42:acff:fe11:4/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:8 errors:0 dropped:0 overruns:0 frame:0
TX packets:8 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:648 (648.0 B) TX bytes:648 (648.0 B)
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
inet6 addr: ::1/128 Scope:Host
UP LOOPBACK RUNNING MTU:65536 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:1
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)

จะพบว่า มี eth1 interface เพิ่มขึ้นมาซึ่งจะได้ IP address จาก default bridge network และเมื่อลอง ping หากันใหม่ก็จะได้แล้ว

$ docker exec -it container3 ping -c 5 172.17.0.2
PING 172.17.0.2 (172.17.0.2): 56 data bytes
64 bytes from 172.17.0.2: seq=0 ttl=64 time=0.164 ms
64 bytes from 172.17.0.2: seq=1 ttl=64 time=0.085 ms
64 bytes from 172.17.0.2: seq=2 ttl=64 time=0.119 ms
64 bytes from 172.17.0.2: seq=3 ttl=64 time=0.089 ms
64 bytes from 172.17.0.2: seq=4 ttl=64 time=0.085 ms
--- 172.17.0.2 ping statistics ---
5 packets transmitted, 5 packets received, 0% packet loss
round-trip min/avg/max = 0.085/0.108/0.164 ms

สุดท้ายถ้าไม่ต้องการเชื่อมต่อ container3 กับ default bridge network ก็ใช้คำสั่ง docker network disconnect จะเห็นว่า eth1 interface จะหายไป

$ docker network disconnect bridge container3$ docker exec -it container3 ifconfig
eth0 Link encap:Ethernet HWaddr 02:42:AC:12:00:02
inet addr:172.18.0.2 Bcast:0.0.0.0 Mask:255.255.0.0
inet6 addr: fe80::42:acff:fe12:2/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:17 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:1338 (1.3 KiB) TX bytes:2552 (2.4 KiB)
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
inet6 addr: ::1/128 Scope:Host
UP LOOPBACK RUNNING MTU:65536 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:1
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)

สรุป

Docker networks แต่ละแบบนั้นก็เหมาะกับงานคนละแบบ เช่นถ้ากังวลเรื่องความปลอดภัย และไม่ต้องการเชื่อมต่อกับ network ก็ใช้ none network หรือถ้าไม่สนใจอยากเปิดให้เข้าได้หมดก็ใช้ host network หรือว่าต้องการความปลอดด้วย สามารถเข้าถึงได้จากภายนอกด้วยก็ใช้ bridge network แล้วค่อยเปิด port ที่ต้องการใช้ออกไป ดังนั้นเราต้องเป็นคนตัดสินใจเลือกเองว่า network แบบไหน ถึงจะเหมาะกับโปรเจคของเรามากที่สุด

--

--