Docker网络概念
网络驱动
Docker 网络子系统使用可插拔的驱动,默认情况下有多个驱动程序,并提供核心联网功能。
- bridge:桥接网络,这是默认的网络驱动程序(不指定驱动程序创建的容器默认是bridge驱动)。
- host:主机网络。消除容器和主机的网络隔离,直接使用主机的网络。
- overlay:覆盖网络。可以将多个Docker守护进程连接,实现跨主机容器通讯(swarm集群)。
- macvlan:将MAC地址分配给容器,使容器作为网络上的物理设备。不通过Docker主机网络栈进行路由,直接通过MAC地址路由到容器。
- none:表示关闭容器的所有网络连接。常与自定义网络驱动一起使用,不适用于swarm。
- 网络插件:可以通过Docker安装和使用第三方网络插件。
Docker网络驱动选用原则
- bridge桥接网络:最适合用于同一个Docker主机上运行的多个容器之间需要通信的场景。(单主机)
- host主机网络:最适用于当网络栈不能与Docker主机隔离,而容器的其他方面需要被隔离的场景。(解除容器和主机隔离)
- overlay网络:适用于不同Docker主机上运行的容器需要通信的场景,或者多个应用程序通过Swarm集群服务一起工作的场景。(多主机、集群)
- macvlan网络:适用于从虚拟机迁移过来的场景,或者容器需要像网络上的物理机一样,拥有独立MAC地址的场景。(容器需要mac)
- 第三方网络插件适用于将Docker与专用网络栈进行集成的场景。(订制化)
容器的网络模式
bridge模式
桥接网络分为默认桥接网络和用户自定义桥接网络两种类型。
桥接网络用于同(单)主机运行的容器间通信。
实现原理:桥接网络使用软件网桥,让连接到同一桥接网络的容器可以通信,没连接该网桥的容器被隔离。
工作流程:Docker守护进程启动,会在主机上创建一个名为 docker0
的虚拟网桥,启动容器时如果没有特别指定,自动连接到这个虚拟网桥。
[root@localhost ~]# ifconfig
docker0: flags=4099<UP,BROADCAST,MULTICAST> mtu 1500
inet 172.17.0.1 netmask 255.255.0.0 broadcast 172.17.255.255
ether 02:42:b2:81:22:9d txqueuelen 0 (Ethernet)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
Docker 守护进程为每个启动的容器创建一个 VETH对设备(总是成对出现,组成数据通道)。
VETH对是直接连接的一对虚拟网络接口,一个接口设置为新创建容器的接口(位于容器的网络名称空间中);另一个接口连接到虚拟网桥docker0(位于Docker的网络名称空间中)。
host模式
host模式的容器使用host驱动,直接连接Docker主机网络栈。实质:关闭 Docker 网络,让容器直接使用主机操作系统的网络。
host模式没有为容器创建一个隔离的网络环境,容器没有隔离的网络名称空间,也不会获得一个独立的网络名称空间,而是和Docker主机共用一个网络名称空间。
容器和主机在同一个网络中,使用主机的物理网络接口,没有独立的IP地址,直接使用主机的IP地址和端口。
由于主机名、地址都一样,因此同一主机上的容器要做好协调。各容器通过端口来进行区分。
container模式
Docker中一种较为特别的网络模式,主要用于容器和容器直接频繁交流的情况。
特点:
- 该模式指定新建的容器和现有的一个容器共享网络名称空间。
- 新创建的容器和一个现有的指定容器共享IP地址、端口范围,不创建自己的网络接口、IP地址。
- 两个容器间网络不隔离,进程可通过回环网络进行通信。
- 这两个容器和主机和其他容器存在网络隔离。
none模式
none模式将容器放置在它自己的网络栈中,但是并不进行任何配置,实际上关闭了容器的网络功能。
特性:none模式,容器有自己的网络名称空间,但未进行任何网络配置,未构建任何网络环境,容器内部只能使用回环网络接口(127.0.0.1)。
可用场景:
- 有些容器并不需要网络,例如只需要写入磁盘卷的批处理任务。
- 安全性要求高并且不需要联网的应用可以使用none模式。
- 要创建自定义网络。
自定义模式
管理员可以使用Docker网络驱动(bridge、overlay、macvlan)或第三方网络驱动插件创建一个自定义的网络,然后将多个容器连接到同一个自定义网络。
特点:
- 连接到用户自定义网络的容器,可以使用IP地址或名称相互通信。
- 可以根据需要创建任意数量的自定义网络。
- 可以在任何时间将容器连接到这些网络。
- 对运行中的容器,可连接、断开自定义网络,无须重启容器。
用户自定义桥接网络(自定义网络使用bridge网络驱动):单机环境常用。生产环境推荐使用。
生产环境不推荐使用默认桥接网络,推荐使用用户自定义桥接网络,原因在以下区别:
- 用户自定义桥接网络能提供容器化应用程序之间更好的隔离和互操作性。如果在默认桥接网络上运行应用栈,则Docker主机需要通过其他方式来限制对端口的访问。
- 用户自定义桥接网络提供容器之间自动DNS解析功能,可以通过名称或别名互相访问。而默认桥接网络上的容器只能通过IP地址互相访问。
- 容器可以在运行时与用户自定义网络连接和断开。要断开与默认桥接网络的连接,需要停止容器并使用不同的网络选项重新创建该容器。
- 每个用户可通过自定义网络创建一个可配置的网桥。而默认桥接网络会自动穿件一个名为docker0的虚拟网桥。
- 用户自定义网络中所连接容器不能共享环境变量,不过有更好的方式实现共享环境变量(docker卷挂载、compose文件定义、集群)。默认桥接网络中所连接的容器共享环境变量。
传统容器连接
创建容器时使用–link选项可以在容器之间建立连接,这是Docker传统的容器互联解决方案。
特性:
- 这种连接方式用来将多个容器连接在一起,并在容器之间发送连接信息。
- 当容器被连接时,在源容器和 接收容器 之间建立一个
安全通道
,关于源容器的信息能够被发送到接收容器,让接收容器可以访问源容器所指定的数据。
为容器设置自定义名称的好处:
- 表示特定用途的名称更易记忆,如将一个Web应用的容器命名为web。
- 便于Docker通过该名称引用其他容器,弥补默认桥接网络不支持容器名称解析的不足
# 语法
[root@localhost ~]# docker create --help
Usage: docker create [OPTIONS] IMAGE [COMMAND] [ARG...]
Create a new container
Options:
--link list Add link to another container # 添加连接到另一个容器
# 案例
# 创建容器时,添加到第一个容器的连接,并配置别名alp
docker run -dit --name alpine2 --link alpine1:alp alpine ash
容器访问外部网络
默认情况下,容器可以主动访问到外部网络的连接,但是外部网络无法访问到容器。
使用bridge模式(默认桥接网络)的容器通过NAT方式实现外部访问,具体通过iptables(Linux的包过滤防火墙)的源地址伪装操作实现。
iptables源地址伪装:容器所有到外部网络的连接,源地址都会被 NAT 成本地系统的 IP 地址(即docker0地址)。
查看主机的 NAT 规则:
[root@localhost ~]# iptables -t nat -vnL
Chain PREROUTING (policy ACCEPT 142 packets, 31842 bytes)
pkts bytes target prot opt in out source destination
1 52 DOCKER all -- * * 0.0.0.0/0 0.0.0.0/0 ADDRTYPE match dst-type LOCAL
Chain INPUT (policy ACCEPT 140 packets, 31384 bytes)
pkts bytes target prot opt in out source destination
Chain OUTPUT (policy ACCEPT 4 packets, 288 bytes)
pkts bytes target prot opt in out source destination
0 0 DOCKER all -- * * 0.0.0.0/0 !127.0.0.0/8 ADDRTYPE match dst-type LOCAL
Chain POSTROUTING (policy ACCEPT 4 packets, 288 bytes)
pkts bytes target prot opt in out source destination
0 0 MASQUERADE all -- * !docker0 172.17.0.0/16 0.0.0.0/0 《————这一条规则将所有源地址在 172.17.0.0/16 网段,目标地址为其他网段(外部网络)的流量动态伪装为从系统网卡发出。
MASQUERADE 相比传统 SNAT 的好处是它能动态从网卡获取地址。
Chain DOCKER (2 references)
pkts bytes target prot opt in out source destination
0 0 RETURN all -- docker0 * 0.0.0.0/0 0.0.0.0/0
容器网络配置
设置容器网络连接
容器启动时,可以使用 --network
选项设置容器要连接的网络,即网络模式。
none:容器为none模式,容器不使用任何网络连接,能完全禁用网络连接。
bridge:容器为bridge模式,连接到默认桥接网络,也是默认设置。
host:容器为host模式,使用主机网络栈。
container:容器为container模式,容器使用某一个容器(通过id或name来标识)的网络栈。
网络名or网络id:容器连接自定义网络,可使用自定义网络的名称或id。
# 语法
[root@localhost ~]# docker run --help
Usage: docker run [OPTIONS] IMAGE [COMMAND] [ARG...]
--network network Connect a container to a network # 连接容器到网络中
# 案例
[root@localhost ~]# docker network ls
NETWORK ID NAME DRIVER SCOPE
9b3f5f5076b9 bridge bridge local
76d9e06a3606 host host local
9f44873071f4 none null local
[root@localhost ~]# docker run --network none -dit --name centos-test centos /bin/bash
24110a1ca4da0f6d7659d7d2e8a1f57a8d980031ab54ac4730a3b89e44679e46
[root@localhost ~]# docker inspect --format='{
{json .HostConfig.NetworkMode}}' 24110a1ca4da
"none"
容器添加网络作用域别名
容器在网络作用域中允许有别名,别名在所在网络中可以直接访问。使用 --network-alias
选项指定容器在网络中的别名。
注意:网络作用域别名只支持用户自定义的网络。
# 语法
[root@localhost ~]# docker run --help
Usage: docker run [OPTIONS] IMAGE [COMMAND] [ARG...]
--network-alias list Add network-scoped alias for the container # 给容器添加网络作用域别名
# 失败案例
[root@localhost ~]# docker run -d -p 80:80 --name testweb --network host --network-alias websrv centos
docker: network-scoped aliases are only supported for user-defined networks. # 网络作用域别名只支持用户自定义的网络
# 案例
[root@localhost ~]# docker network create --driver bridge mynet
a7b402ee062eaf27c50fb303ae6e764f384cd7b2ebd0acf61fdeeba68bddb5f6
[root@localhost ~]# docker network ls
NETWORK ID NAME DRIVER SCOPE
9b3f5f5076b9 bridge bridge local
76d9e06a3606 host host local
a7b402ee062e mynet bridge local
9f44873071f4 none null local
[root@localhost ~]# docker run -d -p 80:80 --name testweb --network mynet --network-alias websrv centos
0630c88e381c805fb9176bf682dfdca5f541d3104364a238a5b4045ca5a7a014
设置容器ip
使用--network
选项启动容器连接自定义网络时,可以使用 --ip
或 --ip6
选项明确指定分配给该网络容器的ip地址。
使用前面创建的mynet,创建新容器指定ip时报错:Error response from daemon: user specified IP address is supported only when connecting to networks with user configured subnets.
注意:仅当连接到具有用户配置的子网的网络时,才支持用户指定的IP地址。
# 语法
[root@localhost ~]# docker run --help
Usage: docker run [OPTIONS] IMAGE [COMMAND] [ARG...]
--ip string IPv4 address (e.g., 172.30.100.104)
--ip6 string IPv6 address (e.g., 2001:db8::33)
# 案例
[root@localhost ~]# docker network create --driver bridge --subnet 172.19.1.0/24 --gateway 172.19.1.1 mynet02
97f9b61b3a30228b714781bfca5c0b6fe2bb140bdb6520eb87f706016707f2d9
[root@localhost ~]# docker network inspect mynet02
[
{
"Name": "mynet02",
"Id": "97f9b61b3a30228b714781bfca5c0b6fe2bb140bdb6520eb87f706016707f2d9",
"Created": "2022-04-13T17:15:12.435135856+08:00",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": {
},
"Config": [
{
"Subnet": "172.19.1.0/24",
"Gateway": "172.19.1.1"
}
]
},
"Internal": false,
"Attachable": false,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
"Containers": {
},
"Options":