Docker容器网络与通信
文章目录
- 1、Docker容器默认网络模型
- 1_原理图
- 2_名词解释
- 2、Docker容器默认网络模型工作原理
- 1_容器访问外网
- 2_外网访问容器
- 3、Docker容器四种网络模型
- 4、Docker容器四种网络模型应用案例
- 1_查看已有的网络模型
- 2_创建指定类型的网络模型
- 1 bridge
- 2 host
- 3 none
- 4 联盟网络
- 5、跨Docker Host容器间通信探讨
- 1_跨Docker Host容器间通信必要性
- 2_跨Docker Host容器间通信实现方案
- 1 Docker原生方案
- 2 第三方方案
- 6、Flannel
- 1_overlay network介绍
- 2_Flannel介绍
- 3_Flannel工作原理
- 7、ETCD
- 7.5、下面开始实现跨Docker Host容器间通信
- 8、ETCD部署
- 1_主机名称配置
- 2_主机IP地址配置
- 3_主机名与IP地址解析
- 4_开启内核转发
- 5_Etcd安装
- 6_Etcd配置
- 7_启动etcd服务
- 8_检查端口状态
- 9_检查Etcd集群是否健康
- 9、Flannel部署
- 1_Flannel安装
- 2_修改Flannel配置文件
- 3_配置etcd中关于flannel的key
- 4_启动Flannel服务
- 5_查看各node中flannel产生的配置信息
- 10、Docker网络配置
- 11、跨Docker Host容器间通信验证
1、Docker容器默认网络模型
1_原理图
2_名词解释
docker0
- 是一个二层网络设备,即网桥
- 通过网桥可以将Linux支持的不同的端口连接起来
- 实现类交换机多对多的通信
veth pair
- 虚拟以太网(Ethernet)设备
- 成对出现,用于解决网络命名空间之间的隔离
- 一端连接 Container network namespace,另一端连接 host network namespace
2、Docker容器默认网络模型工作原理
1_容器访问外网
图解流程说明
1. 容器:
- 容器内的数据包首先通过容器内部的
eth0
虚拟网络接口。 eth0
是容器的网络接口,负责接收和发送容器内的数据包。
2. veth
(虚拟以太网设备):
- 每个容器都会与宿主机建立一对虚拟网络接口,称为 veth pair。
- 容器内的
eth0
通过veth
与 Docker 主机通信。 veth
的另一端连接到宿主机的网络桥docker0
。
3. docker0
(桥接网络):
docker0
是宿主机上由 Docker 创建的虚拟网络桥。- 它将容器的网络接口连接起来,使容器可以通过桥接与外部网络通信。
4. SNAT(源地址网络地址转换):
- 当容器需要与外网通信时,数据包会经过宿主机的
docker0
,然后通过宿主机的eth0
网络接口发送到外部网络。 - 在此过程中,宿主机会对数据包进行 SNAT,将数据包的源 IP 地址转换为宿主机的 IP 地址,以便能够在外部网络中正确路由。
5.外网:
- 经过 SNAT 的数据包通过宿主机的
eth0
网络接口到达外部网络。 - 返回的数据包会通过相反的路径返回到容器内。
创建容器
docker run -d --name web1 -p 8081:80 nginx:latest
检查 NAT 表中 POSTROUTING 链
iptables -t nat -vnL POSTROUTING
输出:
Chain POSTROUTING (policy ACCEPT 7 packets, 766 bytes)
pkts bytes target prot opt in out source destination
0 0 MASQUERADE tcp -- * * 172.17.0.2 172.17.0.2 tcp dpt:80
2_外网访问容器
DNAT:目标地址转换
iptables -t nat -vnL DOCKER
输出:
Chain DOCKER (2 references)
pkts bytes target prot opt in out source destination
0 0 RETURN 0 -- docker0 * 0.0.0.0/0 0.0.0.0/0
0 0 DNAT 6 -- !docker0 * 0.0.0.0/0 0.0.0.0/0 tcp dpt:8081 to:172.17.0.2:80
3、Docker容器四种网络模型
模式 | 使用方法 | 说明 |
---|---|---|
bridge [桥接式网络(Bridge container A)] | --network bridge | 桥接容器,除了有一块本地回环接口(Loopback interface)外,还有一块私有接口(Private interface)通过容器虚拟接口(Container virtual interface)连接到桥接虚拟接口(Docker bridge virtual interface),之后通过逻辑主机接口(Logical host interface)连接到主机物理网络(Physical network interface)。 桥接网卡默认会分配到172.17.0.0/16的IP地址段。 如果我们在创建容器时没有指定网络模型,默认就是(Nat)桥接网络,这也就是为什么我们在登录到一个容器后,发现IP地址段都在172.17.0.0/16网段的原因。 |
host [开放式容器(Open container)] | --network host | 比联盟式网络更开放,我们知道联盟式网络是多个容器共享网络(Net),而开放式容器(Open contaner)就直接共享了宿主机的名称空间。 因此物理网卡有多少个,那么该容器就能看到多少网卡信息。 我们可以说Open container是联盟式容器的衍生。 |
none [封闭式网络(Closed container)] | --network none | 封闭式容器,只有本地回环接口(Loopback interface,和咱们服务器看到的lo 接口类似),无法与外界进行通信。 |
container [联盟式网络(Joined container A | Joined container B ] | --network container:c1 (容器名称或容器ID) | 每个容器都各有一部分名称空间(Mount,PID,User),另外一部分名称空间是共享的(UTS,Net,IPC)。 由于它们的网络是共享的,因此各个容器可以通过本地回环接口(Loopback interface)进行通信。 除了共享同一组本地回环接口(Loopback interface)外,还有一块一块私有接口(Private interface)通过联合容器虚拟接口(Joined container virtual interface)连接到桥接虚拟接口(Docker bridge virtual interface),之后通过逻辑主机接口(Logical host interface)连接到主机物理网络(Physical network interface)。 |
4、Docker容器四种网络模型应用案例
1_查看已有的网络模型
查看已有的网络模型
[root@localhost ~]# docker network ls
NETWORK ID NAME DRIVER SCOPE
60a5207fbd78 bridge bridge local
0d19dc861451 host host local
682320e20891 none null local
查看已有网络模型详细信息
[root@localhost ~]# docker network inspect bridge
[
{
"Name": "bridge",
"Id": "60a5207fbd785569cf31650dd88ff7ac8237aea98ff90b3c4ea5c190e2b1795b",
"Created": "2024-12-07T11:15:50.734476157+08:00",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": null,
"Config": [
{
"Subnet": "172.17.0.0/16",
"Gateway": "172.17.0.1"
}
]
},
"Internal": false,
"Attachable": false,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
"Containers": {
"8365330d68b7ed06db7a842fc25387a0e354147e9829cfa7ab3c52dbfa3bb5dd": {
"Name": "web1",
"EndpointID": "743312da194149c307b6d33b875fadf42426601b95cb657096a6cac9cf8cb39f",
"MacAddress": "02:42:ac:11:00:02",
"IPv4Address": "172.17.0.2/16",
"IPv6Address": ""
}
},
"Options": {
"com.docker.network.bridge.default_bridge": "true",
"com.docker.network.bridge.enable_icc": "true",
"com.docker.network.bridge.enable_ip_masquerade": "true",
"com.docker.network.bridge.host_binding_ipv4": "0.0.0.0",
"com.docker.network.bridge.name": "docker0",
"com.docker.network.driver.mtu": "1500"
},
"Labels": {}
}
]
查看 docker 支持的网络模型
[root@localhost ~]# docker info | grep Network
Network: bridge host ipvlan macvlan null overlay
2_创建指定类型的网络模型
1 bridge
查看创建网络模型的帮助方法
docker network create --help
创建一个名称为mybr0
的网络
docker network create -d bridge --subnet "192.168.100.0/24" --gateway "192.168.100.1" -o com.docker.network.bridge.name=docker1 mybr0
查看已创建网络
[root@localhost ~]# docker network ls
NETWORK ID NAME DRIVER SCOPE
......
a6a1ad36c3c0 mybr0 bridge local
......
在 docker host 主机上可以看到多了一个网桥docker1
[root@localhost ~]# ifconfig
docker1: flags=4099<UP,BROADCAST,MULTICAST> mtu 1500
inet 192.168.100.1 netmask 255.255.255.0 broadcast 192.168.100.255
ether 02:42:14:aa:f5:04 txqueuelen 0 (Ethernet)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 20 bytes 1598 (1.5 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
启动一个容器并连接到已创建mybr0
网络
[root@localhost ~]# docker run -it --network mybr0 --rm busybox
/ # ifconfig
eth0 Link encap:Ethernet HWaddr 02:42:C0:A8:65:02
inet addr:192.168.100.2 Bcast:192.168.100.255 Mask:255.255.255.0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:18 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:2185 (2.1 KiB) TX bytes:0 (0.0 B)
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
UP LOOPBACK RUNNING MTU:65536 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
/ # exit
2 host
查看host
类型的网络模型
[root@localhost ~]# docker network ls
NETWORK ID NAME DRIVER SCOPE
......
0d19dc861451 host host local
......
查看 host 网络模型的详细信息
[root@localhost ~]# docker network inspect host
[
{
"Name": "host",
"Id": "0d19dc861451ad73e194530c11ea2c5cd36fd84185cdbdcbff652b4d86cd49ed",
"Created": "2024-12-05T09:34:58.338959535+08:00",
"Scope": "local",
"Driver": "host",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": null,
"Config": null
},
"Internal": false,
"Attachable": false,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
"Containers": {},
"Options": {},
"Labels": {}
}
]
创建容器使用 host 网络模型,并查看其网络信息
[root@localhost ~]# docker run -it --network host --rm busybox
/ # ifconfig
docker0 Link encap:Ethernet HWaddr 02:42:15:BA:C2:F7
inet addr:172.17.0.1 Bcast:172.17.255.255 Mask:255.255.0.0
inet6 addr: fe80::42:15ff:feba:c2f7/64 Scope:Link
UP BROADCAST MULTICAST MTU:1500 Metric:1
RX packets:73477 errors:0 dropped:0 overruns:0 frame:0
TX packets:145769 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:3022567 (2.8 MiB) TX bytes:527097953 (502.6 MiB)
docker1 Link encap:Ethernet HWaddr 02:42:3F:03:1B:E9
inet addr:192.168.100.1 Bcast:192.168.100.255 Mask:255.255.255.0
inet6 addr: fe80::42:3fff:fe03:1be9/64 Scope:Link
UP BROADCAST MULTICAST MTU:1500 Metric:1
RX packets:10 errors:0 dropped:0 overruns:0 frame:0
TX packets:33 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:678 (678.0 B) TX bytes:4322 (4.2 KiB)
ens33 Link encap:Ethernet HWaddr 00:0C:29:A4:42:BD
inet addr:192.168.150.145 Bcast:192.168.150.255 Mask:255.255.255.0
inet6 addr: fe80::20c:29ff:fea4:42bd/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:848483 errors:0 dropped:0 overruns:0 frame:0
TX packets:1113919 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:586827039 (559.6 MiB) TX bytes:252189967 (240.5 MiB)
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
inet6 addr: ::1/128 Scope:Host
UP LOOPBACK RUNNING MTU:65536 Metric:1
RX packets:259 errors:0 dropped:0 overruns:0 frame:0
TX packets:259 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:38326 (37.4 KiB) TX bytes:38326 (37.4 KiB)
/ # exit
运行Nginx服务
创建用于运行 nginx 应用的容器,使用 host 网络模型
docker run -d --network host nginx:latest
查看容器运行状态
[root@localhost ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
011b218e785c nginx:latest "/docker-entrypoint.…" 11 seconds ago Up 10 seconds hungry_mahavira
查看docker host 80
端口状态
[root@localhost ~]# ss -anput | grep ":80"
tcp LISTEN 0 511 0.0.0.0:80 0.0.0.0:* users:(("nginx",pid=1142601,fd=6),("nginx",pid=1142600,fd=6),("nginx",pid=1142599,fd=6),("nginx",pid=1142598,fd=6),("nginx",pid=1142563,fd=6))
tcp LISTEN 0 511 [::]:80 [::]:* users:(("nginx",pid=1142601,fd=7),("nginx",pid=1142600,fd=7),("nginx",pid=1142599,fd=7),("nginx",pid=1142598,fd=7),("nginx",pid=1142563,fd=7))
使用curl
命令访问 docker host 主机IP地址,验证是否可以对 nginx 进行访问,如可访问,则说明容器与 docker host 共享网络命名空间
[root@localhost ~]# curl http://localhost
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
3 none
查看none
类型的网络模型
[root@localhost ~]# docker network ls
NETWORK ID NAME DRIVER SCOPE
......
682320e20891 none null local
查看 none 网络模型详细信息
[root@localhost ~]# docker network inspect none
[
{
"Name": "none",
"Id": "682320e2089181ec6561e2c586b6f89e16c1a8e32f6f4db07769cc2a712a5cd9",
"Created": "2024-12-05T09:34:58.144297386+08:00",
"Scope": "local",
"Driver": "null",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": null,
"Config": null
},
"Internal": false,
"Attachable": false,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
"Containers": {},
"Options": {},
"Labels": {}
}
]
创建容器使用none
网络模型,并查看其网络状态
[root@localhost ~]# docker run -it --network none --rm busybox:latest
/ # ifconfig
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
inet6 addr: ::1/128 Scope:Host
UP LOOPBACK RUNNING MTU:65536 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
/ # exit
此类新类似于虚拟机的仅主机模式,是无法上网的,除非自己手动创建虚拟网络设备。
4 联盟网络
创建c1容器,使用默认网络模型
[root@localhost ~]# docker run -it --name c1 --rm busybox:latest
/ # ifconfig
eth0 Link encap:Ethernet HWaddr 02:42:AC:11:00:02
inet addr:172.17.0.2 Bcast:172.17.255.255 Mask:255.255.0.0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:17 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:2276 (2.2 KiB) TX bytes:0 (0.0 B)
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
inet6 addr: ::1/128 Scope:Host
UP LOOPBACK RUNNING MTU:65536 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
查看c1容器状态
[root@localhost ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
92a07e7ef663 busybox:latest "sh" 20 seconds ago Up 19 seconds c1
创建c2容器,与c1容器共享网络命名空间
[root@localhost ~]# docker run -it --name c2 --network container:c1 --rm busybox:latest
/ # ifconfig
eth0 Link encap:Ethernet HWaddr 02:42:AC:11:00:02
inet addr:172.17.0.2 Bcast:172.17.255.255 Mask:255.255.0.0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:20 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:2486 (2.4 KiB) TX bytes:0 (0.0 B)
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
inet6 addr: ::1/128 Scope:Host
UP LOOPBACK RUNNING MTU:65536 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
在c2容器中创建文件并开启httpd
服务
/ # echo "hello world" >> /tmp/index.html
/ # ls /tmp
index.html
/ # httpd -h /tmp
验证80端口是否打开
/ # netstat -npl
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 :::80 :::* LISTEN 10/httpd
在c1容器中进行访问验证
[root@localhost ~]# docker exec c1 wget -O - -q 127.0.0.1
hello world
查看c1容器/tmp目录,发现没有在c2容器中创建的文件,说明c1与c2仅共享了网络命名空间,没有共享文件系统
docker exec c1 ls /tmp
5、跨Docker Host容器间通信探讨
1_跨Docker Host容器间通信必要性
由于Docker容器运行的环境类似于在局域网中运行服务一样,无法直接被外界访问,如果采用在Docker Host利用端口映射方式会导致端口被严重消耗。
能够实现不同的Docker Host方便访问其它Docker Host之上的容器提供的服务
2_跨Docker Host容器间通信实现方案
1 Docker原生方案
overlay
- 基于VXLAN封装实现Docker原生overlay网络
macvlan
- Docker主机网卡接口逻辑上分为多个子接口,每个子接口标识一个VLAN,容器接口直接连接Docker Host
网卡接口
- 通过路由策略转发到另一台Docker Host
2 第三方方案
隧道方案
Flannel
- 支持UDP和VLAN封装传输方式
Weave
- 支持UDP和VXLAN
OpenvSwitch
- 支持VXLAN和GRE协议
路由方案
Calico
- 支持BGP协议和IPIP隧道
- 每台宿主机作为虚拟路由,通过BGP协议实现不同主机容器间通信。
6、Flannel
1_overlay network介绍
Overlay 网络是指在不改变现有网络基础设施的前提下,通过某种约定通信协议,把二层报文封装在IP报文之上的新的数据格式。
这样不但能够充分利用成熟的IP路由协议进程数据分发;而且在 Overlay 技术中采用扩展的隔离标识位数,能够突破 VLAN 的4000数量限制支持高达16M的用户,并在必要时可将广播流量转化为组播流量,避免广播数据泛滥。
因此,Overlay 网络实际上是目前最主流的容器跨节点数据传输和路由方案。
2_Flannel介绍
Flannel 是 CoreOS 团队针对 Kubernetes 设计的一个覆盖网络(Overlay Network)工具,其目的在于帮助每一个使用 Kuberentes 的 CoreOS 主机拥有一个完整的子网。
Flannel 通过给每台宿主机分配一个子网的方式为容器提供虚拟网络,它基于Linux TUN/TAP,使用 UDP 封装 IP包来创建 Overlay 网络,并借助 Etcd 维护网络的分配情况。
Flannel is a simple and easy way to configure a layer 3 network fabric designed for Kubernetes.
3_Flannel工作原理
Flannel 是 CoreOS 团队针对 Kubernetes 设计的一个网 络规划服务,简单来说,它的功能是让集群中的不同节点主机创建的 Docker 容器都具有全集群唯一的虚拟 IP地址。
但在默认的 Docker 配置中,每个 Node 的 Docker 服务会分别负责所在节点容器的 IP 分配。
Node 内部的容器之间可以相互访问,但是跨主机(Node)网络相互间是不能通信。
Flannel 设计目的就是为集群中所有节点重新规划IP地址的使用规则,从而使得不同节点上的容器能够获得"同属一个内网"且"不重复的"IP地址,并让属于不同节点上的容器能够直接通过内网 IP 通信。
Flannel 使用 Etcd 存储配置数据和子网分配信息。
Flannel 启动之后,后台进程首先检索配置和正在使用的子网列表,然后选择一个可用的子网,然后尝试去注册它。
Etcd 也存储这个每个主机对应的 IP。
Flannel 使用 Etcd 的 watch 机制监视/coreos.com/network/subnets
下面所有元素的变化信息,并且根据它来维护一个路由表。
为了提高性能,Flannel 优化了 Universal TAP/TUN 设备,对 TUN 和 UDP 之间的 IP 分片做了代理。
如下原理图:
1、数据从源容器中发出后,经由所在主机的docker0
虚拟网卡转发到flannel0
虚拟网卡,这是个 P2P 的虚拟网卡,Flanneld 服务监听在网卡的另外一端。
2、Flannel 通过 Etcd 服务维护了一张节点间的路由表,该张表里保存了各个节点主机的子网网段信息。
3、源主机的 flanneld 服务将原本的数据内容 UDP 封装后根据自己的路由表投递给目的节点的 flanneld 服务,数据到达以后被解包,然后直接进入目的节点的flannel0
虚拟网卡,然后被转发到目的主机的docker0
虚拟网卡,最后就像本机容器通信一样的由docker0
路由到达目标容器。
7、ETCD
Etcd 是 CoreOS 团队于2013年6月发起的开源项目,它的目标是构建一个高可用的分布式键值(key-value)数据库。
Etcd 内部采用raft
协议作为一致性算法,Etcd 基于Go语言实现。
Etcd 作为服务发现系统,具有以下特点:
- 简单:安装配置简单,而且提供了 HTTP API 进行交互,使用也很简单
- 安全:支持SSL证书验证
- 快速:根据官方提供的基准测试(benchmarking)数据,单实例支持每秒2k+读操作
- 可靠:采用 raft 算法,实现分布式系统数据的可用性和一致性
7.5、下面开始实现跨Docker Host容器间通信
8、ETCD部署
主机防火墙及SELINUX需要均关闭。
firewall-cmd --state
sestatus
1_主机名称配置
设置节点1的主机名
hostnamectl set-hostname node1
设置节点2的主机名
hostnamectl set-hostname node2
2_主机IP地址配置
节点1的网络配置
[root@localhost ~]# cat /etc/sysconfig/network-scripts/ifcfg-ens33
TYPE=Ethernet
PROXY_METHOD=none
BROWSER_ONLY=no
BOOTPROTO=static
DEFROUTE=yes
IPV4_FAILURE_FATAL=no
IPV6INIT=yes
IPV6_AUTOCONF=yes
IPV6_DEFROUTE=yes
IPV6_FAILURE_FATAL=no
IPV6_ADDR_GEN_MODE=stable-privacy
NAME=ens33
UUID=cc3b99f0-e07f-47cb-a602-a5b3fa13c451
DEVICE=ens33
ONBOOT=yes
IPADDR="192.168.150.131"
NETMASK="255.255.255.0"
GATEWAY="192.168.150.2"
DNS1="192.168.150.2"
节点2的网络配置
[root@localhost ~]# cat /etc/sysconfig/network-scripts/ifcfg-ens33
TYPE=Ethernet
PROXY_METHOD=none
BROWSER_ONLY=no
BOOTPROTO=static
DEFROUTE=yes
IPV4_FAILURE_FATAL=no
IPV6INIT=yes
IPV6_AUTOCONF=yes
IPV6_DEFROUTE=yes
IPV6_FAILURE_FATAL=no
IPV6_ADDR_GEN_MODE=stable-privacy
NAME=ens33
UUID=fe08c2ef-0105-42bf-845d-06e108b86420
DEVICE=ens33
ONBOOT=yes
IPADDR="192.168.150.132"
NETMASK="255.255.255.0"
GATEWAY="192.168.150.2"
DNS1="192.168.150.2"
3_主机名与IP地址解析
在两个节点中都进行IP地址解析操作
vim /etc/hosts
添加如下内容
192.168.150.131 node1
192.168.150.132 node2
4_开启内核转发
所有 Docker Host 中都开启内核转发
echo "net.ipv4.ip_forward=1" >> /etc/sysctl.conf
配置生效
sysctl -p
5_Etcd安装
我们要搭建 Etcd 集群,所以在两个节点中都安装
yum -y install etcd
6_Etcd配置
对 Etcd 进行配置,主要是对节点和集群进行配置
vim /etc/etcd/etcd.conf
节点1配置内容如下:
#[Member]
#ETCD_CORS=""
ETCD_DATA_DIR="/var/lib/etcd/node1.etcd"
#ETCD_WAL_DIR=""
ETCD_LISTEN_PEER_URLS="http://0.0.0.0:2380"
ETCD_LISTEN_CLIENT_URLS="http://0.0.0.0:2379,http://0.0.0.0:4001"
#ETCD_MAX_SNAPSHOTS="5"
#ETCD_MAX_WALS="5"
ETCD_NAME="node1"
#ETCD_SNAPSHOT_COUNT="100000"
# ........
#[Clustering]
ETCD_INITIAL_ADVERTISE_PEER_URLS="http://192.168.150.131:2380"
ETCD_ADVERTISE_CLIENT_URLS="http://192.168.150.131:2379,http://192.168.150.131:4001"
#ETCD_DISCOVERY=""
#ETCD_DISCOVERY_FALLBACK="proxy"
#ETCD_DISCOVERY_PROXY=""
#ETCD_DISCOVERY_SRV=""
ETCD_INITIAL_CLUSTER="node1=http://192.168.150.131:2380,node2=http://192.168.150.132:2380"
#ETCD_INITIAL_CLUSTER_TOKEN="etcd-cluster"
节点2配置内容如下
#[Member]
#ETCD_CORS=""
ETCD_DATA_DIR="/var/lib/etcd/node2.etcd"
#ETCD_WAL_DIR=""
ETCD_LISTEN_PEER_URLS="http://0.0.0.0:2380"
ETCD_LISTEN_CLIENT_URLS="http://0.0.0.0:2379,http://0.0.0.0:4001"
#ETCD_MAX_SNAPSHOTS="5"
#ETCD_MAX_WALS="5"
ETCD_NAME="node2"
#ETCD_SNAPSHOT_COUNT="100000"
# ........
#[Clustering]
ETCD_INITIAL_ADVERTISE_PEER_URLS="http://192.168.150.132:2380"
ETCD_ADVERTISE_CLIENT_URLS="http://192.168.150.132:2379,http://192.168.150.132:4001"
#ETCD_DISCOVERY=""
#ETCD_DISCOVERY_FALLBACK="proxy"
#ETCD_DISCOVERY_PROXY=""
#ETCD_DISCOVERY_SRV=""
ETCD_INITIAL_CLUSTER="node1=http://192.168.150.131:2380,node2=http://192.168.150.132:2380"
#ETCD_INITIAL_CLUSTER_TOKEN="etcd-cluster"
7_启动etcd服务
两个节点都启动
systemctl enable etcd
systemctl start etcd
8_检查端口状态
检查
netstat -tnlp | grep -E "4001|2380"
输出结果:
tcp6 0 0 :::4001 :::* LISTEN 50056/etcd
tcp6 0 0 :::2380 :::* LISTEN 50056/etcd
9_检查Etcd集群是否健康
访问集群端口验证集群状态
etcdctl -C http://192.168.150.131:2379 cluster-health
输出:
member adf6f6b228d1577a is healthy: got healthy result from http://192.168.150.131:2379
member baf1f0a8edfe9e89 is healthy: got healthy result from http://192.168.150.132:2379
cluster is healthy
查看成员,可以看到谁是 Leader
etcdctl member list
输出:
adf6f6b228d1577a: name=node1 peerURLs=http://192.168.150.131:2380 clientURLs=http://192.168.150.131:2379,http://192.168.150.131:4001 isLeader=false
baf1f0a8edfe9e89: name=node2 peerURLs=http://192.168.150.132:2380 clientURLs=http://192.168.150.132:2379,http://192.168.150.132:4001 isLeader=true
9、Flannel部署
1_Flannel安装
在两个节点中都安装 flannel
yum -y install flannel
2_修改Flannel配置文件
编辑配置文件
vim /etc/sysconfig/flanneld
节点1、节点2 配置相同:
# Flanneld configuration options
# etcd url location. Point this to the server where etcd runs
FLANNEL_ETCD_ENDPOINTS="http://192.168.150.131:2379,http://192.168.150.132:2379"
# etcd config key. This is the configuration key that flannel queries
# For address range assignment
FLANNEL_ETCD_PREFIX="/atomic.io/network"
# Any additional options that you want to pass
FLANNEL_OPTIONS="--logtostderr=false --log_dir=/var/log/ --etcd-endpoints=http://192.168.150.131:2379,http://192.168.150.132:2379 --iface=ens33"
3_配置etcd中关于flannel的key
Flannel 使用 Etcd 进行配置,来保证多个 Flannel 实例之间的配置一致性,所以需要在 Etcd 上进行配置。
使用时 key 的前缀要一致:/atomic.io/network/config
这个key与上面的/etc/sysconfig/flannel
中的配置项 FLANNEL_ETCD_PREFIX 是相对应的,不然启动就会出错
[root@node1 ~]# etcdctl mk /atomic.io/network/config '{"Network":"172.21.0.0/16"}'
{"Network":"172.21.0.0/16"}
或
[root@node1 ~]# etcdctl set /atomic.io/network/config '{"Network":"172.21.0.0/16"}'
{"Network":"172.21.0.0/16"}
由于 Etcd 已经搭建集群,所以可以在其他节点进行查看
[root@node2 ~]# etcdctl get /atomic.io/network/config
{"Network":"172.21.0.0/16"}
该IP网段可以任意设定,随便设定一个网段都可以。
容器的IP就是根据这个网段进行自动分配的,IP 分配后,容器一般是可以对外联网的(网桥模式,只要 Docker Host 能上网即可。)
4_启动Flannel服务
两台主机都启动
systemctl enable flanneld
systemctl start flanneld
5_查看各node中flannel产生的配置信息
注意子网信息
[root@node1 ~]# ls /run/flannel/
docker subnet.env
[root@node1 ~]# cat /run/flannel/subnet.env
FLANNEL_NETWORK=172.21.0.0/16
FLANNEL_SUBNET=172.21.51.1/24
FLANNEL_MTU=1472
FLANNEL_IPMASQ=false
[root@node2 ~]# ls /run/flannel/
docker subnet.env
[root@node2 ~]# cat /run/flannel/subnet.env
FLANNEL_NETWORK=172.21.0.0/16
FLANNEL_SUBNET=172.21.68.1/24
FLANNEL_MTU=1472
FLANNEL_IPMASQ=false
生效前的网络接口信息,注意docker0地址
[root@node1 ~]# ip a s
......
5: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default
link/ether 02:42:02:e0:7b:65 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
valid_lft forever preferred_lft forever
7: flannel0: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP> mtu 1472 qdisc pfifo_fast state UNKNOWN group default qlen 500
link/none
inet 172.21.51.0/16 scope global flannel0
valid_lft forever preferred_lft forever
inet6 fe80::3fe9:35df:6225:e948/64 scope link flags 800
valid_lft forever preferred_lft foreve
[root@node2 ~]# ip a s
......
5: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default
link/ether 02:42:ee:8f:1e:9d brd ff:ff:ff:ff:ff:ff
inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
valid_lft forever preferred_lft forever
6: flannel0: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP> mtu 1472 qdisc pfifo_fast state UNKNOWN group default qlen 500
link/none
inet 172.21.68.0/16 scope global flannel0
valid_lft forever preferred_lft forever
inet6 fe80::340a:b3d7:5158:1698/64 scope link flags 800
valid_lft forever preferred_lft forever
10、Docker网络配置
将 flannel 分配的 FLANNEL_SUBNET 地址配置到 docker 启动服务的配置文件中
--bip=172.21.x.1/24 --ip-masq=true --mtu=1472
放置于启动程序后
vim /usr/lib/systemd/system/docker.service
节点1配置如下,仅修改此行
# for containers run by docker
ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock --bip=172.21.51.1/24 --ip-masq=true --mtu=1472
节点2修改
# for containers run by docker
ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock --bip=172.21.68.1/24 --ip-masq=true --mtu=1472
存疑:如果fd://
与默认的unix:///var/run/docker.sock
冲突,可能导致无法监听?
systemctl stop docker.socket
systemctl disable docker.socket
重启 docker,两个节点都执行
systemctl daemon-reload
systemctl restart docker
查看生效后的配置
[root@node1 ~]# ip a s
......
5: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1472 qdisc noqueue state DOWN group default
link/ether 02:42:02:e0:7b:65 brd ff:ff:ff:ff:ff:ff
inet 172.21.51.1/24 brd 172.21.51.255 scope global docker0
valid_lft forever preferred_lft forever
7: flannel0: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP> mtu 1472 qdisc pfifo_fast state UNKNOWN group default qlen 500
link/none
inet 172.21.51.0/16 scope global flannel0
valid_lft forever preferred_lft forever
inet6 fe80::3fe9:35df:6225:e948/64 scope link flags 800
valid_lft forever preferred_lft foreve
[root@node2 ~]# ip a s
......
5: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1472 qdisc noqueue state DOWN group default
link/ether 02:42:ee:8f:1e:9d brd ff:ff:ff:ff:ff:ff
inet 172.21.68.1/24 brd 172.21.68.255 scope global docker0
valid_lft forever preferred_lft forever
6: flannel0: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP> mtu 1472 qdisc pfifo_fast state UNKNOWN group default qlen 500
link/none
inet 172.21.68.0/16 scope global flannel0
valid_lft forever preferred_lft forever
inet6 fe80::340a:b3d7:5158:1698/64 scope link flags 800
valid_lft forever preferred_lft forever
11、跨Docker Host容器间通信验证
在节点1的容器中进行测试
[root@node1 ~]# docker run -it --rm busybox:latest
/ # ifconfig
eth0 Link encap:Ethernet HWaddr 02:42:AC:15:33:02
inet addr:172.21.51.2 Bcast:172.21.51.255 Mask:255.255.255.0
UP BROADCAST RUNNING MULTICAST MTU:1472 Metric:1
RX packets:7 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:586 (586.0 B) TX bytes:0 (0.0 B)
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
inet6 addr: ::1/128 Scope:Host
UP LOOPBACK RUNNING MTU:65536 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
/ # ping 172.21.68.2 -c 4
PING 172.21.68.2 (172.21.68.2): 56 data bytes
64 bytes from 172.21.68.2: seq=0 ttl=60 time=1.084 ms
64 bytes from 172.21.68.2: seq=1 ttl=60 time=0.888 ms
64 bytes from 172.21.68.2: seq=2 ttl=60 time=0.778 ms
64 bytes from 172.21.68.2: seq=3 ttl=60 time=1.032 ms
--- 172.21.68.2 ping statistics ---
4 packets transmitted, 4 packets received, 0% packet loss
round-trip min/avg/max = 0.778/0.945/1.084 ms
在节点2的容器中进行测试
[root@node2 ~]# docker run -it --rm busybox:latest
/ # ifconfig
eth0 Link encap:Ethernet HWaddr 02:42:AC:15:44:02
inet addr:172.21.68.2 Bcast:172.21.68.255 Mask:255.255.255.0
UP BROADCAST RUNNING MULTICAST MTU:1472 Metric:1
RX packets:7 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:586 (586.0 B) TX bytes:0 (0.0 B)
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
inet6 addr: ::1/128 Scope:Host
UP LOOPBACK RUNNING MTU:65536 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
/ # ping 172.21.51.2 -c 4
PING 172.21.51.2 (172.21.51.2): 56 data bytes
64 bytes from 172.21.51.2: seq=0 ttl=60 time=0.855 ms
64 bytes from 172.21.51.2: seq=1 ttl=60 time=0.673 ms
64 bytes from 172.21.51.2: seq=2 ttl=60 time=0.831 ms
64 bytes from 172.21.51.2: seq=3 ttl=60 time=1.004 ms
--- 172.21.51.2 ping statistics ---
4 packets transmitted, 4 packets received, 0% packet loss
round-trip min/avg/max = 0.673/0.840/1.004 ms
跨 DockerHost 容器间通信成功