1. 程式人生 > >docker-網絡基礎

docker-網絡基礎

sed tin scope 進程 inet6 define server eth tcp

網絡

Docker 網絡從覆蓋範圍可分為單個 host 上的容器網絡和跨多個 host 的網絡

Docker 安裝時會自動在 host 上創建三個網絡,

 ? root@bogon  /home  docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
4232d0b89e85        bridge              bridge              local
90b3cebedfb6        host                host                local
c1a576af27d2        none                null                local
 ? root@bogon  /home  

none 網絡

掛在這個網絡下的容器除了 lo,沒有其他任何網卡。容器創建時,可以通過?--network=none?指定使用 none 網絡。

 ? root@bogon  /home  docker run -it --network=none busybox
Unable to find image 'busybox:latest' locally
Trying to pull repository docker.io/library/busybox ... 
latest: Pulling from docker.io/library/busybox
8c5a7da1afbc: Pull complete 
Digest: sha256:cb63aa0641a885f54de20f61d152187419e8f6b159ed11a251a09d115fdff9bd
Status: Downloaded newer image for docker.io/busybox:latest
/ # 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)

/ # 

一些對安全性要求高並且不需要聯網的應用可以使用 none 網絡。

host 網絡

連接到 host 網絡的容器共享 Docker host 的網絡棧,容器的網絡配置與 host 完全一樣。可以通過?--network=host?指定使用 host 網絡

 ? ? root@bogon  /home  docker run -it --network=host busybox
/ # ip l
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast qlen 1000
    link/ether 00:0c:29:0f:09:89 brd ff:ff:ff:ff:ff:ff
3: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue 
    link/ether 02:42:66:21:3f:9d brd ff:ff:ff:ff:ff:ff
21: veth3e15456@if20: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue master docker0 
    link/ether c2:02:4f:c0:9e:5d brd ff:ff:ff:ff:ff:ff
27: vethed6909e@if26: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue master docker0 
    link/ether f2:56:d6:65:38:18 brd ff:ff:ff:ff:ff:ff

在容器中可以看到 host 的所有網卡,並且連 hostname 也是 host 的

直接使用 Docker host 的網絡最大的好處就是性能,如果容器對網絡傳輸效率有較高要求,則可以選擇 host 網絡。

bridge 網絡

Docker 安裝時會創建一個 命名為?docker0?的 linux bridge。如果不指定--network,創建的容器默認都會掛到?docker0?上

 ? root@bogon  /home  brctl  show
bridge name bridge id       STP enabled interfaces
docker0     8000.024266213f9d   no      veth3e15456
                                      vethed6909e

其中veth3e15456 vethed6909e就是創建容器的虛擬網卡。

容器裏的配置

? root@bogon  /home  docker exec -it 6b9f16f7de01 bash
root@6b9f16f7de01:/usr/local/apache2# ip a
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
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
28: eth0@if29: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group defau
    link/ether 02:42:ac:11:00:04 brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.4/16 scope global eth0
       valid_lft forever preferred_lft forever
    inet6 fe80::42:acff:fe11:4/64 scope link 
       valid_lft forever preferred_lft forever
root@6b9f16f7de01:/usr/local/apache2# 

? vethed6909e和eth0@if29是一對veth pair。veth pair 是一種成對出現的特殊網絡設備, 想象成由一根虛擬網線連接起來的一對網卡,網卡的一頭(eth0@if34)在容器中,另一頭(veth28c57df)掛在網橋?docker0?上,其效果就是將?eth0@if34?也掛在了?docker0?上

eth0@if29?已經配置了 IP?172.17.0.4

通過?docker network inspect bridge?看一下 bridge 網絡的配置信息:

技術分享圖片

?bridge 網絡配置的 subnet 就是 172.17.0.0/16,並且網關是 172.17.0.1。

技術分享圖片容器創建時,docker 會自動從 172.17.0.0/16 中分配一個 IP,這裏 16 位的掩碼保證有足夠多的 IP 可以供容器使用

user-defined 網絡

1.創建

 ? ? root@bogon  ~  docker network create --driver bridge my_net
57fd498eab6a3202f2bac97ad91f6770dae73b9c3690b5a1a72c100ef5f9a060

創建一個user-defind 網絡

新增了一個網橋?br-57fd498eab6a,這裏?57fd498eab6a?正好新建 bridge 網絡?my_net?的短 id。

 ? root@bogon  ~  brctl show
bridge name bridge id       STP enabled interfaces
br-57fd498eab6a     8000.0242b1c813c6   no      
docker0     8000.024266213f9d   no      veth3e15456
                            vethb35268d
                            vethed6909e 

執行?docker network inspect?查看一下?my_net?的配置信息:

 ? root@bogon  ~  docker network inspect my_net 
[
    {
        "Name": "my_net",
        "Id": "57fd498eab6a3202f2bac97ad91f6770dae73b9c3690b5a1a72c100ef5f9a060",
        "Created": "2018-08-05T11:47:52.338929045-04:00",
        "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": {},
        "Options": {},
        "Labels": {}
    }
]

另外指定 子網和網關創建,如下

docker network create --driver bridge --subnet 192.168.0.0/24 --gateway 192.168.0.10 my_net2

2.使用

容器要使用新的網絡,需要在啟動時通過?--network?指定

? root@bogon  ~  docker run -it --network=my_net2 busybox
/ # ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue 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
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
32: eth0@if33: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue 
    link/ether 02:42:c0:a8:00:01 brd ff:ff:ff:ff:ff:ff
    inet 192.168.0.1/24 scope global eth0
       valid_lft forever preferred_lft forever
    inet6 fe80::42:c0ff:fea8:1/64 scope link 
       valid_lft forever preferred_lft forever

指定子網創建

docker run -it --network=my_net2 --ip 192.168.0.100 busybox

只有使用?--subnet?創建的網絡才能指定靜態 IP

容器之間的連通性

1.查看路由

 ? root@bogon  ~  ip r
default via 192.168.246.2 dev ens33 proto static metric 100 
172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1 
172.18.0.0/16 dev br-57fd498eab6a proto kernel scope link src 172.18.0.1 
192.168.0.0/24 dev br-7119530cd62a proto kernel scope link src 192.168.0.10 
192.168.246.0/24 dev ens33 proto kernel scope link src 192.168.246.138 

2.查看防火墻

 ? root@bogon  ~  iptables-save     
# Generated by iptables-save v1.4.21 on Sun Aug  5 12:22:14 2018
*nat
:PREROUTING ACCEPT [7:1070]
:INPUT ACCEPT [7:1070]
:OUTPUT ACCEPT [94:7140]
:POSTROUTING ACCEPT [94:7140]
: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 192.168.0.0/24 ! -o br-7119530cd62a -j MASQUERADE
-A POSTROUTING -s 172.18.0.0/16 ! -o br-57fd498eab6a -j MASQUERADE
-A POSTROUTING -s 172.17.0.0/16 ! -o docker0 -j MASQUERADE
-A DOCKER -i br-7119530cd62a -j RETURN
-A DOCKER -i br-57fd498eab6a -j RETURN
-A DOCKER -i docker0 -j RETURN
COMMIT
# Completed on Sun Aug  5 12:22:14 2018
# Generated by iptables-save v1.4.21 on Sun Aug  5 12:22:14 2018
*filter
:INPUT ACCEPT [1124:81571]
:FORWARD DROP [0:0]
:OUTPUT ACCEPT [746:87877]
:DOCKER - [0:0]
:DOCKER-ISOLATION - [0:0]
-A FORWARD -j DOCKER-ISOLATION
-A FORWARD -o br-7119530cd62a -j DOCKER
-A FORWARD -o br-7119530cd62a -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -i br-7119530cd62a ! -o br-7119530cd62a -j ACCEPT
-A FORWARD -i br-7119530cd62a -o br-7119530cd62a -j ACCEPT
-A FORWARD -o br-57fd498eab6a -j DOCKER
-A FORWARD -o br-57fd498eab6a -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -i br-57fd498eab6a ! -o br-57fd498eab6a -j ACCEPT
-A FORWARD -i br-57fd498eab6a -o br-57fd498eab6a -j ACCEPT
-A FORWARD -o docker0 -j DOCKER
-A FORWARD -o docker0 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -i docker0 ! -o docker0 -j ACCEPT
-A FORWARD -i docker0 -o docker0 -j ACCEPT
-A DOCKER-ISOLATION -i br-57fd498eab6a -o br-7119530cd62a -j DROP
-A DOCKER-ISOLATION -i br-7119530cd62a -o br-57fd498eab6a -j DROP
-A DOCKER-ISOLATION -i docker0 -o br-7119530cd62a -j DROP
-A DOCKER-ISOLATION -i br-7119530cd62a -o docker0 -j DROP
-A DOCKER-ISOLATION -i docker0 -o br-57fd498eab6a -j DROP
-A DOCKER-ISOLATION -i br-57fd498eab6a -o docker0 -j DROP
-A DOCKER-ISOLATION -j RETURN
COMMIT
# Completed on Sun Aug  5 12:22:14 2018

可以看到

-A DOCKER-ISOLATION -i docker0 -o br-7119530cd62a -j DROP
-A DOCKER-ISOLATION -i br-7119530cd62a -o docker0 -j DROP
-A DOCKER-ISOLATION -i docker0 -o br-57fd498eab6a -j DROP
-A DOCKER-ISOLATION -i br-57fd498eab6a -o docker0 -j DROP

實現網絡的隔離

3.docker連接網絡

docker network connect my_net2 6b9f16f7de01
? ? root@bogon  ~  docker exec -it  amazing_lovelace bash
root@6b9f16f7de01:/usr/local/apache2# ip a
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
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
28: eth0@if29: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
    link/ether 02:42:ac:11:00:04 brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.4/16 scope global eth0
       valid_lft forever preferred_lft forever
    inet6 fe80::42:acff:fe11:4/64 scope link 
       valid_lft forever preferred_lft forever
40: eth1@if41: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
    link/ether 02:42:c0:a8:00:01 brd ff:ff:ff:ff:ff:ff
    inet 192.168.0.1/24 scope global eth1
       valid_lft forever preferred_lft forever
    inet6 fe80::42:c0ff:fea8:1/64 scope link 
       valid_lft forever preferred_lft forever

容器之間可通過 IP,Docker DNS Server 或 joined 容器三種方式通信。

1.IP通信

如上一節

2.Docker DNS Server通信

啟動時用?--name?為容器命名

只能在 user-defined 網絡中使用。也就是說,默認的 bridge 網絡是無法使用 DNS 的

示例:

docker run -it --network=my_net2 --name=bbox1 busybox

docker run -it --network=my_net2 --name=bbox2 busybox

/ # ping bbox1
PING bbox1 (192.168.0.2): 56 data bytes
64 bytes from 192.168.0.2: seq=0 ttl=64 time=0.062 ms
64 bytes from 192.168.0.2: seq=1 ttl=64 time=0.068 ms

3.joined 通信

可以使兩個或多個容器共享一個網絡棧,共享網卡和配置信息,joined 容器之間可以通過 127.0.0.1 直接通信。

1,創建一個http的容器

docker run -it --name web1 httpd

2.創建一個容器使用web1 的網絡

docker run -it --network=container:web1 busybox

然後發現 web1的網絡和busybox的網絡完全一致

busybox 可以直接用 127.0.0.1 訪問 web1 的 http 服務

容器訪問外部

技術分享圖片

1.查看主機路由

 ? ? root@bogon  ~  ip r 
default via 192.168.246.2 dev ens33 proto static metric 100 
172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1 
172.18.0.0/16 dev br-57fd498eab6a proto kernel scope link src 172.18.0.1 
192.168.0.0/24 dev br-7119530cd62a proto kernel scope link src 192.168.0.10 
192.168.246.0/24 dev ens33 proto kernel scope link src 192.168.246.138 

2.查看nat表

 ? ? root@bogon  ~  iptables -t nat -S
-P PREROUTING ACCEPT
-P INPUT ACCEPT
-P OUTPUT ACCEPT
-P POSTROUTING ACCEPT
-N DOCKER
-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 192.168.0.0/24 ! -o br-7119530cd62a -j MASQUERADE
-A POSTROUTING -s 172.18.0.0/16 ! -o br-57fd498eab6a -j MASQUERADE
-A POSTROUTING -s 172.17.0.0/16 ! -o docker0 -j MASQUERADE
-A DOCKER -i br-7119530cd62a -j RETURN
-A DOCKER -i br-57fd498eab6a -j RETURN
-A DOCKER -i docker0 -j RETURN
 ? root@bogon  ~  

-A POSTROUTING -s 172.17.0.0/16 ! -o docker0 -j MASQUERADE

來自 172.17.0.0/16 網段的包,目標地址是外網(! -o docker0),就把它交給 MASQUERADE 處理。而 MASQUERADE 的處理方式是將包的源地址替換成 host 的地址發送出去,即做了一次網絡地址轉換(NAT)

3.抓包分析

抓docker

 ? root@bogon ? ~ ? tcpdump -i docker0 -n icmp
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on docker0, link-type EN10MB (Ethernet), capture size 262144 bytes
03:21:28.362520 IP 172.17.0.2 > 13.107.21.200: ICMP echo request, id 1792, seq 133, length 64
03:21:28.400419 IP 13.107.21.200 > 172.17.0.2: ICMP echo reply, id 1792, seq 133, length 64
03:21:29.363317 IP 172.17.0.2 > 13.107.21.200: ICMP echo request, id 1792, seq 134, length 64
03:21:29.402380 IP 13.107.21.200 > 172.17.0.2: ICMP echo reply, id 1792, seq 134, length 64

docker0 收到 busybox 的 ping 包,源地址為容器 IP 172.17.0.2

抓ens33

? root@bogon  ~  tcpdump -i ens33 -n icmp  
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on ens33, link-type EN10MB (Ethernet), capture size 262144 bytes
03:22:30.405175 IP 192.168.246.138 > 13.107.21.200: ICMP echo request, id 1792, seq 195, length 64
03:22:30.442453 IP 13.107.21.200 > 192.168.246.138: ICMP echo reply, id 1792, seq 195, length 64
03:22:31.405493 IP 192.168.246.138 > 13.107.21.200: ICMP echo request, id 1792, seq 196, length 64

ping 包的源地址變成了 ens33 的 IP 192.168.246.138

busybox 發送 ping 包:172.17.0.2 > www.bing.com。

docker0 收到包,發現是發送到外網的,交給 NAT 處理。

NAT 將源地址換成 enp0s3 的 IP:192.168.246.138 > www.bing.com。

ping 包從 ens33 發送出去,到達 www.bing.com。

外部訪問內部

使用端口映射的方式

docker 可將容器對外提供服務的端口映射到 host 的某個端口,外網通過該端口訪問容器。容器啟動時通過-p參數映射端口:

 ? root@bogon  ~  docker run -d -p 80 httpd
f16876575a9bd742eaeab3b809685d257c51593a491f8b746490a3e2b22d664f

? root@bogon  ~  docker ps
CONTAINER ID        IMAGE               COMMAND              CREATED             STATUS              PORTS                   NAMES
f16876575a9b        httpd               "httpd-foreground"   2 minutes ago       Up 2 minutes        0.0.0.0:32768->80/tcp   nostalgic_mccarthy


 ? root@bogon  ~  curl 0.0.0.0:32768
<html><body><h1>It works!</h1></body></html>

指定綁定端口

 ? root@bogon  ~  docker run -d -p 8080:80  httpd
026c43829faa0a5a9956dd76e029ad39943c9c74739026558634e9b3d9ad9e0d
 ? root@bogon  ~  docker ps                      
CONTAINER ID        IMAGE               COMMAND              CREATED             STATUS              PORTS                   NAMES
026c43829faa        httpd               "httpd-foreground"   3 seconds ago       Up 2 seconds        0.0.0.0:8080->80/tcp    tender_hawking
f16876575a9b        httpd               "httpd-foreground"   8 minutes ago       Up 8 minutes        0.0.0.0:32768->80/tcp   nostalgic_mccarthy

每一個映射的端口,host 都會啟動一個?docker-proxy?進程來處理訪問容器的流量

 ? root@bogon  ~  ps -ef | grep docker-proxy
root       1584      1  0 03:17 ?        00:00:02 /usr/bin/dockerd-current --add-runtime docker-runc=/usr/libexec/docker/docker-runc-current --default-runtime=docker-runc --exec-opt native.cgroupdriver=systemd --userland-proxy-path=/usr/libexec/docker/docker-proxy-current --init-path=/usr/libexec/docker/docker-init-current --seccomp-profile=/etc/docker/seccomp.json --selinux-enabled --log-driver=journald --signature-verification=false --storage-driver overlay2
root       2126   1584  0 03:26 ?        00:00:00 /usr/libexec/docker/docker-proxy-current -proto tcp -host-ip 0.0.0.0 -host-port 32768 -container-ip 172.17.0.2 -container-port 80
root       2362   1584  0 03:35 ?        00:00:00 /usr/libexec/docker/docker-proxy-current -proto tcp -host-ip 0.0.0.0 -host-port 8080 -container-ip 172.17.0.3 -container-port 80
root       2525   1407  0 03:36 pts/0    00:00:00 grep --color=auto --exclude-dir=.bzr --exclude-dir=CVS --exclude-dir=.git --exclude-dir=.hg --exclude-dir=.svn docker-proxy

技術分享圖片

docker-網絡基礎