Docker网络

一、什么是ip地址

通常我们看到的ip地址会长这样(由点分割的十进制数):192.168.1.1

其实ip地址是一个32位的二进制数,被分割成4部分,每部分8位。也就是说他们其实长成这样

00000000.00000000.00000000.00000000

每一部分都是8位的二进制数,那他能表示的范围其实就是0~255,并且在一个子网中,第一个0为保留位,最后一个255为广播位,这两位不会划分出去。(比如在局域网中找不到一个完全匹配的ip时,可能就会广播数据报文,广播的地址就会使用255)

所以说,一般情况下,局域网中可以使用的ip为1~254

0.0.0.0 回环地址

255.255.255.255 广播地址

二、划分子网

2.1、为什么要划分子网

划分子网是为了更好的利用ip地址资源,因为ip地址就是上面提到的4个byte字节组成的,一共就有2的32方个,随着互联网的发展,ip地址已经不够用了

现在的解决方案有两种,一种是将ipv4升级成ipv6,第二种就是现在说的划分子网,通过合理划分子网来缓解ip地址枯竭的问题。

2.2、子网分类

子网分类说的是人为的将子网分成A、B、C、D类,每个分类都有两部分组成:网络号+主机号

无论怎么划分,网络号和主机号一共32位是不会变的

A类:8位网络号  24位主机号
B类:16位网络号 16位主机号
C类:24位网络号 8位主机号

2.3、子网划分

子网划分的应用场景:

上面C类子网支持254台主机,B类子网支持6万多台主机。

那假设现在有一个公司,他们公司有几千名员工,如果为他们申请ip的话请问是该申请C类地址还是B类地址呢?

很显然,C类肯定不够用,B类又会浪费掉好几万个ip资源~

这时就得进行子网划分,拿这个例子来说就是我们给该公司申请一个B类地址,然后将B类地址中的部分主机位当作网络ID,这样的话,主机位数就变少了,最新的网络号 = 网络号+从主机位划分出来的网络ID,原来的二级Ip 地址被划分成三级Ip地址,收益就是:实现节省ip地址。

实战子网划分

假设我们对192.168.1.0这个网络号进行子网划分。

然后我们从主机号借用两位当作网络号

# 如果不进行子网分,它是一个C类网络地址,可以承载254台机器
192.168.1.00000000

# 借两位主机位当作网络id来 划分子网,可以得到下面四个子网
192.168.1.00 000000
192.168.1.01 000000
192.168.1.10 000000
192.168.1.11 000000

网络号相同的ip视为在一个局域网中,这样就将原来的一个C类地址划分成四个网络地址,也就能给四个公司使用,而且每个网络中都能分配2的6次方个左右的ip地址。

一个设备有多个ip是正常的,甚至当有它有多个物理网卡,就能有多个公网ip,相应的每个设备也有私网ip,也就是他所在的局域网中的ip(一般是通过DHCP获取的)

想接入互联网就的有公网ip,全球有42亿的ipv4的公网ip,我们的硬件设备默认有一个自己的本地ip,比如192.168...,当设备连通局域网后,设备的本地ip其实是这个公网ip下的局域网的ip地址之一,这样可以尽最大可能的利用有限的ip网络地址资源(而不用为每一台设备都分配一个独有的公网ip)

2.4、子网掩码

在上一个例子中我们将这个网络号192.168.1.0,通过子网划分,分成了四个网络,如下

192.168.1.00 000000
192.168.1.01 000000
192.168.1.10 000000
192.168.1.11 000000

问题是怎么让机器区分开这是四个网络地址,而不是一个C类地址呢?

这就引出了子网掩码的概念: 子网掩码和ip地址同为32位,子网掩码为1的区域对应着ip地址的网络号部分,子网掩码为0的区域对应着ip地址的主机号部分。

就这个例子来说,它的子网掩码如下

# 192.168.1.0	 ==转二进制==>   11000000.10101000.00000001.00000000
# 本来他是C类网络地址:它的网络号为前24位,后8位为主机号
# 然后我们划分子网,从主机位给网络位借两位,也就是前26位是网络号,后6位是主机号
# 对应的子网掩码位:前26位为1,后6位为0。即11111111.11111111.11111111.11000000
# 11111111.11111111.11111111.11000000 =转十进制=>255.255.255.192

如果通过ip和子网掩码得出网络ID呢?

# 两者的二进制表示做与运算
# 相同为1,不同为0

网络ID相同,说明这两个ip在同一个局域子网中

2.5、无分类-构成超网

这里说的无分类-构成超网本质上也是一种ip地址的编址方式,并且它消除了传统的ABCD这种划分子网的概念。

它的编制方式为:网络号/主机号

通常使用这种方式编址的ip长这个样子:192.68.1.1/20

在ipv4中,ip地址的总长度为32位这是不会变的,这里的20表示的是在这总长为32位的地址中,前20为网络号,剩下的12位是主机号

三、网络模式

常见的网络模式有:桥接模式、NAT模式、仅主机模式。比如在vmware中设置虚拟机的网络模式时,可以看到

image-20200918081455193

3.1、桥接

桥接模式的本质是:使用一个虚拟的交换机,将虚拟机和物理机网卡打通。他们同属于一个网段

image-20200918082322318

在这种模式下:有如下特性:

  • 虚拟机和物理机同属一个网段
  • 虚拟机之间可以相同Ping通
  • 虚拟机和物理机之间可以相互ping通
  • 只要主机能上网,虚拟机就能上网

3.2、NAT

NAT是一种网络地址转换技术,实现了局域网内的使用自己的本地IP即可联通互联网(NAT会将本地Ip,转换成全球IP)

常见的你家里的wifi,家里按了网线之后会有一个公网ip,但是家里的任何智能设备通过路由器连接上wifi后都能同时上网,因为路由器会分配给设备一个局域网ip,设备使用这个局域网ip上网,其中的转换技术就是NAT技术

image-20200918090414954

有如下特性:

  • 主机能上网,虚拟机就能上网
  • 虚拟机直接可以互通

3.3、Host

Host,仅主机,即它是存在于主机内部的一个虚拟网络。

image-20200918091044530

这仅主机模式下,有一块虚拟网卡,这块网卡的网段和主机上物理网卡的网段是不相同的。

所有的虚拟机在虚拟网卡的网段下,所以他们彼此直接互通。

默认情况下,虚拟机可以访问到物理机,但是默认情况下虚拟机不能上网的。(也可以通过修改配置让他们上互联网)

3.4、内部网络

在内部网络下,虚拟机和外部完全隔断,只允许虚拟机之间才能相互访问

四、Docker0

Docker网络的核心是Docker0

通过ip addr可以看到服务器中如下几块网卡

image-20200917204101504

查看公网ip可以在控制台获取或者执行:curl cip.cc

4.1、小实验1:

Docker中启动Nginx容器,问宿主机能通过容器的ip地址ping通它吗?

# 运行镜像
[root@VM-0-15-centos ~]# docker run -d -P --name nginx1 nginx

# 检查容器是否运行起来了
[root@VM-0-15-centos ~]# docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                   NAMES
962cf239325d        nginx               "/docker-entrypoint.…"   5 seconds ago       Up 3 seconds        0.0.0.0:32768->80/tcp   nginx1

# 进入容器中
[root@VM-0-15-centos ~]# docker exec -it nginx1 /bin/bash

# 查看容器ip地址
root@962cf239325d:/# cat /etc/hosts
127.0.0.1	localhost
::1	localhost ip6-localhost ip6-loopback
fe00::0	ip6-localnet
ff00::0	ip6-mcastprefix
ff02::1	ip6-allnodes
ff02::2	ip6-allrouters
172.17.0.2	962cf239325d

# 退出容器
root@962cf239325d:/# exit
exit

# ping
[root@VM-0-15-centos ~]# ping 172.17.0.2
PING 172.17.0.2 (172.17.0.2) 56(84) bytes of data.
64 bytes from 172.17.0.2: icmp_seq=1 ttl=64 time=0.064 ms
64 bytes from 172.17.0.2: icmp_seq=2 ttl=64 time=0.059 ms
64 bytes from 172.17.0.2: icmp_seq=3 ttl=64 time=0.056 ms
c64 bytes from 172.17.0.2: icmp_seq=4 ttl=64 time=0.058 ms

实验结果很明显:可以ping通

为什么能ping通呢???

查看容器和宿主机网卡的信息就知道了

宿主机中有一块叫Docker0的网卡如下,它的网络段172.17.0.1/16

image-20200917211309301

容器的网卡信息如下:

image-20200917211400404

可以看到这宿主机和容器其实是在同一个网段的~,所以肯定能通!

4.2、小实验2:

如果我宿主机上的容器中同时运行两个容器,问:

这两个容器之间能通过彼此的ip的相互ping通吗?

# 检查两个容器是否都运行起来了
[root@VM-0-15-centos ~]# docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS                     NAMES
d37b518465a0        tomcat              "catalina.sh run"   2 seconds ago       Up 2 seconds        0.0.0.0:32772->8080/tcp   tomcat2
85859d226c8c        f796d3d2c195        "catalina.sh run"   17 minutes ago      Up 17 minutes       0.0.0.0:32771->8080/tcp   tomcat1

# 查看记录tomcat1的ip
[root@VM-0-15-centos ~]# docker exec -it tomcat1 ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    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
184: eth0@if185: <BROADCAST,MULTICAST,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
    link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
       valid_lft forever preferred_lft forever
       
# 查看记录tomcat2的ip
[root@VM-0-15-centos ~]# docker exec -it tomcat2 ip addr
1: lo: <LOOPBACK,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    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
186: eth0@if187: <BROADCAST,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
    link/ether 02:42:ac:11:00:03 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 172.17.0.3/16 brd 172.17.255.255 scope global eth0
       valid_lft forever preferred_lft forever

# 使用tomcat2 ping tomcat1
[root@VM-0-15-centos ~]# docker exec -it tomcat2 ping 172.17.0.2
PING 172.17.0.2 (172.17.0.2) 56(84) bytes of data.
64 bytes from 172.17.0.2: icmp_seq=1 ttl=64 time=0.089 ms
64 bytes from 172.17.0.2: icmp_seq=2 ttl=64 time=0.066 ms
64 bytes from 172.17.0.2: icmp_seq=3 ttl=64 time=0.072 ms
^C
--- 172.17.0.2 ping statistics ---
3 packets transmitted,3 received,0% packet loss,time 1001ms
rtt min/avg/max/mdev = 0.066/0.075/0.089/0.014 ms

# 使用tomcat1 ping tomcat2
[root@VM-0-15-centos ~]# docker exec -it tomcat1 ping 172.17.0.3
PING 172.17.0.3 (172.17.0.3) 56(84) bytes of data.
64 bytes from 172.17.0.3: icmp_seq=1 ttl=64 time=0.069 ms
64 bytes from 172.17.0.3: icmp_seq=2 ttl=64 time=0.061 ms
64 bytes from 172.17.0.3: icmp_seq=3 ttl=64 time=0.070 ms
64 bytes from 172.17.0.3: icmp_seq=4 ttl=64 time=0.070 ms
^C

结论很明显:彼此之间能ping通!

那Docker是怎么做的呢?

我们安装Docker后会带有一个默认的网卡叫做Docker0,它实际上是一个网桥,其中有一端连接在真实的互联网上,使用的的技术是veth-pair桥接技术

此时我的Docker中已经运行了两个容器了,现在去看下宿主机和两个容器的网卡信息。

宿主机:

image-20200917213205238

tomcat1:

image-20200917213244825

tomcat2:

image-20200917213426831

仔细看如上两图中多出来的网卡命名对应关系

# 宿主机多出来的:      185: veth79ccfd1@if184
# 对应容器tomcat1:	  184: eth0@if185

# 宿主机多出来的:      187: vethac83886@if186
# 对应容器tomcat2:	  186: eth0@if187

这种网卡成对对应的关系,就是借助veth-pair技术实现的

veth-pair就是一对虚拟的网络接口,成对出现,一端连着协议,一端彼此相连。由它充当一个桥梁的作用,连接各个Docker 容器,实现网络数据交互

image-20200917215041013

在当前的案例中之间能Ping的

image-20200917222201902

在不指定容器网络的情况下,默认容器使用的Docker0做网桥

通过下面的命令查看使用Docker0的所有Container

image-20200917223906864

image-20200917224026778

Docker会为容器分配一个可用的ip

分配的ip都在上图规定的subnet子网网段下的格式:172.17.0.2/16

在上面划分子网时有提到这种划分的方式,最后的16为它的网络号,也就是说他还有16位的机器号,也就是2的16次方-2个

前面的验证了Docker两个不同的容器可以通过ip直接ping通

--link 可以让我们让两个容器通过服务名直接ping通

# 使用--link这个启动参数,连通不同的容器,实现通过服务名就ping通容器
[root@VM-0-15-centos ~]# docker run -d -P --name tomcat3 --link tomcat2 tomcat
2d8c1363094cd2e09bcd3d3a4e85e0864f32718d38aa4dab9640522c4ea3a87a

# 检查容器是否正常启动了
[root@VM-0-15-centos ~]# docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS                     NAMES
2d8c1363094c        tomcat              "catalina.sh run"   2 seconds ago       Up 2 seconds        0.0.0.0:32773->8080/tcp   tomcat3
d37b518465a0        tomcat              "catalina.sh run"   About an hour ago   Up About an hour    0.0.0.0:32772->8080/tcp   tomcat2
85859d226c8c        f796d3d2c195        "catalina.sh run"   About an hour ago   Up About an hour    0.0.0.0:32771->8080/tcp   tomcat1

# 使用tomcat3ping通tomcat2
[root@VM-0-15-centos ~]# docker exec -it tomcat3 ping tomcat2
PING tomcat2 (172.17.0.3) 56(84) bytes of data.
64 bytes from tomcat2 (172.17.0.3): icmp_seq=1 ttl=64 time=0.093 ms
64 bytes from tomcat2 (172.17.0.3): icmp_seq=2 ttl=64 time=0.068 ms
64 bytes from tomcat2 (172.17.0.3): icmp_seq=3 ttl=64 time=0.069 ms
c64 bytes from tomcat2 (172.17.0.3): icmp_seq=4 ttl=64 time=0.067 ms
^C
--- tomcat2 ping statistics ---
4 packets transmitted,4 received,time 1002ms
rtt min/avg/max/mdev = 0.067/0.074/0.093/0.012 ms

# 反向使用tomcat2 ping tomcat3
[root@VM-0-15-centos ~]# docker exec -it tomcat2 ping tomcat3
ping: tomcat3: Name or service not known

原理:--link实际上是修改了tomcat3的host文件,如下

[root@VM-0-15-centos ~]# docker exec -it tomcat3 cat /etc/hosts
127.0.0.1	localhost
::1	localhost ip6-localhost ip6-loopback
fe00::0	ip6-localnet
ff00::0	ip6-mcastprefix
ff02::1	ip6-allnodes
ff02::2	ip6-allrouters
172.17.0.3	tomcat2 d37b518465a0
172.17.0.4	2d8c1363094c

而tomcat2的host文件中没有这种别名,所以反向通过服务名不能ping通

六、自定义Docker网络

6.1、docker中的网络

查看docker所有的网络:

image-20200918080638181

  • briage:桥接网络(也是默认的网络)。通过Docker0作为网桥,实现容器联网互通
  • host:和宿主机共享网络(使用同一块网卡)
  • none:不配置网络,形成一个全封闭的容器,无法和外网连接
  • container:让一个容器共享另一个容器网络相关的namespace,实现让几个容器内网络互通

6.2、自定义网络

默认网络参数

# 启动容器时我们不添加网络相关启动参数,Docker会为我们补全成下面这样
# 而这里指定的 bridge 就是就是docker0
docker run -d -P --name xxx --net bridge imageId

# --net 指定当前容器启动后加入到哪个网络中

自定义

# 创建自定义网络
# --subnet 192.168.0.0/16 指定了子网网络,可以分配2的16次方-2个ip
# --gateway 192.168.0.1 网关路由器的ip地址
[root@VM-0-5-centos ~]# docker network create --driver bridge --subnet 192.168.0.0/16 --gateway 192.168.0.1 mynet
a8a84221d4a73a2e2eda9f692c74af75cdbdac440e8c7587b56847c61e1dde4c

# 查看是否创建成功了
[root@VM-0-5-centos ~]# docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
a9ff308438a8        bridge              bridge              local
0d98ae518a10        host                host                local
a8a84221d4a7        mynet               bridge              local
cb71d8cdbbca        none                null                local

查看我们自定义的网络详情

image-20200918093535139

查看宿主机网卡信息:可以看到宿主机上多出来了一张虚拟网卡

image-20200918093721195

在自定义的网络中的容器是可以直接通过对方的 容器名 ping通的

七、网络连通

如何让Docker中两个不同网络中的容器互通呢?

image-20200918095046292

见上图,理论上容器1和容器2彼此互通,容器3容器4彼此互通,但是容器12和容器34之间时不互通的,因为他们都不在一个网段中。

具体的作为如下图:

image-20200918095115470

容器2想ping通容器3或者容器4,本质上是需要将容器2加入到mynet 的网络中。

# 使用connect命令,把一个容器连接到一个网络上

# 查看帮助文档
[root@VM-0-5-centos ~]# docker network --help

Usage:	docker network COMMAND

Manage networks

Commands:
  connect     Connect a container to a network
  create      Create a network
  disconnect  Disconnect a container from a network
  inspect     Display detailed information on one or more networks
  ls          List networks
  prune       Remove all unused networks
  rm          Remove one or more networks

Run 'docker network COMMAND --help' for more information on a command.

# 查看connect帮助文档的使用
[root@VM-0-5-centos ~]# docker network connect --help

Usage:	docker network connect [OPTIONS] NETWORK CONTAINER

Connect a container to a network

Options:
      --alias strings           Add network-scoped alias for the container
      --driver-opt strings      driver options for the network
      --ip string               IPv4 address (e.g.,172.30.100.104)
      --ip6 string              IPv6 address (e.g.,2001:db8::33)
      --link list               Add link to another container
      --link-local-ip strings   Add a link-local address for the container

# 将指定容器添加到指定网络
[root@VM-0-5-centos ~]# docker network connect mynet tomcat1

# 检查是否添加成功
[root@VM-0-5-centos ~]# docker inspect mynet
[
    {
        "Name": "mynet","Id": "a8a84221d4a73a2e2eda9f692c74af75cdbdac440e8c7587b56847c61e1dde4c","Created": "2020-09-18T09:30:17.769656045+08:00","Scope": "local","Driver": "bridge","EnableIPv6": false,"IPAM": {
            "Driver": "default","Options": {},"Config": [
                {
                    "Subnet": "192.168.0.0/16","Gateway": "192.168.0.1"
                }
            ]
        },"Internal": false,"Attachable": false,"Ingress": false,"ConfigFrom": {
            "Network": ""
        },"ConfigOnly": false,"Containers": {
            "41976989fbea4138554e131d4067d4eb2bcfb3b6a2491be94af2fd5c64c64256": {
                "Name": "tomcat1","EndpointID": "6894396881ffbbfe0fcf62da1ffcee304218120207f5b5a27f907bb2c306955b","MacAddress": "02:42:c0:a8:00:02","IPv4Address": "192.168.0.2/16","IPv6Address": ""
            }
        },"Labels": {}
    }
]

八、参考:

猿大白:https://www.cnblogs.com/bakari/p/10613710.html

相关文章

最近一直在开发Apworks框架的案例代码,同时也在一起修复Apw...
最近每天都在空闲时间努力编写Apworks框架的案例代码WeText。...
在《Kubernetes中分布式存储Rook-Ceph部署快速演练》文章中,...
最近在项目中有涉及到Kubernetes的分布式存储部分的内容,也...
CentOS下Docker与.netcore(一) 之 安装 CentOS下Docker与.ne...
CentOS下Docker与.netcore(一) 之 安装 CentOS下Docker与.ne...