其他分享
首页 > 其他分享> > Docker网络

Docker网络

作者:互联网

Docker网络

docker容器之间连接,之前我们使用的是link命令,但是这个命令其实已经不被官方所推荐,在以后新的版本中,也可能会被移除,这就有一个问题了?

问题:我们怎么打通容器之间的通信呢?

接下来,我们了解一下docker的网络,随之解决遇到的问题。

网络模式

docker 自身有四种网络工作模式以及一种自定义网络模式

安装Docker时,它会自动创建三个网络,bridge(创建容器默认连接到此网络)、 none 、host

默认网络模式 简介 设置方式
bridge 启动容器的默认网络模式,会为每一个容器都分配、设置IP等,将容器连接到虚拟网桥docker0,通过虚拟网桥以及Iptables nat表配置和宿主机通信 --net=bridge 【默认】
host 容器将不会虚拟出自己的网卡,配置自己的IP等,而是使用宿主机的IP和端口。 --net=host
Container 创建的容器不会创建自己的网卡,配置自己的IP,而是和一个指定的容器共享IP、端口范围。 --net=container:NAME_or_ID
none 关闭了容器的网络功能 --net=none

查询网络模式命令:

docekr network ls 

bridge 网络模式

相当于Vmware中的Nat模式,容器使用独立network Namespace,并连接到docker0虚拟网卡(默认模式)。通过docker0网桥以及Iptables nat表配置与宿主机通信;bridge模式是Docker默认的网络设置,此模式会为每一个容器分配Network Namespace、设置IP等,并将一个主机上的Docker容器连接到一个虚拟网桥上。下面着重介绍一下此模式。

理解:

bridge是docker默认的网络模式,在docker安装成功以后,会在主机上创建一个名为docker0的虚拟网桥,当我们启动docker容器的时候,并且未设置网络模式的情况下,容器会默认连接到docker0虚拟网桥,docker守护进程会创建一对对等虚拟设备接口 veth pair,将其中一个接口设置为容器的 eth0 接口(容器的网卡),另一个接口放置在宿主机的命名空间中,以类似 vethxxx 这样的名字命名,从而将宿主机上的所有容器都连接到这个内部网络上。

docker0虚拟网桥,就像是物理交换机类似,在宿主机和容器之间起到交换数据作用。

image-20211117135755352

整个通信流程是:

  1. Docker Daemon 利用 veth pair 技术,在宿主机上创建一对对等虚拟网络接口设备,假设为 veth0 和 veth1。而 veth pair 技术的特性可以保证无论哪一个 veth 接收到网络报文,都会将报文传输给另一方。
  2. Docker Daemon 将 veth0 附加到 Docker Daemon 创建的 docker0 网桥上。保证宿主机的网络报文可以发往 veth0;
  3. Docker Daemon 将 veth1 添加到 Docker Container 所属的 namespace 下,并被改名为 eth0。如此一来,宿主机的网络报文若发往 veth0,则立即会被 Container 的 eth0 接收,实现宿主机到 Docker Container 网络的联通性;同时,也保证 Docker Container 单独使用 eth0,实现容器网络环境的隔离性。

通过实际操作,我看一下通信的流转:

  1. 运行一个 nginx 镜像容器 nginx01,查看 ip addr
# 启动nginx 容器

docker run -it  --name nginx01  -p 80:80 nginx 

# 查看 ip addr
ip addr

image-20211117143441279

启动nginx01容器后,守护进创建了一对对等虚拟设备接口 veth pair,将其中一个接口设置为容器的 eth0 接口(容器的网卡),另一个接口放置在宿主机的命名空间中,以类似 vethxxx 这样的名字命名。

守护进程还会从网桥 docker0 的私有地址空间中分配一个 IP 地址和子网给该容器,并设置 docker0 的 IP 地址为容器的默认网关。也可以安装 yum install -y bridge-utils 以后,通过 brctl show 命令查看网桥信息。

image-20211117143816930

对于容器的相信网络信息我们可以通过docker inspect 容器ID查看:

docekr inspect nginx01

# 查看网络配置模块
"Networks": {
                "bridge": {
                    "IPAMConfig": null,
                    "Links": null,
                    "Aliases": null,
                    "NetworkID": "2302db010e784147f4e8cb53e668ebfcd932394559fcfff3c65b079e5e9bf827",
                    "EndpointID": "bde65f813752db5877e77ae0fe49fcbf251b8168d27e8caf861568e3da0ae434",
                    "Gateway": "172.17.0.1",	# 网关
                    "IPAddress": "172.17.0.2",	# 容器IP
                    "IPPrefixLen": 16,
                    "IPv6Gateway": "",
                    "GlobalIPv6Address": "",
                    "GlobalIPv6PrefixLen": 0,
                    "MacAddress": "02:42:ac:11:00:02",
                    "DriverOpts": null
                }
            }

bridge 网络模式下的容器

docker network inspect bridge

[root@bogon ~]# docker network inspect bridge
[
    {
        "Name": "bridge",	# 网络模式
        "Id": "2302db010e784147f4e8cb53e668ebfcd932394559fcfff3c65b079e5e9bf827",
        "Created": "2021-11-16T22:28:55.525405758-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": {
            "36b76f065b823df2f9847acee0837ec5d3e21136d795f6e9af264ccb4108addd": {
                "Name": "nginx01",	# 该网络下的容器
                "EndpointID": "bde65f813752db5877e77ae0fe49fcbf251b8168d27e8caf861568e3da0ae434",
                "MacAddress": "02:42:ac:11:00:02",
                "IPv4Address": "172.17.0.2/16",	# 容器IP
                "IPv6Address": ""
            }
        },
        "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": {}
    }
]

注意:

host 网络模式

host网络模式相当于Vm中的桥接模式,与宿主机在同一个网络中,但没有独立IP地址。众所周知,Docker使用了Linux的Namespaces技术来进行资源隔离,如PID Namespace隔离进程,Mount Namespace隔离文件系统,Network Namespace隔离网络等。一个Network Namespace提供了一份独立的网络环境,包括网卡、路由、Iptable规则等都与其他的Network Namespace隔离一个Docker容器一般会分配一个独立的Network Namespace。但如果启动容器的时候使用host模式,那么这个容器将不会获得一个独立的Network Namespace,而是和宿主机共用一个Network Namespace。容器将不会虚拟出自己的网卡,配置自己的IP等,而是使用宿主机的IP和端口。

理解:

image-20211117145956619

基于hsot网络模式启动nginx容器

[root@bogon ~]# docker run --name=nginx_host --net=host -p 80:80 -d nginx
WARNING: Published ports are discarded when using host network mode
3b579b9f40bb47c2ecd382b3b8a8842232caf6d086bbc3fc4093f32e807f8e08

[root@bogon ~]# docker ps 
CONTAINER ID   IMAGE     COMMAND                  CREATED          STATUS          PORTS     NAMES
3b579b9f40bb   nginx     "/docker-entrypoint.…"   33 seconds ago   Up 33 seconds             nginx_host

**查ip addr **

ip addr 
# 下图,可以看到并没有新增虚拟网卡设备

image-20211117150651958

**查nginx容器的网络inspect **

 docker inspect nginx_host 
 
 # 可以看到并没有给容器分配ip
"Networks": {
                "host": {
                    "IPAMConfig": null,
                    "Links": null,
                    "Aliases": null,
                    "NetworkID": "00fa104f6ce11949adc376735ed4ceb61e25af56487832370faa1a7a0201f9f1",
                    "EndpointID": "22fceed66317ea06498b9df4c38818c222f35bbb797144877ee71ee9eb2e825c",
                    "Gateway": "",
                    "IPAddress": "",
                    "IPPrefixLen": 0,
                    "IPv6Gateway": "",
                    "GlobalIPv6Address": "",
                    "GlobalIPv6PrefixLen": 0,
                    "MacAddress": "",
                    "DriverOpts": null
                }
            }

host 网络模式下的容器

docker network inspect host
# 当前我们 的nginx容器使用host网络模式

image-20211117151128797

测试访问

 curl localhost:80
 # 	http://192.168.8.128/  直接访问宿主机的ip即可

image-20211117155957047

none 网络模式

container 网络模式

image-20211117163451294

自定义网络模式

Docker 提供的默认网络使用比较简单,但是为了保证各容器中应用的安全性,在实际开发中更推荐使用自定义的网络进行容器管理,以及启用容器名称到 IP 地址的自动 DNS 解析。

从 Docker 1.10 版本开始,docker daemon 实现了一个内嵌的 DNS server,使容器可以直接通过容器名称通信。方法很简单,只要在创建容器时使用 --name 为容器命名即可。
但是使用 Docker DNS 有个限制:只能在 user-defined 网络中使用。也就是说,默认的 bridge 网络是无法使用 DNS 的,所以我们就需要自定义网络。

创建一个自定义网络

  1. 查看现有网络
docker network ls
# 现有网络
[root@bogon ~]# docker network ls
NETWORK ID     NAME      DRIVER    SCOPE
2302db010e78   bridge    bridge    local
00fa104f6ce1   host      host      local
3a55f6933f38   none      null      local

  1. 创建网络 docker network create
 docker network create new_network
# docker network create --driver bridge --subnet 192.168.1.0/16 --gateway 192.168.1.0 mynet
# --driver 网络模式 [默认bridge]
# --subnet 网段子网
# --gateway 网关

image-20211117171550002

ERROR:守护进程无法创建新网络,由于,我在docker启动之后,关闭了宿主机的防火墙,造成的原因

解决:重启docker环境

image-20211117171913689

上图,可以看到创建网络成功

注意:

  1. 查看自定义网络
docker inspect new_network 
#
[
    {
        "Name": "new_network",
        "Id": "1800a809a0f2bf16da20345a27df9ff79dc27f3108d505b03b4379e07872ed18",
        "Created": "2021-11-17T01:18:36.838971866-08: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,
        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        "Containers": {},
        "Options": {},
        "Labels": {}
    }
]


  1. 启动nginx容器使用自定义网络
docker run  -p 80:80 --name nginx01 --net new_network  -d nginx
# -p 映射宿主机端口 
# --neame 容器名
# --net 指定容器启动使用的网络 【这里我们使用自定义的网络】
# -d 后台运行

  1. 查看启动容器的IP
 docker inspect nginx01

# 查看 Networks 模块 

 "Networks": {
                "new_network": {
                    "IPAMConfig": null,
                    "Links": null,
                    "Aliases": [
                        "0bc7518d16b9"
                    ],
                    "NetworkID": "1800a809a0f2bf16da20345a27df9ff79dc27f3108d505b03b4379e07872ed18",
                    "EndpointID": "740cdf7efb0d7bda920e8670e8fa5ffb446663774289e6eb1312f184ce93765f",
                    "Gateway": "172.18.0.1",  # 网关
                    "IPAddress": "172.18.0.2", # 容器的IP地址
                    "IPPrefixLen": 16,
                    "IPv6Gateway": "",
                    "GlobalIPv6Address": "",
                    "GlobalIPv6PrefixLen": 0,
                    "MacAddress": "02:42:ac:12:00:02",
                    "DriverOpts": null
                }
            }
# 这里的IP网关也就是我们创建网络的网关

  1. 启动第二个nginx容器使用自定义网络
docker run  -p 81:80 --name nginx02 --net new_network  -d nginx

image-20211117173934822

  1. 查看自定义网络下的容器
docker inspect new_network

image-20211117174032764

可以看到二个nginx容器一个都在自定义网络下了

  1. ping 测试
# ping ip  IP能正常ping通
[root@bogon /]# ping 172.18.0.2
PING 172.18.0.2 (172.18.0.2) 56(84) bytes of data.
64 bytes from 172.18.0.2: icmp_seq=1 ttl=64 time=0.328 ms
64 bytes from 172.18.0.2: icmp_seq=2 ttl=64 time=0.061 ms
64 bytes from 172.18.0.2: icmp_seq=3 ttl=64 time=0.037 ms
64 bytes from 172.18.0.2: icmp_seq=4 ttl=64 time=0.045 ms
64 bytes from 172.18.0.2: icmp_seq=5 ttl=64 time=0.103 ms
64 bytes from 172.18.0.2: icmp_seq=6 ttl=64 time=0.031 ms
[1]+  已停止               ping 172.18.0.2
[root@bogon /]# ping 172.18.0.3
PING 172.18.0.3 (172.18.0.3) 56(84) bytes of data.
64 bytes from 172.18.0.3: icmp_seq=1 ttl=64 time=0.062 ms
64 bytes from 172.18.0.3: icmp_seq=2 ttl=64 time=0.098 ms
64 bytes from 172.18.0.3: icmp_seq=3 ttl=64 time=0.102 ms
64 bytes from 172.18.0.3: icmp_seq=4 ttl=64 time=0.039 ms
64 bytes from 172.18.0.3: icmp_seq=5 ttl=64 time=0.096 ms
[2]+  已停止               ping 172.18.0.3
[root@bogon /]# 
  1. 进入容器nginx01,测试ping容器02
# 进入容器nginx01
docker exec -it nginx01 /bin/bash 
# 安装ping工具 docker镜像只保留核心命令
apt update && apt install iputils-ping
# 安装完成 ping 容器2
root@0bc7518d16b9:/# ping nginx02
PING nginx02 (172.18.0.3) 56(84) bytes of data.
64 bytes from nginx02.new_network (172.18.0.3): icmp_seq=1 ttl=64 time=0.114 ms
64 bytes from nginx02.new_network (172.18.0.3): icmp_seq=2 ttl=64 time=0.121 ms
64 bytes from nginx02.new_network (172.18.0.3): icmp_seq=3 ttl=64 time=0.245 ms
64 bytes from nginx02.new_network (172.18.0.3): icmp_seq=4 ttl=64 time=0.073 ms
64 bytes from nginx02.new_network (172.18.0.3): icmp_seq=5 ttl=64 time=0.094 ms

image-20211117175920772

不使用link命令即可实现容器通信,这也是我们在实际常使用自定义网络的原因之一

  1. 使用默认网络启动新nginx容器03
# 使用默认网络启动nginx03 
docker run  -p 82:80 --name nginx03  -d nginx
# 查ip
  "Networks": {
                "bridge": {
                    "IPAMConfig": null,
                    "Links": null,
                    "Aliases": null,
                    "NetworkID": "989e32212a22d0958ca0d854b662555339333f20ea2ce463f29c8919c119f0c5",
                    "EndpointID": "1985f0b431527548739d133fef18eb4cbc6fc3943ba2f936be5d1a33c63fc09d",
                    "Gateway": "172.17.0.1",
                    "IPAddress": "172.17.0.2", # 可以看到这与自定义的网络不在同一个网段
                    "IPPrefixLen": 16,
                    "IPv6Gateway": "",
                    "GlobalIPv6Address": "",
                    "GlobalIPv6PrefixLen": 0,
                    "MacAddress": "02:42:ac:11:00:02",
                    "DriverOpts": null
                }
            }


  1. 测试nginx01中ping容器03
root@0bc7518d16b9:/# ping nginx02 #测试同一个网段02容器可以正常通信
PING nginx02 (172.18.0.3) 56(84) bytes of data.
64 bytes from nginx02.new_network (172.18.0.3): icmp_seq=1 ttl=64 time=0.119 ms
64 bytes from nginx02.new_network (172.18.0.3): icmp_seq=2 ttl=64 time=0.135 ms
^Z
[1]+  Stopped                 ping nginx02
root@0bc7518d16b9:/# ping nginx03 #测试不同网段03容器不可以正常通信
ping: nginx03: Temporary failure in name resolution
root@0bc7518d16b9:/# 

问题:那么我们如何让不在同一个网段的容器贯通呢?

  1. docker network connect
# 使用dockr network connect 贯通两个不在同一个网段的容器
#  将容器三放到与容器1和2的同一个网段即可,也就是我们自定义的网络
docker network connect new_network  ngin03

# 查看自定义网络
 docker inspect new_network

image-20211117181422245

再次到nginx01中 ping容器03

image-20211117181526889

可以看到,此时,容器都在一个网段就可以通信了

总结:一个容器两个ip地址;与阿里云服务,公网ip 私网ip类似

  1. 移除网络
docker network rm  
# 主要注意的是:如果通过某个自定义网络模式创建了容器,则该网络模式无法删除

标签:容器,network,网络,64,172.18,Docker,docker
来源: https://www.cnblogs.com/MrYuChen-Blog/p/15568643.html