1. 网络概述
Docker容器和服务如此强大的原因之一是你可以将它们连接在一起,或将它们连接到非Docker工作负载。Docker容器和服务甚至不需要知道它们已部署在Docker上,也不必知道它们的对等对象是否也是Docker工作负载。无论您的Docker主机运行Linux,Windows还是两者结合,您都可以使用Docker以与平台无关的方式管理它们。
本主题定义了一些基本的 Docker 网络概念,并帮助您设计和部署应用程序以充分利用这些功能
这些内容大多适用于所有的 Docker 安装。 然而,一些高级功能仅适用于Docker 企业版客户。
1.1 网络驱动
Docker的网络子系统可使用驱动程序插拔式接入。默认情况下,有几个驱动程序,它们提供核心联网功能:
bridge
:网桥网络
默认的网络驱动程序。如果您没有指定驱动程序,那么这就是您正在创建的网络类型。桥接网络通常在应用程序运行在需要通信的独立容器中时使用。host
:主机网络
对于独立容器,请删除容器与Docker主机之间的网络隔离,然后直接使用主机的网络。host 仅可用于Docker 17.06及更高版本上的集群服务。overlay
:覆盖网络
将多个 Docker 守护进程连接在一起,使群服务能够相互通信。 您还可以使用覆盖网络来促进群服务和独立容器之间的通信,或者在不同的 Docker 守护进程上的两个独立容器之间的通信。 这种策略消除了在这些容器之间执行操作系统级路由的需要。macvlan
:Macvlan网络
网络允许你为容器分配 MAC 地址,使它看起来像是你网络上的一个物理设备。 Docker 守护进程通过容器的 MAC 地址将流量路由到容器。 在处理希望直接连接到物理网络的遗留应用程序时,使用 macvlan 驱动程序有时是最佳选择,而不是通过 Docker 主机的网络栈进行路由。none
:对于此容器,禁用所有联网。通常与自定义网络驱动程序一起使用。none不适用于群体服务。请参阅 禁用容器联网。网络插件
:您可以在Docker上安装和使用第三方网络插件。这些插件可从 Docker Hub 或第三方供应商处获得。有关安装和使用给定网络插件的信息,请参阅供应商的文档。
网络驱动程序摘要
- 当您需要多个容器在同一Docker主机上进行通信时,最好使用用户定义的
网桥网络
。 - 当网络堆栈不应与Docker主机隔离时,但您希望容器的其他方面隔离时,
主机网络
是最佳选择。 - 当您需要在不同Docker主机上运行的容器进行通信时,或者当多个应用程序使用集群服务一起工作时,
覆盖网络
是最好的。 - 从VM设置迁移或需要容器看起来像网络上的物理主机(每个主机都有唯一的MAC地址)时,
Macvlan网络
是最好的。 - 第三方网络插件使您可以将Docker与专用网络堆栈集成。
1.2 Docker EE网络功能
以下两个功能仅在使用Docker 企业版和使用通用控制平面(UCP)管理Docker服务时才可用:
HTTP路由网格
可以让你分享多个服务之间的相同的网络IP地址和端口。根据客户端的请求,UCP使用主机名和端口的组合将流量路由到适当的服务。会话粘性
使您可以在HTTP标头中指定UCP用于需要状态会话的应用程序将后续请求路由到同一服务任务的信息。
2. 容器网络
容器使用的网络类型,无论是桥接、覆盖、 macvlan 网络还是定制网络插件,都是从容器内部透明的。 从容器的角度来看,它有一个具有 IP 地址、网关、路由表、 DNS 服务和其他网络详细信息的网络接口(假设容器没有使用 none 网络驱动程序)。
2.1 发布端口
默认情况下,当您创建一个容器时,它不会向外部世界发布它的任何端口。 若要使一个端口可用于 Docker 以外的服务,或未连接到容器网络的 Docker 容器,请使用 – publish 或-p 标志。 这将创建一个防火墙规则,该规则将容器端口映射到 Docker 主机上的端口。 下面是一些例子。
标志值 | 描述 |
---|---|
-p 8080:80 | 将容器中的 TCP 端口80映射到 Docker 主机上的端口8080 |
-p 192.168.1.100:8080:80 | 将容器中的 TCP 端口80映射到 Docker 主机上的端口8080,以连接到主机 IP 192.168.1.100 |
-p 8080:80/udp | 将容器中的 UDP 端口80映射到 Docker 主机上的8080端口 |
-p 8080:80/tcp -p 8080:80/udp | 将容器中的 TCP 端口80映射到 Docker 主机上的 TCP 端口8080,并将容器中的 UDP 端口80映射到 Docker 主机上的 UDP 端口8080 |
2.2 IP地址和主机名
默认情况下,容器为它连接的每个 Docker 网络分配一个 IP 地址。 Ip 地址是从分配给网络的池中分配的,因此 Docker 守护进程有效地充当每个容器的 DHCP 服务器。 每个网络还有一个默认的子网掩码和网关。
当容器启动时,它只能使用 --network
连接到单个网络。 但是,可以使用 docker network connect
将正在运行的容器连接到多个网络。 当使用 --network
标志启动容器时,可以使用 --ip
或 --ip6
标志指定分配给该网络上的容器的 IP 地址。
当您使用 docker newwork connect
将现有容器连接到另一个网络时,您可以使用该命令上的 --ip
或 --ip6
标志来指定容器在附加网络上的 IP 地址。
同样,容器的主机名默认为 Docker 中容器的 ID。 您可以使用 --hostname
覆盖主机名。 当使用 docker newwork connect
连接到现有网络时,可以使用 --alias
标志为该网络上的容器指定一个额外的网络别名。
2.3 DNS服务
默认情况下,容器继承 Docker 守护进程的 DNS 设置,包括 /etc/hosts
和 /etc/resolv.conf
。你可以根据每个容器重写这些设置。
标志值 | 描述 |
---|---|
–dns | DNS服务器的IP地址。要指定多个DNS服务器,请使用多个–dns标志。如果容器无法访问您指定的任何IP地址,8.8.8.8则会添加Google的公共DNS服务器,以便您的容器可以解析Internet域。 |
–dns-searc | 一个DNS搜索域,用于搜索非完全限定的主机名。要指定多个DNS搜索前缀,请使用多个–dns-search标志。 |
–dns-opt | 代表DNS选项及其值的键/值对 |
–hostname | 容器本身使用的主机名。如果未指定,则默认为容器的ID。 |
2.4 代理服务器
如果你的容器需要使用 HTTP,HTTPS,或者 FTP 代理服务器,你可以用不同的方式配置它:
在Docker 17.07及更高版本中,您可以 配置Docker客户端以将代理信息自动传递到容器。
在Docker 17.06及更低版本中,您必须 在容器内设置适当的环境变量。您可以在构建映像时执行此操作(这会降低映像的可移植性),或者在创建或运行容器时执行此操作
配置 Docker 客户机
在 Docker 客户机上,创建或编辑文件
~/.Docker/config
. 在启动容器的用户的主目录中。 添加如下所示的 JSON,必要时用httpsProxy
或ftpProxy
替换代理类型,并替换代理服务器的地址和端口。 您可以同时配置多个代理服务器。通过将 noProxy 键设置为一个或多个逗号分隔的 IP 地址或主机,可以有选择地排除主机或范围,使其无法通过代理服务器。 支持使用 * 字符作为通配符,如本例所示。
{ "proxies": { "default": { "httpProxy": "http://127.0.0.1:3001", "httpsProxy": "http://127.0.0.1:3001", "noProxy": "*.test.example.com,.example2.com" } } }
保存文件
在创建或启动新容器时,环境变量将在容器中自动设置。
使用环境变量
在构建映像时,或者在创建或运行容器时使用 --env
标志时,可以将以下一个或多个变量设置为适当的值。 这种方法降低了图像的可移植性,因此如果您使用的是 Docker 17.07或更高版本,则应该配置 Docker 客户机。
变量 | Dockfile示例 | docker run示例 |
---|---|---|
HTTP_PROXY | ENV HTTP_PROXY “http://127.0.0.1:3001" | –env HTTP_PROXY=”http://127.0.0.1:3001" |
HTTPS_PROXY | ENV HTTPS_PROXY “https://127.0.0.1:3001" | –env HTTPS_PROXY=”https://127.0.0.1:3001" |
FTP_PROXY | ENV FTP_PROXY “ftp://127.0.0.1:3001" | –env FTP_PROXY=”ftp://127.0.0.1:3001" |
NO_PROXY | ENV NO_PROXY “*.test.example.com,.example2.com” | –env NO_PROXY=”*.test.example.com,.example2.com” |
2.5 启用IPv6支持
在 Docker 容器或群服务中使用 IPv6之前,需要在 Docker 守护进程中启用 IPv6支持。 之后,您可以选择对任何容器、服务或网络使用 IPv4或 IPv6(或者两者都使用)。
注意: IPv6网络只支持在 Linux 主机上运行的 Docker 守护进程。
- 编辑
/etc/docker/daemon.json
并将ipv6
键设置为true
。
{
"ipv6": true
}
保存文件
- 重新加载 Docker 配置文件。
$ systemctl reload docker
现在您可以使用 --ipv6
标志创建网络,并使用 --ip6
标志分配容器的 IPv6 地址。
2.6 Docker 和 iptables
在 Linux 上,Docker 操纵 iptables 规则来提供网络隔离。 虽然这是一个实现细节,你不应该修改 Docker 插入到你的 iptables 策略中的规则,但是如果你想在 Docker 管理的策略之外还有自己的策略,它确实会对你需要做的事情产生一些影响。
如果您正在一个公开到 Internet 的主机上运行 Docker,那么您可能希望将 iptables 策略放在适当的位置,以防止对在您的主机上运行的容器或其他服务的未经授权的访问。 本页描述了如何实现这一点,以及需要注意的事项。
在 Docker 规则之前添加 iptables 策略
Docker 安装了两个自定义 iptables 链,分别名为 Docker-user 和 Docker,它确保传入的数据包总是首先由这两个 iptables 链检查。
Docker 的所有 iptables 规则都添加到 Docker 链中。 不要手动操作此链。 如果需要在 Docker 的规则加载之前添加规则,请将它们添加到 Docker-user 链中。 这些规则在 Docker 自动创建任何规则之前被应用。
添加到 FORWARD 链中的规则——手动地,或者由另一个基于 iptables 的防火墙——在这些链之后进行评估。 这意味着,如果您通过 Docker 公开一个端口,那么无论您的防火墙配置了什么规则,该端口都会公开。 如果希望即使在通过 Docker 公开端口时也应用这些规则,则必须将这些规则添加到 Docker-user 链中。
限制与 Docker 主机的连接
默认情况下,所有外部源 ip 都允许连接到 Docker 主机。 若要只允许特定的 IP 或网络访问容器,请在 DOCKER-USER 过滤器链的顶部插入否定规则。 例如,以下规则限制除192.168.1.1以外的所有 IP 地址的外部访问:
$ iptables -I DOCKER-USER -i ext_if ! -s 192.168.1.1 -j DROP
请注意,如果要符合主机的实际外部接口,则需要更改 ext。 您可以改为允许来自源子网的连接。 以下规则只允许从子网192.168.1.0 / 24访问:
$ iptables -I DOCKER-USER -i ext_if ! -s 192.168.1.0/24 -j DROP
最后,您可以使用 – src-range 指定一个要接受的 IP 地址范围(记住在使用 – src-range 或 – dst-range 时也要添加-m iprange) :
$ iptables -I DOCKER-USER -m iprange -i ext_if ! --src-range 192.168.1.1-192.168.1.3 -j DROP
您可以将-s 或 – src-range 与-d 或 – dst-range 组合起来,以控制源和目标。 例如,如果 Docker 守护进程同时监听192.168.1.99和10.1.2.3,您可以制定特定于10.1.2.3的规则,并保持192.168.1.99处于开放状态。
Iptables 比较复杂,而且更复杂的规则超出了本主题的范围。 更多信息请参见 netfilter. org HOWTO。
路由器上的 Docker
Docker 还为 FORWARD 链设置 DROP 策略。 如果你的 Docker 主机也作为一个路由器,这将导致该路由器不再转发任何流量。 如果您希望您的系统继续发挥路由器的功能,可以向 DOCKER-USER 链添加显式的 ACCEPT 规则以允许它:
$ iptables -I DOCKER-USER -i src_if -o dst_if -j ACCEPT
防止 Docker 操纵 iptables
在 /etc/Docker/daemon.json
的 Docker 引擎配置文件中,可以将 iptables 键设置为 false。 但是这个选项并不适合大多数用户。 完全阻止 Docker 创建 iptables 规则是不可能的,并且在事后创建这些规则非常复杂,超出了本说明的范围。 将 iptables 设置为 false 很可能会破坏 Docker 引擎的容器网络。
设置容器的默认绑定地址
默认情况下,Docker 守护进程将在0.0.0.0地址上公开端口,即主机上的任何地址。 如果希望更改该行为以便只公开内部 IP 地址上的端口,可以使用 --ip
选项指定不同的 IP 地址。 但是,设置 --ip
只改变默认值,它不将服务限制在该 IP 上。
3. 禁用容器联网
如果希望完全禁用容器上的网络堆栈,可以在启动容器时使用 --network none
标志。 在容器中,只创建环回设备。 下面的例子说明了这一点。
- 创建容器
$ docker run --rm -dit \
--network none \
--name no-net-alpine \
alpine:latest \
ash
- 通过在容器中执行一些常见的网络命令来检查容器的网络堆栈。
$ docker exec no-net-alpine ip link show
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN qlen 1
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: tunl0@NONE: <NOARP> mtu 1480 qdisc noop state DOWN qlen 1
link/ipip 0.0.0.0 brd 0.0.0.0
3: ip6tnl0@NONE: <NOARP> mtu 1452 qdisc noop state DOWN qlen 1
link/tunnel6 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00 brd 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00
$ docker exec no-net-alpine ip route
第二个命令返回空,因为没有路由表。
- 停止容器。它会自动删除,因为它是用 – rm 标志创建的。
$ docker container rm no-net-alpine