docker网络详解

in #docker6 years ago (edited)

 Network dirvers

  • bridge:默认的网络驱动,常用在单独的单实例容器需要通信的环境;
  • host:对于单实例容器,移除和宿主机的网络隔离,直接使用宿主机的网络。host 网络驱动只在 docker 17.6及以上版本的 swarm 服务上可用;
macvlan:给容器分配 mac 地址,当应用程序需要直接连接到物理网络时的最好选择;
  • none:禁用所有网络,在使用自定义网络驱动时使用,在 swarm 服务时不可用;
  • network plugins:第三方网络驱动

Docker EE 网络功能

  1. http routing mesh:允许在不同的服务共享相同的 IP 地址和端口,客户端发起的请求,UCP通过主机名和端口的组合路由相关的流量到对应的服务;
  2. Session stickiness:当程序需要满足状态会话要求时,允许指定 http header 信息,使 UCP 路由同一服务任务到后续请求。

使用 bridge 网络

桥接的网络是一个在不同网络段之间转发流量的网络链路层的设备,可以是运行在内核的软件设备,也可以是硬件设备。 ##用户自定的 bridge 和默认 bridge 的区别 ##

  1. 对于容器化的应用,用户定义的 bridge 提供更好的隔离和互操作性; 连接到同一用户定义的 bridge 网络的容器,自动互相暴露所有端口,对外不开放端口。如果一个应用堆栈运行在默认的 bridge 网络包含 web 前端和数据库后端,但是 只有 web 前端需要连接数据库,数据库后端不需要对外开放端口,用户可以通过自定义的 bridge 网络进行访问。
  2. 用户定义的 bridge 提供容器之间自动的 DNS 解析; 在默认 bridge 网络的容器,默认只能通过 IP 进行彼此的访问,除非使用 --link 选项。在用户定义的 bridge 网络,容器可以通过名称或者别名访问彼此。如果你的容器叫做 web 和 db,无论 应用堆栈运行在哪个 Docker 主机,web 容器都能够连接到 db 容器。如果在默认的 bridge 运行相同的应用堆栈,你需要在容器之间手动创建连接(使用 --link)。这些连接需要双向创建,当多余两个的容器需要通行时,会发现复杂度大大增加。虽然可以通过容器内的 /etc/hosts 文件来进行维护,但是会导致难以排错。
  3. 容器在运行时,从用户定义的网络 attached 和 deattached; 在容器的生命周期,用户可以从定义的 bridge 连接或者断开连接。要从默认的 bridge 网络移除容器,需要停止容器并以不同网络参数重新创建。
  4. 每一个用户定义的 bridge 生成一个可配置的 bridge; 最初,使用 --link 标志是两个容器之间共享环境参数的唯一方式。但这种参数共享方式在用户定义的 bridge 网络中不可使用。下面是一些关于参数共享的其他方式:
  • 多个容器可以使用 docker volume 挂载包含共享信息的文件或者目录;
  • 多个容器可以使用 docker compose 一起启动,compose 文件可以定义共享的参数;
  • 使用 swarm 服务替换单实例容器,使用共享 secrets 和 configs。

用户定义的 bridge 管理

  • docker network create/rm 创建/删除用户定义的 bridge
  • 连接一个容器到用户定义的 bridge
  1. 指定 --network 标志位,创建一个网络,对外发布80端口,绑定在 Docker 主机上容器的8080端口; $ docker create --name my-nginx \
      --network my-net \
      --publish 8080:80 \
      nginx:latest
  2. docker network connect my-linux 运行中的容器连接到已存在的用户定义的 bridge
  • docker network disconnect my-net my-nginx 断开容器到用户定义 bridge 网络的连接
  • 启用 IPv6支持
  1. 编辑 /etc/docker/daemon.json,将 ipv6 的值设置为 true;{  "ipv6": true}
  2. 重载 docker 配置文件 systemctl reload docker
  • 允许 docker 容器到外面的转发
  1. 配置 Linux 内核,允许 IP 转发 sysctl net.ipv4.conf.all.forwarding=1
  2. 将 iptables 的 FORWARD 策略从拒绝更改为接受 iptables -P FORWARD ACCEPT
这些设置重启后不生效,需要加入开机启动脚本

##使用默认的 bridge 网络##

如果不使用 --network 标志,容器会默认连接到默认的 bridge 网络。除非通过 --link 标志去连接,连接到默认的 bridge 网络的容器默认只能通过 IP 地址进行通信。

daemon.json配置文件示例:

 {

   "bip": "192.168.1.5/24",

   "fixed-cidr": "192.168.1.5/25",

   "fixed-cidr-v6": "2001:db8::/64",

   "mtu": 1500,

   "default-gateway": "10.20.1.1",

   "default-gateway-v6": "2001:db8:abcd::89",

   "dns": ["10.20.1.2","10.20.1.3"]

 }
如果配置 docker的 IPv6支持,默认的 bridge 网络会自动配置 IPv6。和用户定义的 bridge 网络不同, 默认的 bridge 不能选择禁用。

使用 overlay 网络

overlay 网络驱动会在多个 docker 守护进程主机上创建一个分布式网络。这个网络位于主机特定的网络之上,提供运行容器的连接(包括 swarm 服务容器)进行安全的通信。docker 透明的处理路由每个数据包流经正确的 docker 守护进程主机和正确的目标容器。 初始化一个 swarm 或者将一个 docker 主机加入到一个 swarm,在这个 docker 主机上,两个新网络会被创建:

  • 一个名称为 ingress 的 overlay 网络,用来处理 swarm 服务相关的控制和数据流量。当创建了一个没有连接到用户定义的 overlay 网络的 swarm 服务时,默认会年检到 ingress 网络;
  • 一个名称为 docker_gwbridge 的 bridge 网络,将单个Docker守护进程与参与群集的其他守护进程连接起来。

overylay 网络的相关操作

创建一个 overlay 网络 前提:

  1. 加入 overlay 网络的每台 docker 主机,需要开放如下端口:
  • 用于 cluster 管理通信的端口 TCP 2377
  • 用于节点之间通信的端口 TCP/UDP 7946;
  • 用于 overlay 网络流量的端口 UDP 4789
  1. 初始化 swarm 管理节点:docker swarm init,加入以存在的 swarm:docker swarm join。上述操作默认都会创建一个用于 swarm 服务,称为 ingress 的 overlay 网络。即使你不打算使用 swarm 服务,也需要进行这个操作。后续才能创建用户定义的 overlay 网络。

创建一个用于 swarm 服务的 overlay 网络,使用如下命令:docker network create -d overlay my-overlay。 创建一个用于 swarm 服务或者在 docker 守护进程主机上独立的容器之间能互相通信的 overlay 网络,使用 --attachable标志:docker network create -d overlay --attachable my-attachable-overlay

加密 overlay 网络流量

默认情况下,所有的 swarm 管理流量使用 GCM 模式的 AES 算法加密。每12个小时,swarm 的管理节点循环一次用于加密 gossip 数据的密钥。 在创建 overlay 网络时添加 --opt encrypted,可以用来加密应用程序的数据。这会在 vxlan 层启用 IPSec 加密。此加密会打来不可忽视的性能损失,上线生产环境时,需进行测试。

不能将 windows 节点附加到加密的 overlay 网络。overlay 网络不支持windows 节点。如果尝试将 windows 节点附加到加密的 overlay 网络,并不会检测到有错误,但是节点不能通信。

可以在 overlay 网络使用 --opt encrypted --attachable,将未管理的容器附加到这个网络: docker network create --opt encrypted --driver overlay --attachable my-attachable-multi-host-network

自定义默认的 ingress 网络

Docker 17.05之前的版本不能进行自定义。
  1. docker network inspect ingress 命令检查网络,移除任何连接到 ingress 网络上的容器。如果此类服务(有对外发布的端口)不停止,后续步骤会失败;
  2. 删除已存在的 ingress 网络: docker network rm ingress<br>WARNING! Before removing the routing-mesh network, make sure all the nodes<br>in your swarm run the same docker engine version. Otherwise, removal may not<br>be effective and functionality of newly created ingress networks will be impaired.<br>Are you sure you want to continue?[y/N]<br>
  3. 使用 --ingress 标志创建新的 overlay 网络,示例如下: $ docker network create \
      --driver overlay \
      --ingress \
      --subnet=10.11.0.0/16 \
      --gateway=10.11.0.2 \
      --opt com.docker.network.driver.mtu=1200 \
      my-ingress
可以对 ingress 网络进行命名,但是只能有一个 ingress 网络。
  1. 重启附加到 ingress 网络上的相关服务。

自定义 docker_gwbridge 接口###

    docker_gwbridge 是将overlay 网络(包含 ingress 网络)连接到单独的 docker 守护进程的物理网络的虚拟 bridge。Docker 在初始化和加入一个 swarm 时自动创建,但它不是一个 docker 服务。它存在 docker 主机的内核,如果想对它进行自定义设置,必须在加入 swarm 之前,或者从 swarm 中临时删除。

  1. 停止docker服务:systemctl stop docker;
  2. 删除已存在的 docker_gwbridge 接口; sudo ip link set docker_gwbridge down sudo ip link del dev docker_gwbridge 
  3. 启动 Docker,不要加入或者初始化 swarm;
  4. 手动创建 docker_gwbridge 接口示例如下: $ docker network create \
    --subnet 10.11.0.0/16 \
    --opt com.docker.network.bridge.name=docker_gwbridge \
    --opt com.docker.network.bridge.enable_icc=false \
    --opt com.docker.network.bridge.enable_ip_masquerade=true \
    docker_gwbridge
  5. 初始化或者加入 swarm。因为 bridge 已经存在,Docker 不会自动设置创建。

swarm 服务 相关操作

    ingress 网络创建时不带 --attachable 标志位,意味着只有 swarm 服务才能使用,独立的 container 服务不能使用。你可以创建带--attachable 标志的用户定义的 overlay 网络来连接独立的 container。这提供了在不同Docker守护进程上运行的独立容器能够进行通信,而不需要在单独的Docker守护进程主机上设置路由的能力。

端口发布

Container 发现

     对于大多数情况,应该连接到服务名称,该名称是负载平衡的,并由支持服务的所有容器(“tasks”)处理。要获取支持服务的所有 tasks 的列表,请对 tasks.<service-name> 执行DNS查询。

使用 host 网络

    如果容器使用 host 网络驱动程序,则该容器的网络堆栈不会与 Docker 主机隔离。例如,如果运行绑定到端口80的容器并使用 host 网络,则容器的应用程序将在主机 IP 地址的端口 80上可用。 host 网络只支持 Linux 主机,不支持 docker for mac,docker for windows 和 docker EE for windows server。 在 Docker 17.06或更高版本中,可以通过向 Docker 容器创建命令传递——网络主机来为群集服务使用 host 网络。在这种情况下,控制流量(与管理群集和服务相关的流量)仍然通过 overlay 网络发送,但是单个的 swarm 服务容器使用 Docker 守护进程的主机网络和端口发送数据。这就产生了一些额外的限制。例如,如果服务容器绑定到端口80,那么在给定的群集节点上只能运行一个服务container。 如果容器使用 host 网络驱动程序,则该容器的网络堆栈不会与 Docker 主机隔离。例如,如果运行绑定到端口80的容器并使用 host 网络,则容器的应用程序将在主机 IP 地址的端口 80上可用。 host 网络只支持 Linux 主机,不支持 docker for mac,docker for windows 和 docker EE for windows server。 在 Docker 17.06或更高版本中,可以通过向 Docker 容器创建命令传递——网络主机来为群集服务使用 host 网络。在这种情况下,控制流量(与管理群集和服务相关的流量)仍然通过 overlay 网络发送,但是单个的 swarm 服务容器使用 Docker 守护进程的主机网络和端口发送数据。这就产生了一些额外的限制。例如,如果服务容器绑定到端口80,那么在给定的群集节点上只能运行一个服务container。 如果容器或者服务不对外发布端口,host 网络没有任何影响。

使用 Macvlan 网络

有些应用,如传统程序程序或者网络流量监控程序,希望能直接连接到物理网络。在这种情况下,可以使用 Macvlan 网络驱动给每个容器的虚拟网络接口分配一个 MAC 地址,使得看起来像是物理网络接口直接连接到物理网络接口。在这种情况下,你需要在 Docker 主机为 Macvlan 设计一个物理接口以及子网和网关。你甚至可以通过不同的物理网络接口来隔离你的 Macvlan 网络。记住以下几点:

  • 很容易无意地损坏您的网络,因为IP地址耗尽或“VLAN扩展”,这是您在您的网络中有不适当数量的唯一MAC地址的情况。
  • 您的网络设备需要能够处理“混杂模式”,其中一个物理接口可以分配多个MAC地址。
  • 如果您的应用程序可以使用桥(在单一的Docker主机上)或覆盖(在多个Docker主机上进行通信),那么从长远来看,这些解决方案可能会更好。

创建 Macvlan 网络

当创建 macvlan 网络时,它既可以在 bridge 模式也可以在 802.1q trunk bridge 模式

  • 在 bridge 模式,Macvlan 流量直接经过物理设备到达主机。
  • 在 802.1q trunk bridge 模式,流量通过主机创建的 802.1q子接口。这允许您在更细粒度的级别控制路由和过滤。

Bridge 模式

在一个给定的物理接口创建 Macvlan ,在执行docker network create 命令时使用 --driver macvlan。同时你也需要指定父接口,也就是流量物理传到的主机接口。

 $ docker network create -d macvlan \

   --subnet=172.16.86.0/24 \

   --gateway=172.16.86.1  \

   -o parent=eth0 pub_net

如果你需要在一个已经使用中的 Macvlan 网络中排除 IP 地址,例如一个给定的 IP 已经在使用中,使用 --aux-addresses

 $ docker network create -d macvlan  \

   --subnet=192.168.32.0/24  \

   --ip-range=192.168.32.128/25 \

   --gateway=192.168.32.254  \

   --aux-address="my-router=192.168.32.129" \

   -o parent=eth0 macnet32

####802.1q trunk bridge 模式如果你指定的父接口包含一个.,如 eth.50,docker 会将其理解为 eth0的子接口,并自动为其创建子接口。

 $ docker network  create  -d macvlan \

     --subnet=192.168.50.0/24 \

     --gateway=192.168.50.1 \

     -o parent=eth0.50 macvlan50

####使用 ipvlan 代替 macvlan在上面的例子中,仍然是使用 L3 bridge。你可以使用 ipvlan 来替代,并获得一个 L2 bridge。指定 -o ipvlan_mode=l2.

禁用 container 网络

如果想在一个container 完全禁用网络,你可以在启动 container 时指定 --network none 标志位。在 container 内,只有 loopback 设备被创建。下面的例子说明了这个。

  1. 创建 container。 $ docker run --rm -dit \
      --network none \
      --name no-net-alpine \
      alpine:latest \
      ash
  2. 在 container 内部执行一些网络命令,检查容器的网络。注意没有 eth0被创建。 $ 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因为没有路由表,第二条命令返回为空。

Coin Marketplace

STEEM 0.28
TRX 0.12
JST 0.033
BTC 70434.55
ETH 3761.18
USDT 1.00
SBD 3.84