docker网络学习笔记


※,参考文章列表

  • https://zhuanlan.zhihu.com/cloudnetwork 【来龙去脉很赞!!!】
  • https://xiaoz.co/tags/docker/

※,docker内嵌dns服务器

  • https://www.itmuch.com/docker/18-docker-user-network-embeded-dns/

※,用于故障排除的容器和服务日志:(深入浅出docker pdf版本 P165):

  • 在使用docker过程中遇到问题时,检查daemon日志以及容器日志(应用日志)是非常有必要的。在Linux上,的daemon日志的存储位置取决于当前系统正在使用的初始化方式。如果是Systemd,日志会存储在Journald,并且可以通过journalctl 查看。
  • daemon日志还可以设置级别,在daemon.json文件中可以将debug设置为true, 并将log-level设置成某个级别:debug, info, warn, error, fatal。
  • 容器日志可以通过·docker container logs ·查看。
  • docker service logs 可以查看swarm服务日志。

※,Docker 网络命令

 ★,Docker网络有自己的子命令docker network,具体用法如下:

  • docker network ls 用于列出运行在本地Docker主机上的全部网络。Swarm模式下的Docker主机只能看到已经接入运行中的容器的网络。这种方式保证了网络Gossip开销最小化。
  • docker network create 创建新的Docker网络。默认情况下,在Windows上会采用NAT 驱动,在Linux上会采用Bridge 驱动。-d参数允许用户指定所用驱动(网络类型),对于覆盖网络,控制层默认是加密的。需要指定-o encrypted对数据层进行加密(会导致额外的性能开销)。
  • docker network inspect 提供Docker网络的详细配置信息。其中包括范围、驱动、IPv6、子网配置、VXLAN网络ID以及加密状态。
  • docker network prune 删除Docker主机上全部未使用的网络。
  • docker network rm 删除Docker主机上指定网络

,docker网络架构:CNM、libnetwork、驱动。参考 深入浅出docker 第11章。

  • - CNM(Container Network Model):CNM 是设计标准。在 CNM 中,规定了 Docker 网络架构的基础组成要素。ppt
  • - Libnetwork 是 Docker 对 CNM 的一种实现,提供了 Docker 核心网络架构的全部功能。go语言实现,开源库。
  • - 驱动:驱动通过实现特定网络拓扑的方式来拓展该模型的能力。不同的驱动可以通过插拔的方式接入 Libnetwork 来提供定制化的网络拓扑。
  • - 本地驱动(原生驱动):Docker 封装了一系列本地驱动,覆盖了大部分常见的网络需求.
  • - 远程驱动(第三方驱动)。

★,本地(原生)驱动支持(Linux):

  • - bridge:单机桥接网络,也是容器创建时默认的网络驱动类型(只能单机上的容器互通)。(windows下叫NAT网络)
  • - host: 与宿主机共享网络栈。容器可以操纵宿主机的网络配置,很危险一般不用。
  • - null:
  • - container: --network=container:id/name
  • - macvlan: 跨主机互联通信的一种网络方案。(windows下叫做Transparent)。macvlan驱动可为容器提供MAC和IP地址,让容器在物理网络上称为“一等公民”,这样容器化的应用就可以和外部系统以及物理网络进行通信。macvlan的优点是性能优异,因为无需端口映射或者额外桥接,可以直接通过主机接口(或者子接口)访问容器接口。但是macvlan的缺点是需要将主机网卡(NIC:Network Interface Controller)设置为混杂模式(Promiscuous Mode),这在大部分公有云平台上是不允许的。设置macvlan驱动时需要设置几个参数:子网信息,网关,可分配给容器的IP范围,主机使用的接口或子接口。
    • `docker network create --driver macvlan --subnet=10.0.0.0/24 --ip-range=10.0.00/25 --gateway=10.0.0.1 -o parent=ens192.100 macvlan100` // 物理机网卡为ens192。这个命令会创建macvlan100网络以及ens192.100子接口。
  • - overlay: (多机)覆盖网络. 适用于多主机环境,它允许单个网络包含多个主机,这样不同主机上的容器间就可以在链路层实现通信。Docker为覆盖网络提供了本地驱动,这使得创建覆盖网络非常简单,只需要在创建docker网络时指定 --driver overlay 参数即可,同时也可以不适用原生驱动而使用第三方驱动。

★,远程驱动方案常见的有:Pipework、Flannel、Weaveworks、Open vSwitch(虚拟交换机)、Calico等等。

  • - flannel:借助ETCD或CONSUL实现跨主机通信
  • - calico:同flannel类似,借助ETCD或CONSUL实现跨主机通信
  • - weaveworks: 无需借助其他工具

★,bridge单机桥接网络:

  • - 每个 Docker 主机都有一个默认的单机桥接网络(docker inspect id),在 Linux 上网络名称为 bridge. 新创建的容器除非使用--network指定网络,否则默认情况下都会连接到该单机桥接网络。
  • 默认的“bridge”网络被映射到内核中为“docker0”的 Linux 网桥.
  • - 一对veth,一端在容器中,一端在docker0网桥上。PPT图解。
  • - `docker network ls`
  • - `docker network inspect bridge`
  • - `docker network create mynet` // 创建自定义单机桥接网络 brctl show; docker network inspect mynet
  • - docker network create 创建新的Docker网络。默认情况下,在Windows上会采用NAT 驱动,在Linux上会采用Bridge 驱动。使用-d 参数指定驱动(网络类型)
  • - docker network create -d overlay overnet 会创建一个新的名为overnet的覆盖网络,其采用的驱动为Docker Overlay 。
  • - docker run -itd --name box1 --network mynet busybox
  • - 原生bridge不支持dns解析,自定义桥接网络支持dns解析。
  • - docker network prune //删除未被使用的所有网络
  • - docker network rm // 删除指定网络

※,docker 跨主机互联的几种方案 https://www.bilibili.com/video/BV1Mz4y1C7hT

★方案★

※,添加静态路由:

主机A

  • 物理网卡地址为192.168.1.100
  • docker0 网桥IP地址为10.10.1.1
  • 容器的IP地址为10.10.1.2

主机B:

  • 物理网卡地址为192.168.1.101
  • docker0 网桥IP地址为10.10.2.1
  • 容器的IP地址为10.10.2.2

操作过程记录:首先★(重要!)设置iptables的 FORWARD默认策略为ACCEPT,或者更保险点,直接关闭firewalld 和 iptables

  • 开始状态,两台物理网卡可以互通。两台主机互相 ping 对方的的docker0地址不通,ping对方的的容器地址不通。
  • 在主机A上添加一条静态路由:`ip route add 10.10.2.0/24 via 192.168.1.101`//注意关键点在于这个ip的路由的网关(via后面)地址设置成了主机B的物理网卡IP
    • 此时:A主机pingB主机docker0可以通,pingB主机容器也可以通,原因在于由于刚刚添加的路由,A知道怎么去B,B回来时的目的IP是A主机的物理网卡IP,所以也通。可以通过 tshark 抓包看到具体包。
    • 在A主机容器内,pingB主机docker0不通,pingB主机容器不通(ping包的源IP是A上容器的IP)。tshark抓包可以看到,在B主机上抓包可以看到回包,但是在A主机上看不到回包,只有request。因为包在B上,没有到A的路由转发到A主机上。
  • 在主机B上添加一条静态路由:·route add -net 10.10.1.0 netmask 255.255.255.0 gw 192.168.1.100· //同上,B主机上添加一条到A主机的路由,网关设置成A主机的物理网卡IP。
    • 此时:两边主机以及容器内都可以互通,如果不通就是防火墙的问题了。
    • ·systemctl stop firewalld·
    • `iptables -P FORWARD ACCEPT`// 将filter表的FORWARD链的默认策略改为ACCEPT。
    • ·setenforce 0· //selinux 策略设为Permissive。

★方案★

※,macvlan驱动方式:原理可以参考 深入浅出docker 第11章。

操作记录:记录一台主机A上的操作,另一台主机B操作类似。

  • ·ip link set ens192 promisc on· // macvlan网络必须打开物理网卡的混杂模式
  • ·docker network create --driver macvlan --subnet 192.168.6.0/24 --gateway 192.168.6.254 --ip-range 192.168.6.64/26 -o parent=ens192 mymacvlan·
    • 创建名为mymacvlan的macvlan网络。
    • 192.168.6.64/26表示的是一个IP地址范围192.168.6.64~192.168.6.127(即192.168.6.01000000~192.168.6.01111111)
  • ·docker run -itd --name macvlanbox1 --network mymacvlan busybox· // 还可以加上--ip 192.168.6.66指定具体IP。这样即可把这个容器加入到macvlan网络中。

★方案★:还有ipvlan的方式,略

★方案★:使用overlay驱动方式:原理是利用了 vxlan 隧道技术,可参考 深入浅出docker 第12章部分(图例很清晰)

★,以consul或ETCD的方式使用overlay网络:具体操作参见视频讲解,

大致叙述下思路(自己理解,未经验证,不保证正确):以consul为例,ETCD几乎一模一样

  • 首先创建consul集群 或单节点也行
  • 在每台docker的 /etc/docker/daemon.json 文件中配置两个配置项:假设主机A的IP为192.168.1.10
{
     "cluster-store":"consul://192.168.1.10:8500",# 这个是为docker指定consul的地址,以便让docker知道去哪里存储数据,注意集群也只能配置一个IP地址
     "cluster-advertise":"192.168.1.10:2376"   # 这个是docker向consul数据库中注册节点的信息。告诉consul当前节点的位置
}
  • 所有主机都启动docker后,consul数据库存储了各个主机的节点信息,包含了网络的各种信息,当一台主机上的容器需要和另一台上的容器通信时,先去consul查找如何路由,进而通信。

★,以swarm集群方式使用overlay网络跨主机互联。

swarm集群部署跨主机通信: 各节点环境最好保持一致

  • - docker swarm init --advertise-addr 192.168.1.107:2377 --listen-addr 192.168.1.107:2377
  • - 在当前初始化swarm的主机上运行docker swarm join-token worker 和 docker swarm join-token manager命令来获取添加新的工作节点和管理节点到swarm的命令和Token(一个主机节点是作为工作节点还是作为管理节点接入完全取决于使用了哪个Token)。然后在其他主机上执行获取到的命令即可加入这个swarm。
  • - docker node ls
  • - docker network create -d overlay ol-net
  • - 将服务接入overlay网络。docker service create --name bbox-service --replicas 3 --network ol-net busybox sleep 3600
  • - docker service ls
  • - docker service ps bbox-service
  • - docker service scale bbox-service=5 //缩减、扩容

★,

★方案★

※,centos7中 flanneld 的安装与使用:关键点:systemd的使用!!!

★,安装:

  • ·yum install -y flannel·,安装后的变化如下:
    • ·/etc/sysconfig/flanneld· //产生了flanneld的配置文件,需要将其中的etcd地址改一下。
    • ·/usr/libexec/flannel/mk-docker-opts.sh· //产生了一个用于生成 docker环境变量的脚本(主要是用于指定docker的--bip参数)
    • ·/usr/lib/systemd/system/docker.service.d/flannel.conf· //产生了 systemd 下的docker.service的 drop-in 文件,并且通过 systemctl status docker 发现竟然已经自动加载了此drop in文件!里面指定了一个环境变量文件:`/run/flannel/docker`
    • `/run/flannel/` //产生了一个文件夹
  • ·ETCDCTL_API=2 etcdctl mk /atomic.io/network/config '{ "Network": "10.33.0.0/16", "SubnetLen": 24, "Backend": { "Type": "vxlan" } }'· // 往etcd中配置自己指定的网段。
  • ·systemctl start flanneld·//启动flanneld后发生的事情如下:
    • flanneld 读取etcd中的网段,然后生成一个此网段中的ip地址,将其记录到·/run/flannel/subnet.env·文件。
    • flanneld 向 etcd集中配置中注册当前主机的ip地址。比如:key: ·/atomic.io/network/subnets/10.33.7.0-24· value: `{"PublicIP":"10.70.128.163","BackendType":"vxlan","BackendData":{"VtepMAC":"da:8a:c2:d4:12:08"}}`
    • 通过 systemd下flanneld.service中的配置(ExecStartPost),生成·/run/flannel/docker·, 这个/run/flannel/docker文件中指定了docker启动参数--bip,这个bip由flanneld产生,和flanneld在同一个子网。这样就只要重启下docker即可。
    • ip a可以看到多了一个flanneld.1的 虚拟网卡
  • ·systemctl daemon-reload· //重新加载systemd下的配置文件(这一步主要是重新加载·/usr/lib/systemd/system/docker.service.d/flannel.conf·,但是这个加载 在flanneld安装的时候就已经自动做过了,所以这一步无需做)
  • ·systemctl restart docker·//重启docker ,然后发现docker0的ip变成了和flanneld在一个字网的地址。这样跨主机的docker容器就可以通信了。
    • 注意:重启docker的过程中docker做了一件事:修改了iptables中的filter表中的FORWARD链的规则!!!!
  • ==============问题排查================
  • 如果还有不能互通,基本就是防火墙的问题了
  • ·systemctl stop firewalld·
  • `iptables -P FORWARD ACCEPT`// 将filter表的FORWARD链的默认策略改为ACCEPT。
  • ·setenforce 0· //selinux 策略设为Permissive。

★,docker容器如何通过flanneld进行跨主机通信:。

A主机上docker0网桥的IP假设为:10.33.41.1/24,flanneld的IP地址为:10.33.41.0/32。A上有个容器IP: 10.33.41.2/24,A主机上的路由表为:

A上的容器的路由表为:

B主机上docker0网桥的IP假设为:10.33.7.1/24,flanneld的IP地址为:10.33.7.0/32。其上有个容器IP: 10.33.7.2/24

A主机在容器内ping B 主机: ping 10.33.7.2的过程为:

容器里执行·ip r get 10.33.7.2·,得到结果·10.33.7.2 via 10.33.41.1 dev eth0 src 10.33.41.2· //可以看到 去往10.33.7.2需要经过网关设备eth0(实际就是docker0,在容器里叫eth0)。src是封包的源IP,目的ip当然是10.33.7.2了。注意10.33.41.1是docker0网关(而不是一个待去往的目的IP!!),网关的作用是数据到达网关后由网关决定下一步去往哪里,到达docker0后,docker0再根据宿主机的路由表·ip r get 10.33.7.2·得到结果·10.33.7.2 dev flannel.1 src 10.33.41.0·,即需要经过flanneld这个虚拟网卡。flanneld根据etcd中的配置信息拿到10.33.7.0这个网段的物理机的ip地址,然后flanneld重新封包,目的IP是 10.33.7.0这个网段的物理机的ip地址。到达B主机后,flanneld解包,然后将包传给docker0,然后传给容器。从而通信。

★方案★、使用calico跨主机互联。 略

※,