docker-网络基础

网络

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 网络的配置信息:

mark

bridge 网络配置的 subnet 就是 172.17.0.0/16,并且网关是 172.17.0.1。

mark容器创建时,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

posted @ 2018-08-09 15:39  mrwuzs  阅读(297)  评论(0编辑  收藏  举报