容器网络

在前面的博客中已经详细讲解了几种网络方案: none, host, bridge,user-defined。但是他们只是解决了单个主机间的容器的通信问题,并不能实现多个主机容器之间的通信。本篇博客将详细介绍如何实现该功能。

跨主机网络方案包括两大类:

  1. docker原生的:overlay和macvlan
  2. 第三方方案:flannel、weave和calico

本篇博客将详细讲解overlay以及weave两种方案。

overlay

Docerk overlay 网络需要一个 key-value 数据库用于保存网络状态信息,包括 Network、Endpoint、IP 等。Consul、Etcd 和 ZooKeeper 都是 Docker 支持的 key-vlaue 软件,我们这里使用 Consul。

在 docker 主机 host1(172.20.10.2)和 host2(172.20.10.7)上实践各种跨主机网络方案,在 172.20.10.2 上部署支持的组件,比如 Consul。

第一步:启动路由转发功能

两台主机上面都需要开启

[root@ken3 ~]# echo "" > /proc/sys/net/ipv4/ip_forward

第二步:运行consul

最简单的方式是以容器方式运行 Consul:

[root@ken1 ~]# docker run -d -p : -h consul --name consul progrium/consul -server -bootstrap

第三步:浏览器访问

容器启动后,可以通过 http://172.20.10.2:8500 访问 Consul。

第四步:修改docker启动文件

接下来修改 host1 和 host2 的 docker daemon 的配置文件/usr/lib/systemd/system/docker.service

[Service]
Type=notify
# the default is not to use systemd for cgroups because the delegate issues still
# exists and systemd currently does not support the cgroup feature set required
# for containers run by docker
ExecStart=/usr/bin/dockerd -H unix:// --cluster-store=consul://172.20.10.2:8500 --cluster-advertise=eth0:2376
...

--cluster-store 指定 consul 的地址。
--cluster-advertise 告知 consul 自己的连接地址(eth0即为网卡名,固定格式)

重启 docker daemon。

[root@ken1 ~]# systemctl daemon-reload
[root@ken1 ~]# systemctl restart docker

重启consul

[root@ken1 ~]# docker rm $(docker ps -aq)
[root@ken1 ~]# docker run -d -p : -h consul --name consul progrium/consul -server -bootstrap

第五步:浏览器查看

可以发现两个主机已经自动注册上去了

创建overlay网络

在host1中创建网络ov_ken

[root@ken1 ~]# docker network create -d overlay ov_ken
25979f1d44c12362f3866295995756984468060c10479288835d64588f27fa3b
[root@ken1 ~]# docker network ls
NETWORK ID NAME DRIVER SCOPE
e36545bfeb92 bridge bridge local
43b0997b8ce5 host host local
36d9a3277b19 none null local
25979f1d44c1 ov_ken overlay global

注意到 ov_ken 的 SCOPE 为 global,而其他网络为 local。在 host2 上查看存在的网络:

host2 上也能看到 ov_ken。这是因为创建 ov_ken 时 host1 将 overlay 网络信息存入了 consul,host2 从 consul 读取到了新网络的数据。之后 ov_ken 的任何变化都会同步到 host1 和 host2。

docker network inspect 查看 ov_ken 的详细信息:

docker 自动为 ov_ken分配的 IP 空间为 10.0.0.0/24。

在overlay中运行容器

行一个 busybox 容器并连接到 ov_ken:

[root@ken1 ~]# docker run -itd --name b1 --network ov_ken busybox
fc6454145e12c1c1a494914e3c71d4a9c7c7da0d6ed888e4b6d2afe80379e000

访问外网测试

可以发现容器访问外网是没有问题的

外网想要访问主机可以通过端口映射

[root@ken1 ~]# docker exec b1 ping -c  www.baidu.com
PING www.baidu.com (61.135.169.125): data bytes
bytes from 61.135.169.125: seq= ttl= time=25.144 ms
bytes from 61.135.169.125: seq= ttl= time=24.358 ms --- www.baidu.com ping statistics ---
packets transmitted, packets received, % packet loss
round-trip min/avg/max = 24.358/24.751/25.144 ms

跨主机连通

在 host2 中运行容器 b2

[root@ken3 ~]# docker run -itd --name b2 --network ov_ken busybox

查看b2的网络

b2的ip为10.0.0.3

[root@ken3 ~]# docker exec b2 ip r
default via 172.18.0.1 dev eth1
10.0.0.0/ dev eth0 scope link src 10.0.0.3
172.18.0.0/ dev eth1 scope link src 172.18.0.2

测试b1能否ping通b2

[root@ken1 ~]# docker exec b1 ping -c  10.0.0.3
PING 10.0.0.3 (10.0.0.3): data bytes
bytes from 10.0.0.3: seq= ttl= time=10.344 ms
bytes from 10.0.0.3: seq= ttl= time=1.694 ms --- 10.0.0.3 ping statistics ---
packets transmitted, packets received, % packet loss
round-trip min/avg/max = 1.694/6.019/10.344 ms [root@ken1 ~]# docker exec b1 ping -c b2
PING b2 (10.0.0.3): data bytes
bytes from 10.0.0.3: seq= ttl= time=2.916 ms
bytes from 10.0.0.3: seq= ttl= time=1.950 ms --- b2 ping statistics ---
packets transmitted, packets received, % packet loss
round-trip min/avg/max = 1.950/2.433/2.916 ms

可见 overlay 网络中的容器可以直接通信,同时 docker 也实现了 DNS 服务。

overlay网络隔离

不同的 overlay 网络是相互隔离的。我们创建第二个 overlay 网络 ov_ken2 并运行容器 b

[root@ken1 ~]# docker network create -d overlay ov_ken2
2008b1f950566f105a567ea422ef2269b1db226de58b2d8d8350a91106542d27 [root@ken1 ~]# docker run -itd --name b3 --network ov_ken2 busybox
9f6b4166169ebe5993f8533c57dbf0089fe539a09607d94d3d9442990c8393ea

查看b3分配到的IP

可以发现是10.0.1.2

[root@ken1 ~]# docker exec b3 ip r
default via 172.18.0.1 dev eth1
10.0.1.0/ dev eth0 scope link src 10.0.1.2
172.18.0.0/ dev eth1 scope link src 172.18.0.3

现在尝试ping b2

[root@ken1 ~]# docker exec b3 ping -c  10.0.0.3
PING 10.0.0.3 (10.0.0.3): data bytes --- 10.0.0.3 ping statistics ---
packets transmitted, packets received, % packet loss

ping 失败,可见不同 overlay 网络之间是隔离的。

如果要实现 b3 与 b2 通信,可以将 b3 也连接到 ov_ken。

[root@ken1 ~]# docker network connect ov_ken b3

[root@ken1 ~]# docker exec b3 ip r
default via 172.18.0.1 dev eth1
10.0.0.0/ dev eth2 scope link src 10.0.0.4
10.0.1.0/ dev eth0 scope link src 10.0.1.2
172.18.0.0/ dev eth1 scope link src 172.18.0.3

可以发现现在的b3有了一个eth2的网卡,ip地址为10.0.0.4

现在再来测试一下b3能否ping通b2

[root@ken1 ~]# docker exec b3 ping -c  10.0.0.3
PING 10.0.0.3 (10.0.0.3): data bytes
bytes from 10.0.0.3: seq= ttl= time=7.145 ms
bytes from 10.0.0.3: seq= ttl= time=2.769 ms --- 10.0.0.3 ping statistics ---
packets transmitted, packets received, % packet loss
round-trip min/avg/max = 2.769/4.957/7.145 ms

可以发现现在可以ping通了

weave网络

weave 不依赖分布式数据库(例如 etcd 和 consul)交换网络信息,每个主机上只需运行 weave 组件就能建立起跨主机容器网络。接下来在 host1 和 host2 上部署 weave 并实践 weave 的各项特性。

安装部署weave

weave 安装非常简单,在 host1 和 host2 上执行如下命令:

[root@ken1 ~]# curl -L git.io/weave -o /usr/local/bin/weave
[root@ken1 ~]# chmod a+x /usr/local/bin/weave

host1中启动weave

在 host1 中执行 weave launch 命令,启动 weave 相关服务。weave 的所有组件都是以容器方式运行的,weave 会从 docker hub 下载最新的 image 并启动容器。

[root@ken1 ~]# weave launch

查看启动的容器

[root@ken1 ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
7a59dcccd908 weaveworks/weave:2.5. "/home/weave/weaver …" seconds ago Restarting () seconds ago weave

weave 运行了一个容器:

weave 是主程序,负责建立 weave 网络,收发数据 ,提供 DNS 服务等。

host1中启动容器

[root@ken ~]# eval $(weave env)
[root@ken ~]# docker run --name b1 --rm -itd busybox
e04f798321072542450ca800601e980d206e00e8850b1b1ce16f4cba8ce94a32

首先执行 eval $(weave env) 很重要,其作用是将后续的 docker 命令发给 weave proxy 处理。如果要恢复之前的环境,可执行 eval $(weave env --restore)

查看一下当前容器 bbox1 的网络配置:

b1 有两个网络接口 eth0 和 ethwe,其中 eth0 连接的是默认 bridge 网络,即网桥 docker0。

分配的 IP 10.32.0.1/12  ethwe 与 weave 相关

再运行一个容器 b2。

[root@ken ~]# docker run --name b2 --rm -itd busybox
abf55e9dead051e0e87afd524243fbb7c3a6985042d0d924a829a91399c76ade

测试b1与b2的连通性(相同主机host!)

可以发现b1与b2不仅可以互相ping通,还可以解析

[root@ken ~]# docker exec b1 ping -c  b2
PING b2 (10.32.0.2): data bytes
bytes from 10.32.0.2: seq= ttl= time=0.141 ms
bytes from 10.32.0.2: seq= ttl= time=0.282 ms --- b2 ping statistics ---
packets transmitted, packets received, % packet loss
round-trip min/avg/max = 0.141/0.211/0.282 ms

weave跨主机通信

第一步:首先在host2 执行如下命令

[root@ken3 ~]# weave launch 172.20.10.2
e69a5bec56eb8d5471b139ce2c3080f2681e44c7bf582ef798c017d83107e3ac

这里必须指定 host1 的 IP 172.20.10.2,这样 host1 和 host2 才能加入到同一个 weave 网络。

第二步:开启路由转发功能

echo "">/proc/sys/net/ipv4/ip_forward

第三步:启动容器

[root@ken3 ~]# eval $(weave env)
[root@ken3 ~]# docker run --name b3 --rm -itd busybox
4c86439dd59d545eb73e796709872cd51e4953503e63c2a0ff4549b2eb3ce8fa

第四步:测试容器连接性

可以发现主机host2上运行的b3容器可以与host1主机上面运行的b1和b2容器进行通信,而且可以解压主机名。

[root@ken3 ~]# docker exec b3 ping -c  b1
PING b1 (10.32.0.1): data bytes
bytes from 10.32.0.1: seq= ttl= time=7.157 ms
bytes from 10.32.0.1: seq= ttl= time=1.021 ms --- b1 ping statistics ---
packets transmitted, packets received, % packet loss
round-trip min/avg/max = 1.021/4.089/7.157 ms
[root@ken3 ~]# docker exec b3 ping -c b2
PING b2 (10.32.0.2): data bytes
bytes from 10.32.0.2: seq= ttl= time=8.116 ms
bytes from 10.32.0.2: seq= ttl= time=1.960 ms --- b2 ping statistics ---
packets transmitted, packets received, % packet loss
round-trip min/avg/max = 1.960/5.038/8.116 ms

weave网络隔离

默认配置下,weave 使用一个大 subnet(例如 10.32.0.0/12),所有主机的容器都从这个地址空间中分配 IP,因为同属一个 subnet,容器可以直接通信。如果要实现网络隔离,可以通过环境变量 WEAVE_CIDR 为容器分配不同 subnet 的 IP,举例如下:

[root@ken3 ~]# docker run -e WEAVE_CIDR=net:10.32.2.0/ --rm -itd busybox
98bc93412af210e08b4be7a9456e40749ca4a0672f3ebbc5a5f616ab0b4d3b50

这里 WEAVE_CIDR=net:10.32.2.0/24 的作用是使容器分配到 IP 10.32.2.2。由于 10.32.0.0/12 与 10.32.2.0/24 位于不同的 subnet,所以无法 ping 到 b2。

[root@ken3 ~]# docker exec 98bc93412af ping -c  b2
PING b2 (10.32.0.2): data bytes --- b2 ping statistics ---
packets transmitted, packets received, % packet loss

除了 subnet,我们还可以直接为容器分配特定的 IP:

[root@ken3 ~]# docker run -e WEAVE_CIDR=ip:10.32.6.6/ -it busybox
/ # ip a
: lo: <LOOPBACK,UP,LOWER_UP> mtu qdisc noqueue qlen
link/loopback ::::: brd :::::
inet 127.0.0.1/ scope host lo
valid_lft forever preferred_lft forever
: eth0@if37: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu qdisc noqueue
link/ether ::ac::: brd ff:ff:ff:ff:ff:ff
inet 172.17.0.4/ brd 172.17.255.255 scope global eth0
valid_lft forever preferred_lft forever
: ethwe@if39: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu qdisc noqueue
link/ether ae:e0:cd::ac:f5 brd ff:ff:ff:ff:ff:ff
inet 10.32.6.6/ brd 10.32.6.255 scope global ethwe
valid_lft forever preferred_lft forever
/ # ping -c b2
PING b2 (10.32.0.2): data bytes --- b2 ping statistics ---
packets transmitted, packets received, % packet loss

weave与外网的连通性

weave 是一个私有的 VxLAN 网络(容器可以访问外网),默认与外部网络隔离。外部网络如何才能访问到 weave 中的容器呢?

答案是:

  1. 首先将主机加入到 weave 网络。

  2. 然后把主机当作访问 weave 网络的网关。

第一步:要将主机加入到 weave,执行 weave expose

[root@ken3 ~]# weave expose
10.32.2.129

第二步:查看IP

这个 IP 10.32.2.129 会被配置到 host2 的 weave 网桥上。

第三步:测试连通性

ping同一主机的b3

[root@ken3 ~]# ping -c  10.44.0.0
PING 10.44.0.0 (10.44.0.0) () bytes of data.
bytes from 10.44.0.0: icmp_seq= ttl= time=0.327 ms
bytes from 10.44.0.0: icmp_seq= ttl= time=0.068 ms --- 10.44.0.0 ping statistics ---
packets transmitted, received, % packet loss, time 999ms
rtt min/avg/max/mdev = 0.068/0.197/0.327/0.130 ms

ping host1中的b1

[root@ken3 ~]# ping -c  10.32.0.1
PING 10.32.0.1 (10.32.0.1) () bytes of data.
bytes from 10.32.0.1: icmp_seq= ttl= time=28.4 ms
bytes from 10.32.0.1: icmp_seq= ttl= time=0.975 ms --- 10.32.0.1 ping statistics ---
packets transmitted, received, % packet loss, time 1002ms
rtt min/avg/max/mdev = 0.975/14.708/28.442/13.734 ms

接下来要让其他非 weave 主机访问到 bbox1 和 bbox3,只需将网关指向 host1。例如在 172.20.10.9上添加如下路由:

[root@host2 ~]# ip route add 10.32.0.0/ via 172.20.10.2

[root@host2 ~]# ping -c  10.32.0.1
PING 10.32.0.1 (10.32.0.1) () bytes of data.
bytes from 10.32.0.1: icmp_seq= ttl= time=1.45 ms
bytes from 10.32.0.1: icmp_seq= ttl= time=2.25 ms --- 10.32.0.1 ping statistics ---
packets transmitted, received, % packet loss, time 1002ms
rtt min/avg/max/mdev = 1.450/1.852/2.254/0.402 ms

10.32.0.0/12 是 weave 网络使用的默认 subnet,如果此地址空间与现有 IP 冲突,可以通过 --ipalloc-range 分配特定的 subnet。

weave launch --ipalloc-range 10.2.0.0/16

不过请确保所有 host 都使用相同的 subnet。

Docker跨主机通信(九)--技术流ken的更多相关文章

  1. Docker跨主机通信(九)

    容器网络 在前面的博客中已经详细讲解了几种网络方案: none, host, bridge,user-defined.但是他们只是解决了单个主机间的容器的通信问题,并不能实现多个主机容器之间的通信.本 ...

  2. Docker网络(五)--技术流ken

    本章内容 1.dokcer默认自带的几种网络介绍 2. 自定义网络 3. 容器间通信 4. 容器与外界交互 docker网络分为单个主机上的容器网络和多个主机上的哇网络,本文主要讲解单个主机上的容器网 ...

  3. Docker容器监控(十)--技术流ken

    docker自带的监控命令 docker自带了三个监控命令即ps, top, stats ps docker ps 可以帮助我们很快的了解当前正在运行的容器 -a:会显示已经停掉的容器 [root@h ...

  4. docker跨主机通信扁平化网络的设计与实现

    端口映射.ovs. fannel,weave 1.使用网桥实现跨主机容器连接 使用Open vSwitch实现跨主机容器连接

  5. Docker跨主机通信之路由

    一.实验环境: 主机名 主机IP Docker0_IP Docker1 192.168.88.130 172.17.0.1 Docker2 192.168.88.131 172.18.0.1 二.实验 ...

  6. docker跨主机通信-overlay

    使用consul 1,让两个网络环境下的容器互通,那么必然涉及到网络信息的同步,所以需要先配置一下consul. 直接运行下面命令.启动consul. docker run -d -p 8500:85 ...

  7. Docker跨主机网络——overlay

    前言 在Docker网络--单host网络一文中,我为大家总结了Docker的单机网络相关知识和操作,单机网络比较容易.本文我为大家总结Docker跨主机通信相关知识.同样本文大部分内容以CloudM ...

  8. k8s集群监控(十一)--技术流ken

    Weave Scope   在我之前的docker监控中<Docker容器监控(十)--技术流ken>就已经提到了weave scope. Weave Scope 是 Docker 和 K ...

  9. Docker跨主机网络实践

    Docker使用中网络管理是最麻烦的,在项目初始化前期就需要进行合理的规划,如果在比较理想的单主机的网络通信是比较简单的,但如果涉及到跨主机的网络就需要使用docker自带的overlay netwo ...

随机推荐

  1. ABP源码分析三:ABP Module

    Abp是一种基于模块化设计的思想构建的.开发人员可以将自定义的功能以模块(module)的形式集成到ABP中.具体的功能都可以设计成一个单独的Module.Abp底层框架提供便捷的方法集成每个Modu ...

  2. Codeforces Round #267 (Div. 2) C. George and Job DP

                                                  C. George and Job   The new ITone 6 has been released ...

  3. HashMap为什么线程不安全(hash碰撞与扩容导致)

    一直以来都知道HashMap是线程不安全的,但是到底为什么线程不安全,在多线程操作情况下什么时候线程不安全? 让我们先来了解一下HashMap的底层存储结构,HashMap底层是一个Entry数组,一 ...

  4. RoboGuice注入框架简单应用

    1.设置Activity为RoboActivity; 2.设置界面@ContentView(int resId) 3.使用@InjectView(int resId)反射组件 4.使用@Inject ...

  5. TortoiseGit push失败原因小结(转)

    花了我一个晚上,终于弄明白为什么总是 push 失败的原因了!竟然是因为我用的是注册的用户名而不是邮箱名……囧死. 另外搞清楚了一个问题,就是 Git 和远程仓库交互有两种方式,即 https 方式和 ...

  6. 转://MySQL客户端工具的选择

    先说我的选择:SQLyog. 尝试的客户端:Toad for MySQL.MySQL-Front.Navicat for MySQL.SQLyog. 官方下载链接: Toad for MySQL:ht ...

  7. api controller 接口接收json字符串参数

    {"data":{"alarmRepeatTimes":2,"currentMode":1,"moduleResetTimeout ...

  8. Ex 6_4 判断序列是否由合法单词组成..._第六次作业

    设字符串为s,字符串中字符的个数为n,vi[i]表示前i+1个字符是否能组成有效的单词vi[i]=true表示能组成有效的单词,vi[i]=false表示不能组成有效的单词,在每个字符串前加一个空格, ...

  9. python 同时迭代多个序列

    每次分别从一个序列中取一个元素 >>> xpts = [1, 5, 4, 2, 10, 7] >>> ypts = [101, 78, 37, 15, 62, 99 ...

  10. shellcode在栈溢出中的利用与优化

    0x00 前言 在<Windows Shellcode学习笔记——shellcode的提取与测试>中介绍了如何对shellcode作初步优化,动态获取Windows API地址并调用,并通 ...