20221202 Docker 3. 网络

Docker 网络

docker同样有着很多不完善的地方,网络方面就是Docker比较薄弱的部分。

docker安装后会自动创建3种网络:

  • bridge

  • host

  • none

docker network ls

理论部分

docker使用Linux桥接网卡,在宿主机虚拟一个docker容器网桥(docker0),docker启动一个容器时会根据docker网桥的网段分配给容器一个IP地址,称为Container-IP,同时docker网桥是每个容器的默认网关。因为在同一宿主机内的容器都接入同一个网桥,这样容器之间就能够通过容器的Container-IP直接通信。

docker网桥是宿主机虚拟出来的,并不是真实存在的网络设备,外部网络是无法寻址到的,这也意味着外部网络无法通过直接Container-IP访问到容器。如果容器希望外部访问能够访问到,可以通过映射容器端口到宿主主机(端口映射),即 docker run 创建容器时候通过 -p-P 参数来启用,访问容器的时候就通过 [宿主机IP]:[容器端口] 访问容器。

# 使用命令查看docker网络部分
docker info

网络接口的命名

eth0: ethernet的简写,一般用于以太网接口。

wifi0:wifi是无线局域网,因此wifi0一般指无线网络接口。

ath0: Atheros的简写,一般指Atheros芯片所包含的无线网络接口。

lo: local的简写,一般指本地环回接口。

网络模式

Docker网络模式 配置 说明
host --net=host 容器和宿主机共享Network namespace。 容器将不会虚拟出自己的网卡,配置自己的IP 等, 而是使用宿主机的IP和端口。
container --net=container:NAME_or_ID 容器和另外一个容器共享Network namespace。
kubernetes中的pod就是多个容器共享一个 Network namespace。
创建的容器不会创建自己的网卡,配置自己的 IP, 而是和一个指定的容器共享IP、端口范围。
none --net=none 容器有独立的Network namespace,并没有对其进行任何网络设置, 如分配 veth pair 和网桥连接,配置IP等。
该模式关闭了容器的网络功能。
bridge --net=bridge 默认为该模式
此模式会为每一个容器分配、设置IP等, 并将容器连接到一个 docker0 虚拟网桥,通过 docker0 网桥 以及 Iptables nat 表配置与宿主机通信。
Macvlan  network 容器具备Mac地址,使其显示为网络上的物理设备
Overlay (覆盖网络): 利用 VXLAN 实现的bridge模式

bridge 模式(默认)

默认的网络模式。bridge模式下容器没有一个公有 ip ,只有宿主机可以直接访问,外部主机是不可见的,但容器通过宿主机的 NAT 规则后可以访问外网。

Bridge 桥接模式的实现步骤主要如下:

  • Docker Daemon 利用 veth pair 技术,在宿主机上创建两个虚拟网络接口设备,假设为veth0veth1 。而veth pair 技术的特性可以保证无论哪一个 veth 接收到网络报文,都会将报文传输给另一方

  • Docker Daemon 将 veth0 附加到 Docker Daemon 创建的 docker0 网桥上。保证宿主机的网络报文可以发往 veth0

  • Docker Daemon 将 veth1 添加到 Docker Container 所属的 namespace 下,并被改名为 eth0

如此一来,保证宿主机的网络报文若发往 veth0,则立即会被 eth0 接收,实现宿主机到DockerContainer网络的联通性;同时,也保证 Docker Container 单独使用 eth0,实现容器网络环境的隔离性。

注意:veth设备是成双成对出现的,一端是容器内部命名为eth0,一端是加入到网桥并命名的veth(通常命名为veth),它们组成了一个数据传输通道,一端进一端出,veth设备连接了两个网络设备并实现了数据通信

bridge 桥接模式的 缺陷

  1. 最明显的是,该模式下 Docker Container 不具有一个公有 IP,即和宿主机的 eth0 不处于同一个网段。导致的结果是宿主机以外的世界不能直接和容器进行通信。

  2. 虽然 NAT 模式经过中间处理实现了这一点,但是 NAT 模式仍然存在问题与不便,如:容器均需要在宿主机上竞争端口,容器内部服务的访问者需要使用服务发现获知服务的外部端口等。

  3. 另外 NAT 模式由于是在三层网络上的实现手段,故肯定会影响网络的传输效率。

host 模式

相当于Vmware中的NAT模式,与宿主机在同一个网络中,但没有独立IP地址。

如果启动容器的时候使用host模式,那么这个容器将不会获得一个独立的Network Namespace,而是和宿主机共用一个Network Namespace。容器将不会虚拟出自己的网卡,配置自己的IP等,而是使用宿主机的IP和端口。但是,容器的其他方面,如文件系统、进程列表等还是和宿主机隔离的。

使用host模式的容器可以直接使用宿主机的IP地址与外界通信,容器内部的服务端口也可以使用宿主机的端口,不需要进行NAT,host最大的优势就是网络性能比较好,但是docker host上已经使用的端口就不能再用了,网络的隔离性不好。

host网络模式需要在容器创建时指定 --network=host

host 模式是 bridge 桥接模式很好的补充。采用 host 模式的 Docker Container,可以直接使用宿主机的 IP地址与外界进行通信,若宿主机的 eth0 是一个公有 IP,那么容器也拥有这个公有IP。同时容器内服务的端口也可以使用宿主机的端口,无需额外进行 NAT 转换。

Host 网络模式的 缺陷

  • 最明显的是 Docker Container 网络环境隔离性的弱化。即容器不再拥有隔离、独立的网络环境。另外,使用 host 模式的 Docker Container 虽然可以让容器内部的服务和传统情况无差别、无改造的使用,但是由于网络隔离性的弱化,该容器会与宿主机共享竞争网络栈的使用;

  • 另外,容器内部将不再拥有所有的端口资源,原因是部分端口资源已经被宿主机本身的服务占用,还有部分端口已经用以 bridge 网络模式容器的端口映射。

container 模式

一种特殊 host 网络模式

Container 网络模式是 Docker 中一种较为特别的网络的模式。在容器创建时使用 --network=container:vm1 指定( vm1指定的是运行的容器名)

这个模式指定新创建的容器和已经存在的一个容器共享一个 Network Namespace,而不是和宿主机共享。

新创建的容器不会创建自己的网卡,配置自己的 IP,而是和一个指定的容器共享 IP、端口范围等。同样,两个容器除了网络方面,其他的如文件系统、进程列表等还是隔离的。两个容器的进程可以通过 lo 网卡设备通信。

优势:处于这个模式下的 Docker 容器会共享一个网络环境,这样两个容器之间可以使用 localhost 高效快速通信。

缺陷:它并没有改善容器与宿主机以外世界通信的情况(和桥接模式一样,不能连接宿主机以外的其他设备)。

none 模式

使用none模式,Docker容器拥有自己的Network Namespace,但是,并不为Docker容器进行任何网络配置。也就是说,这个Docker容器没有网卡、IP、路由等信息。需要我们自己为Docker容器添加网卡、配置IP等。

这种网络模式下容器只有lo回环网络,没有其他网卡。none模式可以在容器创建时通过 --network=none 来指定。这种类型的网络没有办法联网,封闭的网络能很好的保证容器的安全性。

overlay 模式

Overlay 网络,也称为覆盖网络。主要用于 Docker 集群部署

Overlay 网络的实现方式和方案有多种。Docker 自身集成了一种,基于 VXLAN 隧道技术实现。

Overlay 网络主要用于实现跨主机容器之间的通信。

应用场景:需要管理成百上千个跨主机的容器集群的网络时

macvlan 模式

macvlan网络模式,最主要的特征就是他们的通信会直接基于mac地址进行转发。

这时宿主机其实充当一个二层交换机。Docker会维护着一个MAC地址表,当宿主机网络收到一个数据包后,直接根据mac地址找到对应的容器,再把数据交给对应的容器。

容器之间可以直接通过IP互通,通过宿主机上内建的虚拟网络设备(创建macvlan网络时自动创建),但与主机无法直接利用IP互通。

应用场景:由于每个外来的数据包的目的mac地址就是容器的mac地址,这时每个容器对于外面网络来说就相当于一个真实的物理网络设备。因此当需要让容器来的网络看起来是一个真实的物理机时,使用macvlan模式

Macvlan是一个新的尝试,是真正的网络虚拟化技术的转折点。Linux实现非常轻量级,因为与传统的Linux Bridge隔离相比,它们只是简单地与一个Linux以太网接口或子接口相关联,以实现网络之间的分离和与物理网络的连接。

Macvlan提供了许多独特的功能,并有充足的空间进一步创新与各种模式。这些方法的两个高级优点是绕过Linux网桥的正面性能以及移动部件少的简单性。删除传统上驻留在Docker主机NIC和容器接口之间的网桥留下了一个非常简单的设置,包括容器接口,直接连接到Docker主机接口。由于在这些情况下没有端口映射,因此可以轻松访问外部服务。

Macvlan Bridge模式每个容器都有唯一的MAC地址,用于跟踪Docker主机的MAC到端口映射。Macvlan驱动程序网络连接到父Docker主机接口。示例是物理接口,例如eth0,用于802.1q VLAN标记的子接口eth0.10(.10代表VLAN 10)或甚至绑定的主机适配器,将两个以太网接口捆绑为单个逻辑接口。 指定的网关由网络基础设施提供的主机外部。 每个Macvlan Bridge模式的Docker网络彼此隔离,一次只能有一个网络连接到父节点。

每个主机适配器有一个理论限制,每个主机适配器可以连接一个Docker网络。 同一子网内的任何容器都

可以与没有网关的同一网络中的任何其他容器进行通信macvlan bridge。 相同的docker network命令

适用于vlan驱动程序。 在Macvlan模式下,在两个网络/子网之间没有外部进程路由的情况下,单独网络

上的容器无法互相访问。这也适用于同一码头网络内的多个子网

操作实例

基础镜像

# 拉取镜像
docker pull nginx:1.19.3-alpine

# 备份镜像
docker save nginx:1.19.3-alpine -o nginx.1.19.3.alpine.tar

# 导入镜像
docker load -i nginx.1.19.3.alpine.tar

bridge 网络

bridge网络表现形式就是 docker0 这个网络接口。容器默认都是通过 docker0 这个接口进行通信。也可以通过 docker0 去和本机的以太网接口连接,这样容器内部才能访问互联网。

查看docker0网络,在默认环境中,一个名为docker0的linux bridge自动被创建好了,其上有一个docker0 内部接口

# 查看docker0网络
ip a
# 查看 docker 网络
docker network ls

# 查看 bridge 网络详情。主要关注 Containers 节点信息。
docker network inspect bridge
docker0 详解
# 运行镜像
docker run -itd --name nginx1 nginx:1.19.3-alpine

# 查看bridge网络详情。
# 主要关注Containers节点信息。发现nginx1容器默认使用bridge网络
docker network inspect bridge
# 查看主机网络,发现多出一块网卡 veth4748026@if108086
ip a

3: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
    link/ether 02:42:08:df:1e:cd brd ff:ff:ff:ff:ff:ff
    inet 192.168.10.1/24 brd 192.168.10.255 scope global docker0
       valid_lft forever preferred_lft forever
    inet6 fe80::42:8ff:fedf:1ecd/64 scope link 
       valid_lft forever preferred_lft forever
108087: veth4748026@if108086: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default 
    link/ether 86:9d:51:2b:c7:4c brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet6 fe80::849d:51ff:fe2b:c74c/64 scope link 
       valid_lft forever preferred_lft forever

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

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

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

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

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

完成这些之后,容器就可以使用 eth0 虚拟网卡来连接其他容器和其他网络。

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

# 第一种方式:
docker exec -it nginx1 sh
ip a

# 第二种方式:
docker exec -it nginx1 ip a
# 安装brctl
yum install -y bridge-utils

[root@VM-72-146-centos ~]# brctl show
bridge name     bridge id               STP enabled     interfaces
docker0         8000.024208df1ecd       no              veth4748026

多容器之间通讯
# 启动两个容器
docker run -itd --name nginx1 nginx:1.19.3-alpine
docker run -itd --name nginx2 nginx:1.19.3-alpine

# 网络查看,可知到容器的 IP 地址
docker network inspect bridge

# 容器间 ping
docker exec -it nginx1 ping 192.168.10.3
容器IP地址会发生变化
# 停止容器
docker stop nginx1 nginx2

# 先启动nginx2,再启动nginx1
docker start nginx2
docker start nginx1

# 网络查看
docker network inspect bridge
link容器

docker run命令的link参数

  • --link=[]:添加链接到另一个容器;不推荐使用该参数

使用link的场景:在企业开发环境中,我们有一个mysql的服务的容器mysql_1,还有一个web应用程序 web_1,肯定web_1这台容器肯定要连接mysql_1这个数据库。前面网络命名空间的知识告诉我们,两个容器需要能通信,需要知道对方的具体的IP地址。生产环境还比较好,IP地址很少变化,但是在我们内部测试环境,容器部署的IP地址是可能不断变化的,所以,开发人员不能在代码中写死数据库的IP地址。这个时候,我们就可以利用容器之间link来解决这个问题。

下面,我们来介绍如何通过容器名称来进行ping,而不是通过IP地址。

docker run -itd --name nginx1 nginx:1.19.3-alpine
docker run -itd --name nginx2 --link nginx1 nginx:1.19.3-alpine

docker exec -it nginx2 ping nginx1
# 可以 ping 通
  • 上面link命令,是在nginx2容器启动时link到nginx1容器,因此,在nginx2容器里面可以ping通nginx1容器名,link的作用相当于添加了DNS解析。这里提醒下,在nginx1容器里去ping nginx2容器是不通的,因为link关系是单向的,不可逆。

  • 实际工作中,docker官网已经不推荐我们使用link参数。

  • docker用其他方式替换掉link参数,如下

新建 bridge 网络
docker network create -d bridge lagou-bridge

参数 -d 是指 DRIVER 的类型,后面的 lagou-bridge 是network的自定义名称,这个和docker0 是类似的。

把容器连接到lagou-bridge这个网络:

启动一个nginx的容器nginx3,并通过参数network connect来连接lagou-bridge网络。在启动容器nginx3之前,我们查看目前还没有容器连接到了lagou-bridge这个网络上。

ip a    # 多了一个 br-e008eb1ee544
brctl show        # 多了一个 br-e008eb1ee544
docker network ls    # 多了一个 lagou-bridge
docker network inspect lagou-bridge

docker run -itd --name nginx3 --network lagou-bridge nginx:1.19.3-alpine
brctl show
docker network inspect lagou-bridge

把一个运行中容器连接到lagou-bridge网络:

docker network connect lagou-bridge nginx2
docker network inspect lagou-bridge
docker exec -it nginx2 ping nginx3    # 可以ping通
docker exec -it nginx3 ping nginx2    # 可以ping通

host 网络

# 清理所有容器
docker rm $(docker stop $(docker ps -aq))

# 运行容器
docker run -itd --name nginx2 --network host nginx:1.19.3-alpine

# 网络查看
docker network inspect host    # 多了nginx2,不显示IP地址
docker exec -it nginx2 ip a    # 和在主机执行 ip a 结果相同

容器使用了host模式,说明容器和外层linux主机共享一套网络接口。

VMware公司的虚拟机管理软件,其中网络设置,也有host这个模式,作用也是一样,虚拟机里面使用网络和你自己外层机器是一模一样的。

这种容器和本机使用共享一套网络接口,缺点还是很明显的,例如我们知道web服务器一般端口是80,共享了一套网络接口,那么你这台机器上只能启动一个nginx端口为80的服务器了。否则,出现端口被占用的情况。

none 网络

使用none模式,这个容器是不能被其他容器访问。这种使用场景很少,只有项目安全性很高的功能才能使用到。例如:密码加密算法容器

# 清理所有容器
docker rm $(docker stop $(docker ps -aq))

# 删除网络
docker network rm lagou-bridge
docker network inspect none    # Containers 为空
docker run -itd --name nginx1 --network none nginx:1.19.3-alpine
docker network inspect none    # Containers 多了一个 nginx1,不显示IP地址
docker exec -it nginx1 ip a    # 只有一个lo接口

网络命令汇总

docker network --help

# 网络常用命令汇总
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

ls

查看网络

默认情况下,docker安装完成后,会自动创建bridge、host、none三种网络驱动

docker network ls [OPTIONS]
  • -f, --filter filter :过滤条件(如 'driver=bridge’)

  • --format string :格式化打印结果

  • --no-trunc :不缩略显示

  • -q, --quiet :只显示网络对象的ID

docker network ls
docker network ls --no-trunc
docker network ls -f 'driver=host'

create

创建网络

host和none模式网络只能存在一个

docker自带的overlay 网络创建依赖于docker swarm(集群负载均衡)服务

docker network create [OPTIONS] NETWORK
  • -d, --driver string: 指定网络的驱动(默认 "bridge")

  • --subnet strings: 指定子网网段(如192.168.0.0/16、172.88.0.0/24)

  • --ip-range strings: 执行容器的IP范围,格式同subnet参数

  • --gateway strings: 子网的IPv4 or IPv6网关,如(192.168.0.1)

172.88.0.0/24 表示前24位是网络前缀,后8位是主机号,子码掩码是255.255.255.0,包含 IP:172.88.0.0 ~ 172.88.0.255

192.168.0.0/16 包含 IP:192.168.0.0 ~ 192.168.255.255

docker network ls
docker network create -d bridge my-bridge
docker network ls

rm

网络删除

docker network rm NETWORK [NETWORK...]

inspect

查看网络详细信息

docker network inspect [OPTIONS] NETWORK [NETWORK...]
或
docker inspect [OPTIONS] NETWORK [NETWORK...]
  • -f, --format string :根据format输出结果

run

使用网络,为启动的容器指定网络模式

默认情况下,docker创建或启动容器时,会默认使用名为bridge的网络

docker run/create --network NETWORK

connect、disconnect

网络连接与断开

docker network connect [OPTIONS] NETWORK CONTAINER
docker network disconnect [OPTIONS] NETWORK CONTAINER
  • -f, --force :强制断开连接(用于 disconnect)

练习示例

# 创建网络
docker network create -d bridge --subnet=172.172.0.0/24 --gateway 172.172.0.1 lagou-network
# 172.172.0.0/24: 24代表网络前缀,子码掩码是255.255.255.0

docker network ls
docker run -itd --name nginx3 -p 80:80 --net lagou-network --ip 172.172.0.10 nginx:1.19.3-alpine
# --net mynetwork: 选择存在的网络
# --ip 172.172.0.10: 给nginx分配固定的IP地址

# 查看ip是否变化
docker network inspect lagou-network
docker restart nginx3
docker network inspect lagou-network
posted @ 2022-12-03 20:06  流星<。)#)))≦  阅读(47)  评论(0编辑  收藏  举报