目 录CONTENT

文章目录

Docker 容器网络和通信原理

Sakura
2023-10-28 / 0 评论 / 0 点赞 / 22 阅读 / 14886 字 / 正在检测是否收录...

一: Docker 默认的网络模型

Docker Host : 安装了 docker deamon 的主机

docker0 : 安装了 docker 之后出现的网桥

  • 通过网桥可以将 Linux 支持的不同的端口连接起来

  • 实现类交换机多对多的通信

veth pair

  • 虚拟以太网(Ethernet)设备

  • 成对出现,用于解决网络命名空间之间的隔离

  • 一端连接 Container network namespace,另一端连接 host network namespace

当创建了一个容器之后 , 会在主机中创建一个虚拟的以太网设备 ( veth )

一端连接主机的网络的命名空间

一端连接容器的网络命名空间

  • 启动一个容器,查看容器的网络设备

docker run -it centos:latest bash

可以看到容器有自己的网络设备,这是连接容器网络命名空间的一端

按住ctrl+p+q 退回容器,使容器在后台运行

这个虚拟的网络设备就是连接 docker host 网络命名空间的

二: Docker 网络模型工作原理

1. 容器访问外网

容器中的数据包转发给 eth0 网卡,然后在转发到 docker host 命名空间的虚拟网络设备,虚拟的网络设备会把数据传给 docker0, 然后再转发给 eth0 ( 物理网卡 ),

SNAT 源地址转换:把 docker0 的源地址转换成 docker host 主机所在网段的 IP 地址

iptables -t nat -vnL POSTROUTING

MASQUERADE 就是 SNAT ,底层转发是由 iptables 来承载的

2. 外网访问容器

首先外网的数据包能够传送到 eth0 网卡,内核接收到数据之后会进行 DNAT (目标地址转换)

所以容器的 port 就是: 但访问宿主主机的 3306 端口,会被转发到容器的某个端口

可以通过 iptables 看到 docker 链

iptables -t nat -nL

不管哪个 IP , 不管目标地址是哪个,只要访问对应端口,就转换到 172.17.... 的对应端口

三: Docker 四种网络模型

  • bridge [ 桥接式网络 ( Bridge container A ) ]--network bridge (默认网络模型)

    • 桥接容器,除了有一块本地回环接口 ( Loopback interface ) 外,还有一块私有接口 ( Private interface ) 通过容器虚拟接口 ( Container virtual interface ) 连接到桥接虚拟接口 ( Docker bridge virtual interface ),之后通过逻辑主机接口 ( Logical host interface ) 连接到主机物理网络 ( Physical network interface )。桥接网卡默认会分配到 172.17.0.0/16 的IP地址段。
      如果我们在创建容器时没有指定网络模型,默认就是 ( Nat ) 桥接网络,这也就是为什么我们在登录到一个容器后,发现 IP 地址段都在 172.17.0.0/16 网段的原因。

容器通过虚拟以太网设备连接到主机的网络命名空间,通过主机的命名空间实现对外网的访问

  • host [ 开放式容器 ( Open container ) ]--network host

    • 比联盟式网络更开放,联盟式网络是多个容器共享网络 ( Net ) , 而开放式容器 ( Open contaner ) 就直接共享了宿主机的名称空间。因此物理网卡有多少个,那么该容器就能看到多少网卡信息。我们可以说 Open container 是联盟式容器的衍生。

让容器和主键共享同一个网络命名空间,容器中的 IP 地址和 Docker host IP 地址是完全一直的,有利于对容器服务的访问

  • none [封闭式网络(Closed container)]--network none

    • 封闭式容器,只有本地回环接口 ( Loopback interface ) ,和服务器看到的 lo 接口类似),无法与外界进行通信。

这种网络模式中只有 Loopback 这种网路接口,不能去连接外网

  • container [联盟式网络 ( Joined container A | Joined container B ]--network container:c1(容器名称或容器ID)

    • 每个容器都各有一部分名称空间 ( Mount , PID , User ),另外一部分名称空间是共享的( UTS , Net , IPC ) 。由于它们的网络是共享的,因此各个容器可以通过本地回环接口 ( Loopback interface ) 进行通信。除了共享同一组本地回环接口 ( Loopback interface ) 外,还有一块一块私有接口 ( Private interface ) 通过联合容器虚拟接口 ( Joined container virtual interface )连接到桥接虚拟接口 ( Docker bridge virtual interface ),之后通过逻辑主机接口 ( Logical host interface ) 连接到主机物理网络 ( Physical network interface )。

可以共享两个容器的命名空间

五: 查看指定类型的网络模型

1. 查看所有容器的网络模型

# 查看已有的网络模型
docker network ls
docker netword list

2. 查看指定网络模型的详细信息

root@VM-8-13-debian:~# docker network inspect bridge
[
    {
        "Name": "bridge",
        "Id": "6e7985ab54cdd0f9143da410b03f5e0df82146d3e0256fee573e6d3c64de4df5",
        "Created": "2023-10-12T18:42:05.876320519+08:00",
        "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,
        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
		# 哪些容器连接到了这个网络
        "Containers": {
            "420df0739e938ad67819430697329aa0cd0b9dc83be296995bfdf3a90b74b6e7": {
                "Name": "etcd",
                "EndpointID": "52e9e6d2601301c87c5dcaa2d8cfd47e2da9317692d2572e201207e98ca03a3c",
				# 容器的IP地址和MAC地址
                "MacAddress": "02:42:ac:11:00:02",
                "IPv4Address": "172.17.0.2/16",
                "IPv6Address": ""
            },
            "e01f2b3407cb1962b15630623e7d4ecd1ac2e40e256e3d2d87390dd31ef38985": {
                "Name": "quizzical_nobel",
                "EndpointID": "560ab4c4cf83a011fdeec12e2ac3e3b0c4252a7cb81a5ae115067ba82eea9dfb",
                "MacAddress": "02:42:ac:11:00:03",
                "IPv4Address": "172.17.0.3/16",
                "IPv6Address": ""
            }
        },
		# 默认选项
        "Options": {
			# 是不是默认网桥
            "com.docker.network.bridge.default_bridge": "true",
            "com.docker.network.bridge.enable_icc": "true",
			# 是否开启上网功能(源地址转换 SNAT)
            "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": {}
    }
]

3. 查看 docker 支持的网络模型

root@VM-8-13-debian:~# docker info | grep Network
  Network: bridge host ipvlan macvlan null overlay

六: 创建指定类型的网络模型

1. bridge

  1. 查看帮助

docker network create -h

  1. 创建网络模型

# 1.简单写法
docker network create Mysql

# 2.复杂写法
docker network create -d bridge --subnet "192.168.100.0/24" --gateway "192.168.100.1" -o com.docker.network.bridge.name=docker1 Mysql
# com.docker.network.bridge.name 就是上面查看网络模型选项信息里面的内容
  1. 验证是否创建成功

root@VM-8-13-debian:~# docker network ls
NETWORK ID     NAME              DRIVER    SCOPE
b14e183c0386   1panel-network    bridge    local
136c9c1912fc   Mysql             bridge    local
d60f5e7ed7e9   backend_default   bridge    local
6e7985ab54cd   bridge            bridge    local
affe2ac83252   host              host      local
20037e8c62b7   kafka_default     bridge    local
df9f2ca51637   logs_default      bridge    local
aeecc2524ba4   none              null      local

# 同时也可以使用 docker network inspect Mysql查看详细信息
  1. 启动一个容器连接到创建的网络

# docker run -it --network Mysql busybox
/ # ping wwww.baidu.com
PING wwww.baidu.com (110.242.68.66): 56 data bytes
64 bytes from 110.242.68.66: seq=0 ttl=250 time=10.616 ms
64 bytes from 110.242.68.66: seq=1 ttl=250 time=10.601 ms
64 bytes from 110.242.68.66: seq=2 ttl=250 time=10.595 ms
--- wwww.baidu.com ping statistics ---
11 packets transmitted, 11 packets received, 0% packet loss
round-trip min/avg/max = 10.589/10.612/10.628 ms

可以看出是可以正常 ping 通的

2. host

docker run -it --network host --rm busybox
# 启动Nginx 服务
docker run -d --network host nginx:latest
查看容器运行状态
# docker ps
CONTAINER ID   IMAGE          COMMAND                  CREATED         STATUS         PORTS     NAMES
f6677b213271   nginx:latest   "/docker-entrypoint.…"   7 seconds ago   Up 6 seconds             youthful_shtern
查看docker host 80端口状态
# ss -anput | grep ":80"
tcp    LISTEN     0      511       *:80                    *:*                   users:(("nginx",pid=42866,fd=7),("nginx",pid=42826,fd=7))
tcp    LISTEN     0      511      :::80                   :::*                   users:(("nginx",pid=42866,fd=8),("nginx",pid=42826,fd=8))

host 网络模型用的是和宿主主机同一个命名空间

缺点: 无法启动第二个这样的容器 ( 端口很稀缺 )

3. none

root@VM-8-13-debian:~# docker run -it --network none busybox
/ # ifconfig
lo        Link encap:Local Loopback  
          inet addr:127.0.0.1  Mask:255.0.0.0
          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:1000 
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

可以看到是没有网络的,如果连接了只能在本地做一下测试

如果需要有更多的网络,可以创建虚拟的网络设备

4. 联盟网络

  1. 创建c1容器,使用默认网络模型

root@VM-8-13-debian:~# docker run -it --name c1 --rm busybox:latest
/ # ifconfig
eth0      Link encap:Ethernet  HWaddr 02:42:AC:11:00:03  
          inet addr:172.17.0.3  Bcast:172.17.255.255  Mask:255.255.0.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:6 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:516 (516.0 B)  TX bytes:0 (0.0 B)

lo        Link encap:Local Loopback  
          inet addr:127.0.0.1  Mask:255.0.0.0
          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:1000 
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)
  1. 创建c2容器,与c1容器共享网络命名空间

root@VM-8-13-debian:~# docker run -it --name c2 --network container:c1 --rm busybox:latest
root@VM-8-13-debian:~# docker run -it --name c2 --network container:c1 --rm busybox:latest
/ # ifconfig
eth0      Link encap:Ethernet  HWaddr 02:42:AC:11:00:03  
          inet addr:172.17.0.3  Bcast:172.17.255.255  Mask:255.255.0.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:11 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:866 (866.0 B)  TX bytes:0 (0.0 B)

lo        Link encap:Local Loopback  
          inet addr:127.0.0.1  Mask:255.0.0.0
          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:1000 
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

可以看到两者的虚拟网卡一模一样

# 在c2容器中创建文件并开启httpd服务
echo "hello world" >> /tmp/index.html 
ls /tmp
index.html

httpd -h /tmp

# 验证80端口是否打开
/ # netstat -npl
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name
tcp        0      0 :::80                   :::*                    LISTEN      10/httpd

# 在c1容器中进行访问验证
docker exec c1 wget -O - -q 127.0.0.1
hello world

网络共享,文件系统独立

七: 跨 Docker Host 容器间通信实现

0

评论区