# Docker 默认网桥

安装 Docker 服务会默认创建一个 docker0 网桥,它在内核层连通了其他的物理或虚拟网卡,这就将所有容器和本地主机都放到同一个物理网络

容器有三种网络类型,分别是 bridge , host , none ,创建容器时默认是 bridge 。我们可以使用命令查看

docker network ls

先创建一个容器再来讲解

docker run -it ubuntu
apt update
apt install net-tools iputils-ping curl

可以看到这个容器的 IP172.17.0.3 。该 ubuntu 容器启动时没有指定网络类型,默认就是 bridge ,我们看一下 bridge 的网络

cyan@w2d:~$ docker network inspect bridge

看关键部分

"Config": [
    {
        "Subnet": "172.17.0.0/16",
        "Gateway": "172.17.0.1"
    }
]

我的终端倒是没有显示 Gateway 网关,这个其实就是 docker0 的 IP,我们创建的容器默认就是通过 docker0 桥接宿主机的网络。

# 创建容器

Docker 在创建一个容器的时候,会执行如下操作:

  • 创建一对虚拟接口 / 网卡,也就是 veth pair,分别放到本地主机和新容器中;

  • 本地主机一端桥接到默认的 docker0 或指定网桥上,并具有一个唯一的名字,如 vethxxxxx;

  • 容器一端放到新容器中,并修改名字作为 eth0,这个网卡 / 接口只在容器的名字空间可见;

  • 从网桥可用地址段中(也就是与该 bridge 对应的 network)获取一个空闲地址分配给容器的 eth0,并配置默认路由到桥接网卡 vethxxxx。

如果不指定 --network,创建的容器默认都会挂到 docker0 上,使用本地主机上 docker0 接口的 IP 作为所有容器的默认网关

# 网络类型

# 默认网络类型

之前使用 docker network ls 查看三种网络类型,有 bridgehostnone 。,使用 --network 可以指定网络

docker run -it --network=none ubuntu
  • none 网络:只有一个本地环回网络,通过 ifconfig 查看,只有一个本地环回 lo 网络设备:

在这种网络模式下,容器无法连接到互联网:比如, ping 不通,纯纯单机运行。

  • bridger 网络:容器默认使用的网络类型,上文我们已经讲了,此处不再赘述。
  • host 网络:当容器连接到此网络,会共享宿主主机的网络,网络配置是完全一样。

# 自定义网络类型

Docker 默认提供三种网络驱动: bridgeoverlaymacvlan ,不同的驱动对应着不同的网络设备驱动,实现的功能也不一样,比如 bridge 类型的,其实就和我们前面介绍的桥接网络是一样的。

docker network create --driver bridge test

这就是本文最开始的 ifconfig 多显示了一个网络设备,不同网络之间的通信是相互隔离的,无法进行通信,比如我们有一个在默认网络类型的 ubuntu 容器,有一个在 test 网络下的 ubuntu 容器,后者的网关是 172.18.0.1 ,容器 IP 为 172.18.0.2 ,在前者中想要执行命令:

ping 172.18.0.2

会失败,想要实现通信,需要将前者连接到另一个容器所属的网络下:

docker network connect test(网络类型) 容器ID/名称

此时容器就可以互相通信。Docker 的 DNS 服务器可以不需要指定容器 IP,比如有两个可以互相通信的容器,在启动时分别用 --name 指定名称,通信时就可以使用名称而不是 IP(就像有一个 DNS 一样将名字解析成 IP)

两个容器也可以共享一个网络设备,即两个容器共同使用一个 IP 地址,只需要在创建时指定:

docker run -it --name=test02 --network=container:test02 ubuntu

两个容器的 IP 地址和网卡的 Mac 地址是完全一样的,它们的网络现在是共享状态,此时在容器中访问,localhost,既是自己也是别人。

可以在容器 1 中,安装 Nginx,然后再容器 2 中访问:

apt install -y systemctl nginx
 systemctl start nginx

访问到另一个容器中的 Nginx 服务器。

另外两种类型的网络用于多主机通信,多主机通信会使用物理交换机,不同主机的网卡连接到同一台交换机,就相当于各自网桥在同一物理网络了。

# 容器外部网络

在默认的三种的网络下,只有共享模式和桥接模式可以连接到外网,共享模式实际上就是直接使用宿主主机的网络设备连接到互联网,这里主要来看一下桥接模式。

桥接模式容器发送数据包时,关键部分就是 NAT (Netwirk Address Translation),将地址进行转换,再利用宿主主机的 IP 地址发送数据包出去。

比如我们要访问互联网上的某个资源,要和服务器进行通信,那么就需要将数据包发送出去,同时服务器也要将数据包发送回来,我们可以知道服务器的 IP 地址,也可以直接去连接,因为服务器的 IP 地址是暴露在互联网上的,但是我们的局域网就不一样了,它仅仅局限在我们的家里,比如我们连接了家里的路由器,可以得到一个 IP 地址,但是你会发现,这个 IP 公网是无法直接访问到我们的,因为这个 IP 地址仅仅是一个局域网的 IP 地址,俗称内网 IP。

这里就借助了 NAT 在帮助我们与互联网上的服务器进行通信,通过 NAT,可以实现将局域网的 IP 地址,映射为对应的公网 IP 地址,而 NAT 设备一端连接外网,另一端连接内网的所有设备,当我们想要与外网进行通信时,就可以将数据包发送给 NAT 设备,由它来将数据包的源地址映射为它在外网上的地址,这样服务器就能够发现它了,能够直接与它建立通信。当服务器发送数据回来时,也是直接交给 NAT 设备,然后再根据地址映射,转发给对应的内网设备(当然由于公网 IP 地址有限,所以一般采用 IP + 端口结合使用的形式 ANPT)。

用百度查出来的 IP 和在命令行使用 ipconfig(windows) 查出来的不一样,前者是 NAT 设备的公网地址。

Docker 中,内网数据包想要发送到互联网上的流程为:

单纯依靠 NAT,只有主动与外界联系时,外界才知道我们。但是如果容器中部署了一些服务,需要外界主动连接容器的服务,就需要使用端口映射配置。

外界连接,只知道 linux 的 IP 而不知道容器的 IP,就需要通过端口映射访问。端口映射可以将容器需要对外提供服务的端口映射到宿主主机的端口上,这样,当外部访问到宿主主机的对应端口时,就会直接转发给容器内映射的端口了。

# 先部署一个 nginx 服务
docker run -d -p 80:80 nginx

-p 参数是进行端口映射配置,规则为 宿主端口:容器端口 ,其实关于端口映射之前的文章已经讲过了。

然后在浏览器中输入: Linux IP:80 即可访问 nignx 服务。

# 参考

https://pdai.tech/md/devops/docker/docker-07-network.html

https://www.yuque.com/qingkongxiaguang/zwhkpi/kq6rlg#67fb97ea

https://www.it1352.com/2052892.html