版本比较

标识

  • 该行被添加。
  • 该行被删除。
  • 格式已经改变。
本章介绍

Docker Bridge 网络

网络基础知识回顾
提示

IP、子网掩码、网关、DNS、端口号

https://zhuanlan.zhihu.com/p/65226634

Note

面试常问的一个题目, 当你在浏览器中输入一个网址(比如www.baidu.com)并敲回车,这个过程后面都发生了什么

Internet如何工作的

https://www.hp.com/us-en/shop/tech-takes/how-does-the-internet-work

从数据包的角度详细解析

https://www.homenethowto.com/advanced-topics/traffic-example-the-full-picture/

网络常用命令

IP地址的查看

Windows

ipconfig

Linux

ifconfig

或者

ip addr

网络连通性测试

ping命令

PS C:\Users\Peng Xiao> ping 192.168.178.1

Pinging 192.168.178.1 with 32 bytes of data:
Reply from 192.168.178.1: bytes=32 time=2ms TTL=64
Reply from 192.168.178.1: bytes=32 time=3ms TTL=64
Reply from 192.168.178.1: bytes=32 time=3ms TTL=64
Reply from 192.168.178.1: bytes=32 time=3ms TTL=64

Ping statistics for 192.168.178.1:
    Packets: Sent = 4, Received = 4, Lost = 0 (0% loss),
Approximate round trip times in milli-seconds:
    Minimum = 2ms, Maximum = 3ms, Average = 2ms
PS C:\Users\Peng Xiao>

telnet命令

测试端口的连通性

~ telnet www.baidu.com 80
Trying 104.193.88.123...
Connected to www.wshifen.com.
Escape character is '^]'.

HTTP/1.1 400 Bad Request

Connection closed by foreign host.
➜  ~

traceroute

路径探测跟踪

Linux下使用 tracepath

~ tracepath www.baidu.com
1?: [LOCALHOST]                      pmtu 1500
1:  DESKTOP-FQ0EO8J                                       0.430ms
1:  DESKTOP-FQ0EO8J                                       0.188ms
2:  192.168.178.1                                         3.371ms
3:  no reply
4:  gv-rc0052-cr102-et91-251.core.as33915.net            13.970ms
5:  asd-tr0021-cr101-be156-10.core.as9143.net            19.190ms
6:  nl-ams04a-ri3-ae51-0.core.as9143.net                213.589ms
7:  63.218.65.33                                         16.887ms
8:  HundredGE0-6-0-0.br04.sjo01.pccwbtn.net             176.099ms asymm 10
9:  HundredGE0-6-0-0.br04.sjo01.pccwbtn.net             173.399ms asymm 10
10:  63-219-23-98.static.pccwglobal.net                  177.337ms asymm 11
11:  104.193.88.13                                       178.197ms asymm 12
12:  no reply
13:  no reply
14:  no reply
15:  no reply
16:  no reply
17:  no reply
18:  no reply
19:  no reply
20:  no reply
21:  no reply
22:  no reply
23:  no reply
24:  no reply
25:  no reply
26:  no reply
27:  no reply
28:  no reply
29:  no reply
30:  no reply
    Too many hops: pmtu 1500
    Resume: pmtu 1500
➜  ~

Windows下使用 TRACERT.EXE

PS C:\Users\Peng Xiao> TRACERT.EXE www.baidu.com

Tracing route to www.wshifen.com [104.193.88.123]
over a maximum of 30 hops:

1     4 ms     3 ms     3 ms  192.168.178.1
2     *        *        *     Request timed out.
3    21 ms    18 ms    19 ms  gv-rc0052-cr102-et91-251.core.as33915.net [213.51.197.37]
4    14 ms    13 ms    12 ms  asd-tr0021-cr101-be156-10.core.as9143.net [213.51.158.2]
5    23 ms    19 ms    14 ms  nl-ams04a-ri3-ae51-0.core.as9143.net [213.51.64.194]
6    15 ms    14 ms    13 ms  63.218.65.33
7   172 ms   169 ms   167 ms  HundredGE0-6-0-0.br04.sjo01.pccwbtn.net [63.223.60.58]
8   167 ms   168 ms   168 ms  HundredGE0-6-0-0.br04.sjo01.pccwbtn.net [63.223.60.58]
9   168 ms   173 ms   167 ms  63-219-23-98.static.pccwglobal.net [63.219.23.98]
10   172 ms   170 ms   171 ms

curl命令

请求web服务的

http://www.ruanyifeng.com/blog/2019/09/curl-reference.html

Docker Bridge 网络

Warning

注意,本节实验需要在Linux环境下进行

Image Removed

创建两个容器

$ docker container run -d --rm --name box1 busybox /bin/sh -c "while true; do sleep 3600; done"
$ docker container run -d --rm --name box2 busybox /bin/sh -c "while true; do sleep 3600; done"
$ docker container ls
CONTAINER ID   IMAGE     COMMAND                  CREATED          STATUS          PORTS     NAMES
4f3303c84e53   busybox   "/bin/sh -c 'while t…"   49 minutes ago   Up 49 minutes             box2
03494b034694   busybox   "/bin/sh -c 'while t…"   49 minutes ago   Up 49 minutes             box1

容器间通信

两个容器都连接到了一个叫 docker0 的Linux bridge上

$ docker network ls NETWORK ID NAME DRIVER SCOPE 1847e179a316 bridge bridge local a647a4ad0b4f host host local fbd81b56c009 none null local $ docker network inspect bridge [ { "Name": "bridge", "Id": "1847e179a316ee5219c951c2c21cf2c787d431d1ffb3ef621b8f0d1edd197b24",

本节实验需要在Linux环境下进行。

Image Added

创建两个容器

代码块
$ docker container run -d --rm --name box1 busybox /bin/sh -c "while true; do sleep 3600; done"
$ docker container run -d --rm --name box2 busybox /bin/sh -c "while true; do sleep 3600; done"
$ docker container ls
CONTAINER ID   IMAGE     COMMAND                  CREATED          STATUS          PORTS     NAMES
4f3303c84e53   busybox   "/bin/sh -c 'while t…"   49 minutes ago   Up 49 minutes             box2
03494b034694   busybox   "/bin/sh -c 'while t…"   49 minutes ago   Up 49 minutes             box1

容器间通信

两个容器都连接到了一个叫 docker0 的Linux bridge上。

展开
代码块
$ docker network ls
NETWORK ID     NAME      DRIVER    SCOPE
1847e179a316   bridge    bridge    local
a647a4ad0b4f   host      host      local
fbd81b56c009   none      null      local
$ docker network inspect bridge
[
    {
        "Name": "bridge",
        "Id": "1847e179a316ee5219c951c2c21cf2c787d431d1ffb3ef621b8f0d1edd197b24",
        "Created": "2021-07-01T15:28:09.265408946Z",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": null,
            "Config": [
                {
                    "
Created
Subnet": "
2021-07-01T15:28:09.265408946Z
172.17.0.0/16",
           
"Scope":
 
"local",
        "
Driver
Gateway": "
bridge",
172.17.0.1"
       
"EnableIPv6": false,
        
"IPAM":
 
{
}
            ]
   
"Driver":
 
"default",
    },
        "
Options
Internal": 
null
false,
        
"
Config
Attachable": 
[
false,
        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
       
"Subnet": "172.17.0.0/16"
 },
        
"ConfigOnly": false,
        "
Gateway
Containers": 
"172.17.0.1"
{
            "03494b034694982fa085cc4052b6c7b8b9c046f9d5f85f30e3a9e716fad20741": {
   
}
             
]
"Name": "box1",
        
},
        "
Internal
EndpointID": 
false
"072160448becebb7c9c333dce9bbdf7601a92b1d3e7a5820b8b35976cf4fd6ff",
       
"Attachable":
 
false,
        "
Ingress
MacAddress": 
false
"02:42:ac:11:00:02",
   
"ConfigFrom":
 
{
            "
Network
IPv4Address": "172.17.0.2/16",
        
},
        "
ConfigOnly
IPv6Address": 
false,
""
           
"Containers": {
 },
            "
03494b034694982fa085cc4052b6c7b8b9c046f9d5f85f30e3a9e716fad20741
4f3303c84e5391ea37db664fd08683b01decdadae636aaa1bfd7bb9669cbd8de": {
                "Name": "
box1
box2",
                "EndpointID": "
072160448becebb7c9c333dce9bbdf7601a92b1d3e7a5820b8b35976cf4fd6ff
4cf0f635d4273066acd3075ec775e6fa405034f94b88c1bcacdaae847612f2c5",
                "MacAddress": "02:42:ac:11:00:
02
03",
                "IPv4Address": "172.17.0.
2
3/16",
                "IPv6Address": ""
            }
,

        },
        "
4f3303c84e5391ea37db664fd08683b01decdadae636aaa1bfd7bb9669cbd8de
Options": {
            
"Name
"com.docker.network.bridge.default_bridge": "
box2
true",
            
"EndpointID
"com.docker.network.bridge.enable_icc": "
4cf0f635d4273066acd3075ec775e6fa405034f94b88c1bcacdaae847612f2c5
true",
            
"MacAddress
"com.docker.network.bridge.enable_ip_masquerade": "
02:42:ac:11:00:03
true",
            
"IPv4Address
"com.docker.network.bridge.host_binding_ipv4": "
172
0.
17
0.0.
3/16
0",
           
"IPv6Address"
 "com.docker.network.bridge.name": "docker0",
            
}
"com.docker.network.driver.mtu": "1500"
        },
        "
Options
Labels": {}
    }
]
$ brctl show
bridge name     
"com.docker.network.bridge.default_bridge": "true",
bridge id               STP 
"com.docker.network.bridge.enable_icc": "true",
enabled     interfaces
docker0         8000.0242759468cf      
"com.docker.network.bridge.enable_ip_masquerade": "true",
 no             
"com.docker.network.bridge.host_binding_ipv4": "0.0.0.0",
 veth8c9bb82
            
"com.docker.network.bridge.name": "docker0",
                      
"com.docker.network.driver.mtu":
 
"1500"
        
},
        
"Labels":
 
{}
    
} ]
vethd8f9afb
Note
提示

brctl 使用前需要安装, 对于CentOS, 可以通过 sudo yum install -y bridge-utils 安装. 对于Ubuntu, 可以通过 sudo apt

-get install -y bridge-utils

-get install -y bridge-utils

容器对外通信

查看路由:

代码块
$ ip route
default via 10.0.2.2 dev eth0 proto dhcp metric 100
10.0.2.0/24 dev eth0 proto kernel scope link src 10.0.2.15 metric 100
172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1
192.168.200.0/24 dev eth1 proto kernel scope link src 192.168.200.10 metric 101

iptables转发规则:

代码块
$ sudo iptables --list -t nat
Chain PREROUTING (policy ACCEPT)
target     prot opt source
$ brctl show bridge name bridge id STP enabled interfaces docker0 8000.0242759468cf no veth8c9bb82
               destination
DOCKER     all  --  anywhere         
vethd8f9afb

容器对外通信

查看路由

$
 
ip
 
route default
 
via 10.0.2.2 dev eth0 proto dhcp metric 100 10.0.2.0/24 dev eth0 proto kernel scope link src 10.0.2.15 metric 100 172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1 192.168.200.0/24 dev eth1 proto kernel scope link src 192.168.200.10 metric 101

iptable [1] 转发规则

$ sudo iptables --list -t nat Chain PREROUTING
 anywhere             ADDRTYPE match dst-type LOCAL

Chain INPUT (policy ACCEPT)
target     prot opt source               destination

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination
DOCKER     all  --
anywhere
  anywhere           
anywhere
 !loopback/8           
ADDRTYPE match dst-type LOCAL

Chain 
INPUT
POSTROUTING (policy ACCEPT)
target     prot opt source               destination
MASQUERADE  all  --  172.17.0.0/16        anywhere

Chain 
OUTPUT
DOCKER (
policy
2 
ACCEPT
references)
target     prot opt source               destination
DOCKER
RETURN     all  --  anywhere             anywhere

端口转发

创建容器:

代码块
$ docker 
!loopback/8
container run -d --rm --name web -p 8080:80 nginx
$ docker container 
ADDRTYPE
inspect 
match dst
--
type LOCAL Chain POSTROUTING (policy ACCEPT) target prot opt source destination MASQUERADE all -- 172.17.0.0/16 anywhere Chain DOCKER (2 references) target prot opt source
format '{{.NetworkSettings.IPAddress}}' web
$ docker container run -d --rm --name client busybox /bin/sh -c "while true; do sleep 3600; done"
$ docker container inspect --format '{{.NetworkSettings.IPAddress}}' client
$ docker container exec -it client wget http://172.17.0.2

查看iptables的端口转发规则:

代码块
[vagrant@docker-host1 ~]$ sudo iptables -t nat -nvxL
Chain PREROUTING (policy ACCEPT 10 packets, 1961 bytes)
    pkts      bytes target     prot opt 
destination RETURN
in     
all
out  
--
  
anywhere
 source            
anywhere

端口转发

创建容器

$
 
docker
 
container
 
run
destination
 
-d
 
--rm
 
--name
 
web
1 
-p
 
8080:80
 
nginx $
 
docker
 
container
 
inspect
 
--format '{{.NetworkSettings.IPAddress}}' web $ docker container run -d --rm
52 DOCKER     all  --
name
 
client
 
busybox
* 
/bin/sh
 
-c
 
"while
 
true;
 
do
 
sleep
* 
3600;
 
done" $
 
docker
 
container
 
inspect
 
--format '{{.NetworkSettings.IPAddress}}' client $ docker container exec -it client wget http://172.17.0.2

查看iptables的端口转发规则

[vagrant@docker-host1 ~]$ sudo iptables -t nat -nvxL Chain PREROUTING
 0.0.0.0/0            0.0.0.0/0            ADDRTYPE match dst-type LOCAL

Chain INPUT (policy ACCEPT 
10
9 packets, 
1961
1901 bytes)
    pkts      bytes target     prot opt in     out     source               destination

Chain OUTPUT (policy ACCEPT 
1
2 packets, 120 bytes)
    
52
pkts 
DOCKER
     
all
bytes target 
--
  
*
  prot opt in  
*
   out    
0.0.0.0/0 0.0.0.0/0
 source            
ADDRTYPE
 
match
 
dst-type
 
LOCAL Chain INPUT (policy ACCEPT 9 packets, 1901 bytes) pkts
destination
    0        0 DOCKER     all  --  *    
bytes
 
target
 *    
prot
 
opt
 
in
 0.0.0.0/0    
out
     
source
  !127.0.0.0/8          ADDRTYPE match dst-type 
destination
LOCAL

Chain 
OUTPUT
POSTROUTING (policy ACCEPT 
2
4 packets, 
120
232 bytes)
    pkts      bytes target     prot opt in     out     source               destination
    
0
3      
0 DOCKER
202 MASQUERADE  all  --  *      
*
!docker0  
0.0
172.17.0.0/
0
16        
!127
0.0.0.0/
8 ADDRTYPE match dst-type LOCAL Chain POSTROUTING (policy ACCEPT 4 packets, 232 bytes) pkts
0
    0  
bytes
 
target
     
prot
0 
opt
MASQUERADE 
in
 tcp  --  
out
*     
source
 *       172.17.0.2       
destination
    
3
172.17.0.2      
202
 
MASQUERADE
  
all
  
-- *
tcp dpt:80

Chain DOCKER (2 references)
    
!docker0
pkts  
172.17.0.0/16
    bytes 
0.0.0.0/0
target     
0
prot opt in     out 
0
 
MASQUERADE
  
tcp
 source 
--
  
*
      
*
      
172.17.0.2
destination
    0        
172.17.
0
.2
 RETURN     all  --  
tcp dpt:80 Chain DOCKER (2 references)
docker0 *       
pkts
0.0.0.0/0      
bytes
 
target
     
prot opt in
0.0.0.0/0
    1   
out
    52 
source
DNAT       tcp  --  !docker0 *   
destination
    0.0.0.0/0        
0
 
RETURN
   0.0.0.0/0  
all
  
--
  
docker0
 
*
     tcp 
0.0.0.0/0 0.0.0.0/0 1 52 DNAT tcp -- !docker0 * 0.0.0.0/0 0.0.0.0/0 tcp dpt:8080 to:172.17.0.2:80
dpt:8080 to:172.17.0.2:80

创建和使用 bridge

提示

参考docker network --help。

创建bridge:

代码块
docker network create -d bridge mybridge
docker network ls
docker network inspect mybridge

新创建的bridge有自己的网关和掩码。

使用bridge创建容器:

代码块
docker container run -d --rm --name box0 busybox /bin/sh -c "while true; do sleep 3600; done"
docker container run -d --rm --name box1 --network mybridge busybox /bin/sh -c "while true; do sleep 3600; done"

新创建的容器将使用mybridge的网段和ip地址。

也可以将容器连接到另一个bridge上:

代码块
docker network connect mybridge box0
docker container inspect box0

进到box0的终端,查看ip地址,可以看到多了一个mybridge网段的网络接口。

也可以断开一个bridge:

代码块
docker network disconnect mybridge box0
提示

默认的bridge不带主机名解析功能,不可以ping主机名,也就是--name指定的容器名称。但新创建的bridge带有主机名解析功能,可以直接ping主机名。

提示

创建bridge时可以指定网关和掩码,参考docker network create --help,示例如下:

代码块
docker network create -d bridge --gateway 172.200.0.1 --subnet 172.0.0.0/16 mybridge

Docker Host 网络

如果使用这个网络来创建容器,则容器和宿主机共享相同的网络环境,这可以省略NAT的步骤,但是因为所有Host网络的容器和宿主机都是是共享相同的网络环境,容易引起资源冲突,比如一个容器占用了80端口,那么另一个容器就不能再使用相同的端口了。

创建和使用 bridge

Docker Host 网络

网络命名空间

Linux的Namespace(命名空间)技术是一种隔离技术,常用的Namespace有 user namespace, process namespace, network

namespace等

namespace等。

在Docker容器中,不同的容器通过Network namespace进行了隔离,也就是不同的容器有各自的IP地址,路由表等,互不影响。

Note

准备一台Linux机器,这一节会用到一个叫 brtcl 的命令,这个命令需要安装,如果是Ubuntu的系统,可以通过 apt-get install bridge-utils 安装;如果是Centos系统,可以通过 sudo yum install bridge-utils 来安装

Image Removed

创建bridge

Image Added

创建bridge

代码块
[vagrant@docker-host1 ~]$ sudo brctl addbr mydocker0
[vagrant@docker-host1 ~]$ brctl show
bridge name     bridge id               STP enabled     interfaces
mydocker0               8000.000000000000       no
[vagrant@docker-host1 ~]$

准备一个shell脚本

代码块
title
脚本名字叫 
add-ns-to-br.sh
#!/bin/bash

bridge=$1
namespace=$2
addr=$3

vethA=veth-$namespace
vethB=eth00

sudo ip netns add $namespace
sudo ip link add $vethA type veth peer name $vethB

sudo ip link set $vethB netns $namespace
sudo ip netns exec $namespace ip addr add $addr dev $vethB
sudo ip netns exec $namespace ip link set $vethB up

sudo ip link set $vethA up

sudo brctl addif $bridge $vethA

脚本执行

代码块
[vagrant@docker-host1 ~]$ sh add-ns-to-br.sh mydocker0 ns1 172.16.1.1/16
[vagrant@docker-host1 ~]$ sh add-ns-to-br.sh mydocker0 ns2 172.16.1.2/16

把mydocker0这个bridge

up起来

up起来:

代码块
[vagrant@docker-host1 ~]$ sudo ip link set dev mydocker0 up

验证

代码块
[vagrant@docker-host1 ~]$ sudo ip netns exec ns1 bash
[root@docker-host1 vagrant]# ip a
1: lo: 
<LOOPBACK>
<LOOPBACK> mtu 65536 qdisc noop state DOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
5: eth00@if6: 
<BROADCAST
<BROADCAST,MULTICAST,UP,LOWER_
UP>
UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether f2:59:19:34:73:70 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 172.16.1.1/16 scope global eth00
    valid_lft forever preferred_lft forever
    inet6 fe80::f059:19ff:fe34:7370/64 scope link
    valid_lft forever preferred_lft forever
[root@docker-host1 vagrant]# ping 172.16.1.2
PING 172.16.1.2 (172.16.1.2) 56(84) bytes of data.
64 bytes from 172.16.1.2: icmp_seq=1 ttl=64 time=0.029 ms
64 bytes from 172.16.1.2: icmp_seq=2 ttl=64 time=0.080 ms
^C
--- 172.16.1.2 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1000ms
rtt min/avg/max/mdev = 0.029/0.054/0.080/0.026 ms
[root@docker-host1 vagrant]#

对外通信

https://www.karlrupp.net/en/computer/nat_tutorial

flask_redis_demo
flask_redis_demo

Python Flask + Redis 练习

程序准备

准备一个Python文件,名字为 app.py 内容如下:

代码块
from flask import Flask
from redis import Redis
import os
import socket

app = Flask(__name__)
redis = Redis(host=os.environ.get('REDIS_HOST', '127.0.0.1'), port=6379)


@app
@app.route('/')
def hello():
    redis.incr('hits')
    return f"Hello Container World! I have been seen {redis.get('hits').decode('utf-8')} times and my hostname is {socket.gethostname()}.\n"

准备一个Dockerfile:

准备一个Dockerfile
代码块
FROM python:3.9.5-slim

RUN pip install flask redis && \
    groupadd -r flask && useradd -r -g flask flask && \
    mkdir /src && \
    chown -R flask:flask /src

USER flask

COPY app.py /src/app.py

WORKDIR /src

ENV FLASK_APP=app.py REDIS_HOST=redis

EXPOSE 5000

CMD ["flask", "run", "-h", "0.0.0.0"]

镜像准备

构建flask镜像,准备一个redis镜像。

代码块
$ docker image pull redis
$ docker image build -t flask-demo .
$ docker image ls
REPOSITORY   TAG          IMAGE ID       CREATED              SIZE
flask-demo   latest       4778411a24c5   About a minute ago   126MB
python       3.9.5-slim   c71955050276   8 days ago           115MB
redis        latest       08502081bff6   2 weeks ago          105MB

创建一个docker bridge

代码块
$ docker network create -d bridge demo-network
8005f4348c44ffe3cdcbbda165beea2b0cb520179d3745b24e8f9e05a3e6456d
$ docker network ls
NETWORK ID     NAME           DRIVER    SCOPE
2a464c0b8ec7   bridge         bridge    local
8005f4348c44   demo-network   bridge    local
80b63f711a37   host           host      local
fae746a75be1   none           null      local
$

创建redis container

创建一个叫 redis-server 的container,连到 demo-

network上

network上:

代码块
$ docker container run -d --name redis-server --network demo-network redis
002800c265020310231d689e6fd35bc084a0fa015e8b0a3174aa2c5e29824c0e
$ docker container ls
CONTAINER ID   IMAGE     COMMAND                  CREATED         STATUS         PORTS      NAMES
002800c26502   redis     "docker-entrypoint.s…"   4 seconds ago   Up 3 seconds   6379/tcp   redis-server
$

创建flask container

代码块
$ docker container run -d --network demo-network --name flask-demo --env REDIS_HOST=redis-server -p 5000:5000 flask-demo

打开浏览器访问 http://127.0.0.1:5000,应该能看到类似下面的内容,每次刷新页面,计数加1:

应该能看到类似下面的内容,每次刷新页面,计数加1
代码块
Hello Container World! I have been seen 36 times and my hostname is 925ecb8d111a.

总结

如果把上面的步骤合并到一起,成为一个部署脚本

如果把上面的步骤合并到一起,成为一个部署脚本:

代码块
# prepare image
docker image pull redis
docker image build -t flask-demo .

# create network
docker network create -d bridge demo-network

# create container
docker container run -d --name redis-server --network demo-network redis
docker container run -d --network demo-network --name flask-demo --env REDIS_HOST=redis-server -p 5000:5000 flask-demo



目录