一、docker网络基础
docker的网络是基于Linux namespace虚拟化实现的。
Docker本身的技术依赖于Linux内核虚拟化技术的发展。所以Docker对Linux内核的特性有很强的依赖。本章主要介绍Docker所使用的Linux网络技术。
1 网络基础
其中Docker使用到的与Linux网络有关的技术分别有:网络名称空间、Veth、Iptables、网桥、路由。
1.1 网络名称空间
为了支持网络协议栈的多个实例(多个docker容器,一个linux内核),在网络协议栈中引入了网络名称空间(Network Namespace),这些独立的协议栈被隔离到不同的命名空间中。处于不同的命名空间的网络协议栈是完全隔离的,彼此之间无法进行网络通信,就好像两个“平行宇宙”。通过这种对网络资源的隔离,就能在一个宿主机上虚拟多个不同的网络环境,而Docker正是利用这种网络名称空间的特性,实现了不同容器之间的网络隔离。在Linux的网络命名空间内可以有自己独立的Iptables 来转发、NAT及IP包过滤等功能。
Linux的网络协议栈是十分复杂的,为了支持独立的协议栈,相关的这些全局变量都必须修改为协议栈私有。最好的办法就是让这些全局变量成为一个Net Namespace变量的成员,然后为了协议栈的函数调用加入一个Namespace参数。这就是Linux网络名称空间的核心。所以的网络设备都只能属于一个网络名称空间。当然,通常的物理网络设备只能关联到root这个命名空间中。虚拟网络设备则可以被创建并关联到一个给定的命名空间中,而且可以在这些名称空间之间移动。
创建一个命名空间
[root@k8s-node1 ~]# ip netns add test01
[root@k8s-node1 ~]# ip netns add test02
[root@k8s-node1 ~]# ip netns list
test02
test01
[root@k8s-node1 ~]# ip netns add test1
[root@k8s-node1 ~]# ip netns add test2
[root@k8s-node1 ~]# ip netns list
test2
test1
1.2 Veth设备
Veth设备对
veth技术是docker root和容器间使用的技术(不是容器与容器使用的技术)
引入Veth设备对是为了在不同的网络名称空间之间进行通信,利用它可以直接将两个网络名称空间链接起来。由于要连接的两个网络命名空间,所以Veth设备是成对出现的,很像一对以太网卡,并且中间有一根直连的网线。既然是一对网卡,那么我们将其中一端称为另一端的peer 。在Veth设备的一端发送数据时,它会将数据直接发送到另一端,并触发另一端的接收操作。
Veth设备操作
# 创建veth对
# add 名字 type 类型 peer name 名字
[root@k8s-node1 ~]# sudo ip link add veth type veth peer name veth001
[root@k8s-node1 ~]# ip link show
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000
link/ether 08:00:27:b8:1f:f1 brd ff:ff:ff:ff:ff:ff
3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000
link/ether 08:00:27:8b:9b:3a brd ff:ff:ff:ff:ff:ff
4: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN mode DEFAULT group default
link/ether 02:42:2c:7a:07:44 brd ff:ff:ff:ff:ff:ff
5: flannel.1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue state UNKNOWN mode DEFAULT group default
link/ether 72:f6:10:6e:5f:9d brd ff:ff:ff:ff:ff:ff
6: cni0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue state UP mode DEFAULT group default qlen 1000
link/ether 6e:83:37:fa:b6:56 brd ff:ff:ff:ff:ff:ff
7: veth98a27231@if3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue master cni0 state UP mode DEFAULT group default
link/ether fe:b6:4e:35:3d:d0 brd ff:ff:ff:ff:ff:ff link-netnsid 0
8: vetha376bf13@if3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue master cni0 state UP mode DEFAULT group default
link/ether 46:00:a0:2a:7a:57 brd ff:ff:ff:ff:ff:ff link-netnsid 1
#
9: veth001@veth: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
link/ether 22:c4:9d:c6:9b:06 brd ff:ff:ff:ff:ff:ff
#
10: veth@veth001: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
link/ether be:10:28:7c:f0:c4 brd ff:ff:ff:ff:ff:ff
生成了两个veth设备, 互为对方的peer
# 把刚才的peer一端放到test1中
[root@k8s-node1 ~]# sudo ip link set veth001 netns test01
[root@k8s-node1 ~]# ip link show | grep veth
7: veth98a27231@if3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue master cni0 state UP mode DEFAULT group default
8: vetha376bf13@if3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue master cni0 state UP mode DEFAULT group default
# 会发现原来的veth001@veth不见了
10: veth@if9: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
已经查看不到veth001,当我们进入test01命名空间之后,就可以查看到
# 进入命名空间test01
[root@k8s-node1 ~]# sudo ip netns exec test01 bash
[root@k8s-node1 ~]# ip link show
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN mode DEFAULT group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
# 又找到啦
9: veth001@if10: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
link/ether 22:c4:9d:c6:9b:06 brd ff:ff:ff:ff:ff:ff link-netnsid 0
[root@k8s-node1 ~]# ip addr add 172.16.0.111/20 dev veth001
[root@k8s-node1 ~]# ip link show
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN mode DEFAULT group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
9: veth001@if10: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
link/ether 22:c4:9d:c6:9b:06 brd ff:ff:ff:ff:ff:ff link-netnsid 0 # 不知道为什么我这里还是没有ip,可能是因为与docker的ip冲突
# 查看对端veth设备
[root@k8s-node1 ~]# ip netns exec test01 ethtool -S veth001
NIC statistics:
peer_ifindex: 10
[root@k8s-node1 ~]# ip a | grep 10
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN group default qlen 1000
9: veth001@if10: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000
[root@k8s-node1 ~]# sudo ip link set veth netns test02
[root@k8s-node1 ~]# sudo ip netns exec test02 bash
[root@k8s-node1 ~]# ip addr add 172.16.0.112/20 dev veth
[root@k8s-node1 ~]# ip link show
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN mode DEFAULT group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
10: veth@if9: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
link/ether be:10:28:7c:f0:c4 brd ff:ff:ff:ff:ff:ff link-netnsid 0
# 重启 # 需要进入每个命名空间
sudo ip netns exec test01 bash
ip link set dev veth001 down
ip link set dev veth001 up
sudo ip netns exec test02 bash
ip link set dev veth001 down
ip link set dev veth001 up
互相ping就能ping通了
docker就使用了veth技术。
但是docker仅在容器和root之间使用了veth,而容器与容器间使用的网桥
在docker中看veth对不太好看,但我们可以观察到每删除一个容器root也会删除一个pair
1.3 网桥
Linux 可以支持多个不同的网络,它们之间能够相互通信,就需要一个网桥。 网桥是二层的虚拟网络设备,它是把若干个网络接口“连接”起来,从而报文能够互相转发。网桥能够解析收发的报文,读取目标 MAC 地址的信息,和自己记录的 MAC 表结合,来决定报文的转发目标网口。
网桥设备 brO 绑定了 eth0、 eth1 。对于网络协议栈的上层来说,只看得到 brO 。因为桥接是在数据链路层实现的 ,上层不需要关心桥接的细节,于是协议栈上层需要发送的报文被送到 brO ,网桥设备的处理代码判断报文该被转发到 eth0 还是 ethl ,或者两者皆转发。反过来,从 eth0 或从 ethl 接收到的报文被提交给网桥的处理代码,在这里会判断报文应该被转发、丢弃还是提交到协议栈上层。 而有时 ethl 也可能会作为报文的源地址或目的地址 直接参与报文的发送与接收,从而绕过网桥。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fVvQU3cG-1633444046382)(F:/youdaoyunnoteHAN/553736044@qq.com/532224a9f5a74a87b957d9365c0e9eb3/86-477893725.png)]
1.4 Iptables
我们知道, Linux 络协议栈非常高效,同时比较复杂 如果我们希望在数据的处理过程中对关心的数据进行一些操作该怎么做呢? Linux 提供了一套机制来为用户实现自定义的数据包处理过程。
在Linux网络协议栈中有一组回调函数挂接点,通过这些挂接点挂接的钩子函数可以在Linux 网络栈处理数据包的过程中对数据包进行 些操作,例如过滤、修改、丢弃等 整个挂接点技术叫作 Netfilter lptables
Netfilter 负责在内核中执行各种挂接的规则,运行在内核模式中:而 lptables 是在用户模式下运行的进程,负责协助维护内核中 Netfilter 的各种规则表 通过 者的配合来实现整个 Linux网络协议战中灵活的数据包处理机制。
总结
设备 | 作用总结 |
---|
network namespace | 主要提供了关于网络资源的隔离,包括网络设备、IPv4和IPv6协议栈、IP路由表、防火墙、/proc/net目录、/sys/class/net目录、端口(socket)等。 | linux Bridge | 功能相当于物理交换机,为连在其上的设备(容器)转发数据帧。如docker0网桥。 | iptables | 主要为容器提供NAT以及容器网络安全。 | veth pair | 两个虚拟网卡组成的数据通道。在Docker中,用于连接Docker容器和Linux Bridge。一端在容器中作为eth0网卡,另一端在Linux Bridge中作为网桥的一个端口。 |
二、docker网络模式
Docker使用Linux桥接,在宿主机虚拟一个Docker容器网桥(docker0),Docker启动一个容器时会根据Docker网桥的网段分配给容器一个IP地址,称为Container-IP ,同时Docker网桥是每个容器的默认网关(本局域网内处理不了的请求就交给网关处理)。因为在同一宿主机内的容器都接入同一个网桥,这样容器之间就能够通过容器的Container-IP直接通信。
Docker网桥是宿主机虚拟出来的,并不是真实存在的网络设备,外部网络是无法寻址到的,这也意味着外部网络无法通过直接Container-IP访问到容器。如果容器希望外部访问能够访问到,可以通过映射容器端口到宿主主机(端口映射),即docker run创建容器时候通过 -p 或 -P 参数来启用,访问容器的时候就通过[宿主机IP]:[容器端口] 访问容器。
docker的四种网络模式:
我们在使用docker run创建docker容器时,可以用-net选型指定容器的网络模式,这些网络模式的区别是容器命名空间和主机命名空间的关系。,docker有以下四种网络模式:
Docker网络模式 | 配置 | 说明 |
---|
host模式 | –net=host | 容器和宿主机共享Network namespace。 | container模式 | –net=container:NAME_or_ID | 容器和另外一个容器共享Network namespace。 kubernetes中的pod就是多个容器共享一个Network namespace。 | none模式 | –net=none | 容器有独立的Network namespace,但并没有对其进行任何网络设置,如分配veth pair 和网桥连接,配置IP等。 | bridge模式(默认) | –net=bridge | |
启用方式如:
docker run -d --network=host
或者
--net host
1)bridge模式(NAT)
当Docker进程启动时,会在主机上创建一个名为docker0的虚拟网桥,此主机上启动的Docker容器会连接到这个虚拟网桥上。虚拟网桥的工作方式和物理交换机类似,这样主机上的所有容器就通过交换机连在了一个二层网络中。
从docker0子网 中分配一个IP给容器使用,并设置docker0的IP地址为容器的默认网关。在主机上创建一对虚拟网卡veth pair设备(可以理解为网线),Docker将veth pair设备的一端放在新创建的容器中,并命名为eth0 (容器的网卡);另一端放在主机中,以vethxxx 这样类似的名字命名,并将这个网络设备加入到docker0网桥中。可以通过brctl show 命令查看。
bridge模式是docker的默认网络模式,不写–net参数,就是bridge模式。使用docker run -p时,docker实际是在iptables做了DNAT规则,实现端口转发功能。可以使用iptables -t nat -vnL 查看。
如果不指定的话,默认就会使用bridge模式,bridge本意是桥的意思,其实就是网桥模式。我们怎么理解网桥,如果需要做类比的话,我们可以把网桥看出一个二层的交换机设备。
交换机通信简图
也叫NAT
[root@node4 ~]
/
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
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
100: eth0@if101: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue state UP
link/ether 02:42:ac:06:f4:02 brd ff:ff:ff:ff:ff:ff
inet 172.6.244.2/24 brd 172.6.244.255 scope global eth0
valid_lft forever preferred_lft forever
网桥模式示意图
Linux能够起到虚拟交换机作用的网络设备,是网桥。他是一个工作在数据链路层(data link)的设备,主要的功能是根据MAC地址将数据包转发到网桥的不同端口上。
查看网桥
yum install -y bridge-utils
[root@localhost ~]
bridge name bridge id STP enabled interfaces
docker0 8000.0242cf195186 no veth10904eb
veth10ff0a9
veth1787878
veth8244792
veth9760247
vethbca21e7
关于brctl命令参数说明和示例
参数 | 说明 | 示例 |
---|
addbr | 创建网桥 | brctl addbr br10 | delbr | 删除网桥 | brctl delbr br10 | addif | 将网卡接口接入网桥 | brctl addif br10 eth0 | delif | 删除网桥接入的网卡接口 | brctl delif br10 eth0 | show | 查询网桥信息 | brctl show br10 | stp {on|off} | 启用禁用 STP | brctl stp br10 off/on | showstp | 查看网桥 STP 信息 | brctl showstp br10 | setfd | 设置网桥延迟 | brctl setfd br10 10 | showmacs | 查看 mac 信息 | brctl showmacs br10 |
docker网络
docker在启动一个容器时时如何实现容器间的互联互通的?
Docker创建一个容器的时候,会执行如下操作:
- 创建一对虚拟接口/网卡,也就是一对虚拟接口(veth pair)
- 本地主机一端桥接到默认的docker0或指定网桥上,并具有一个唯一的名字,如
veth9953b75 - 容器一端放到新启动的容器内部,并修改名字为
eth0 ,这个网卡/接口只在容器的命名空间可见; - 从网桥可用地址段中(也就是与该bridge对应的network)获取一个空闲地址分配给容器的eth0
- 配置默认路由到网桥
整个过程其实都是docker自动帮我们完成的,清理掉是所有的容器来验证:
基础知识
主机们在不在一个广播域,完全取决于主机连接的交换机端口们在不在同一个VLAN:
1. 如果在同一个VLAN,即使主机们的网段不相同,也是工作在一个广播域。 1.1 主机们的网段相同,可以ARP发现彼此的MAC,直接通信,不需要任何三层设备(网关)的介入。
1.2 主机们的网段不相同,即使在一个广播域,也不能直接通信,需要三层设备(网关)的介入。
2. 如果不在一个VLAN,主机们不在一个广播域 2.1 一个VLAN对应一个网段,那么主机之间的通信需要三层设备(网关)的介入。
2.2 如果很不巧,两个VLAN里的主机使用相同的网段,主机并不知道有VLAN 的存在,所以依然认为其它主机和自己在一个广播域,但是这个广播域被交换机VLAN逻辑隔离,成为两个广播域,这时无法使用三层设备使得它们通信,唯一的方法,使用一个网桥将两个VLAN二层桥接起来,它们就可以通信了。
所谓网关,就是上文提到的三层设备,可以是路由器、或三层交换机、防火墙。
哈哈,这个2.2的情况估计没有几个看得懂,凡是没点赞的都是看不懂的,整个知乎用户能看懂2.2情况的不会超过1000人…
网关是负责不同网络通信使用的。不同网络指的是 ip 地址中的网络号不同,比如 192.168.2.3/24,这个 ip 表示网络号为192.168.2(前24位)
比如 a 节点 ip 为192.168.2.1/24 , b 节点 ip 为 192.168.2.3/24 ,a 给 b 发送消息的时候,会先看是否在同一个网络,根据 b 的 ip 很容易判断出都是在 192. 168. 2这个网络内,所以 a 会直接给 b 发送消息(通过 b 的 mac 地址,这个 mac 地址是通过 arp 协议获取的) 。
c节点 ip 地址为 192.168.3.2/24 ,a 发送消息给 c, a 很容易知道 c 的网络地址是 192.168.3,与自己的网络地址不一样,这时候就会把这个消息发送给网关(也是通过 mac 地址),网关负责把消息发送给 c。
说白了,就是通信协议规定了,在同网段内可以直接通过 mac 通信,不同网段需要通过网关通信。
docker rm -f `docker ps -aq`
docker ps -a
[root@docker ~]
bridge name bridge id STP enabled interfaces
docker0 8000.0242cfb7aaca no 空
docker run -d --name test1 nginx:alpine
[root@docker ~]
bridge name bridge id STP enabled interfaces
docker0 8000.0242cfb7aaca no veth95f0f29
[root@docker ~]
131: veth95f0f29@if130: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default
[root@docker ~]
/
addr:172.17.0.2
/
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
0.0.0.0 172.17.0.1 0.0.0.0 UG 0 0 0 eth0
172.17.0.0 0.0.0.0 255.255.0.0 U 0 0 0 eth0
docker run -d --name test2 nginx:alpine
docker exec -it test2 sh
/
/
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
0.0.0.0 172.17.0.1 0.0.0.0 UG 0 0 0 eth0
172.17.0.0 0.0.0.0 255.255.0.0 U 0 0 0 eth0
[root@docker ~]
port no mac addr is local? ageing timer
1 32:76:d0:a3:0d:5c yes 0.00
1 32:76:d0:a3:0d:5c yes 0.00
2 86:4e:1c:5d:07:83 yes 0.00
2 86:4e:1c:5d:07:83 yes 0.00
ip a |grep -n3 eth
我们如何指定网桥上的这些虚拟网卡与容器端是如何对应?
通过ifindex,网卡索引号
[root@docker ~]
130
[root@docker ~]
134
[root@docker ~]
131: veth95f0f29@if130: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default
135: veth25234c9@if134: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default
容器与宿主机的通信
添加端口映射:
docker run --name test -d -p 8080:80 nginx:alpine
curl localhost:8080
端口映射通过iptables如何实现
访问本机的8088端口,数据包会从流入方向进入本机,因此涉及到PREROUTING【路由前】和INPUT链,我们是通过做宿主机与容器之间加的端口映射,所以肯定会涉及到端口转换,那哪个表是负责存储端口转换信息的呢,那就是nat表,负责维护网络地址转换信息的。
[root@docker ~]
Chain PREROUTING (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
26 1488 DOCKER all -- * * 0.0.0.0/0 0.0.0.0/0 ADDRTYPE match dst-type LOCAL
参数解释:
-t 对指定的表进行操作
-n 以数字的方式显示ip,它会将ip直接显示出来,如果不加-n,则会将ip反向解析成主机名。
-v 详细模式;-vvv :越多越详细
-L 列出链chain上面的所有规则,如果没有指定链,列出表上所有规则
规则利用了iptables的addrtype【地址类型】扩展,匹配网络类型为本地的包
[root@docker ~]
local 127.0.0.0/8 dev lo proto kernel scope host src 127.0.0.1
local 127.0.0.1 dev lo proto kernel scope host src 127.0.0.1
local 172.17.0.1 dev docker0 proto kernel scope host src 172.17.0.1
local 192.168.178.79 dev ens33 proto kernel scope host src 192.168.178.79
也就是说目标地址类型匹配到这些的,会转发到我们的TARGET中,TARGET是动作,意味着对符合要求的数据包执行什么样的操作,最常见的为ACCEPT(接受)和DROP(终止),此处的target(目标)为docker,很明显docker不是标准的动作,那docker是什么呢?我们通常会定义自定义的链,这样把某类对应的规则放在自定义链中,然后把自定义的链绑定到标准的链路中,因此此处docker是自定义的链。那我们现在就来看一下docker这个自定义链上的规则。
[root@docker ~]
Chain DOCKER (2 references)
pkts bytes target prot opt in out source destination
17 1020 RETURN all -- docker0 * 0.0.0.0/0 0.0.0.0/0
0 0 DNAT tcp -- !docker0 * 0.0.0.0/0 0.0.0.0/0 tcp dpt:8080 to:172.17.0.2:80
此条规则就是对主机收到的目的端口为8080的tcp流量进行DNAT转换,将流量发往172.17.0.2:80,172.17.0.2地址是不是就是我们上面创建的docker容器的ip地址,流量走到网桥上了,后面就走网桥的转发就ok了。所以,外加只需要访问192.168.178.79:8080就可以访问到容器中的服务了。
数据包在出来方向走postrouting链,查看一下规则
[root@docker ~]
Chain POSTROUTING (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
96 5925 MASQUERADE all -- * !docker0 172.17.0.0/16 0.0.0.0/0
0 0 MASQUERADE tcp -- * * 172.17.0.2 172.17.0.2 tcp dpt:80
MASQUERADE这个动作其实是一种更灵活的SNAT,把原地址转换成主机的出口ip地址,解释一下这条规则的意思:
这条规则会将原地址为172.17.0.0/16的包(也就是从docker容器产生的包),并且不是从docker0网卡发出的,进行原地址转换,转发成主机网卡的地址。大概的过程就是ACK的包在容器里面发出来,会路由到网桥docker0,网桥根据宿主机的路由规则会转给宿主机网卡eth0,这时候包就从docker0网卡转到eth0网卡了,并从eth0网卡发出去,这时候这条规则就会生效了,把源地址换成了eth0的ip地址。
注意一下,刚才这个过程涉及到了网卡间包的传递,那一定要打开主机的ip_forward转发服务,要不然包转不了,服务肯定访问不到。
2)host模式
如果启动容器的时候使用host模式,那么这个容器将不会获得一个独立的Network Namespace,而是和宿主机共用一个Network Namespace。容器将不会虚拟出自己的网卡,配置自己的IP等,而是使用宿主机的IP和端口。但是,容器的其他方面,如文件系统、进程列表等还是和宿主机隔离的。
使用host模式的容器可以直接使用宿主机的IP地址与外界通信,容器内部的服务端口也可以使用宿主机的端口,不需要进行NAT,host最大的优势就是网络性能比较好,但是docker host上已经使用的端口就不能再用了,网络的隔离性不好。
容器内部不会创建网络空间,共享宿主机的网络空间。
创建方式:
docker run -d --networkd=host
或者
--net host
比如直接通过host模式创建mysql容器:
$ docker run --net host -d --name mysql -e MYSQL_ROOT_PASSWORD=123456 mysql:5.7
$ curl localhost:3306
5.7.3Uid4??1[M/Z5NGRy}mysql_native_password!?
容器启动后,会默认监听3306端口,由于网络是host,因为可以直接通过宿主机的3306端口进行访问服务,效果等同于在宿主机直接启动mysqld的进程。
下面我们再创建个容器后简单看一下
[root@node4 ~]
/
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
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: ens192: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP qlen 1000
link/ether 00:50:56:b3:4c:8f brd ff:ff:ff:ff:ff:ff
inet 192.168.6.244/24 brd 192.168.6.255 scope global ens192
valid_lft forever preferred_lft forever
inet6 fe80::250:56ff:feb3:4c8f/64 scope link
valid_lft forever preferred_lft forever
3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN
link/ether 02:42:65:95:28:d8 brd ff:ff:ff:ff:ff:ff
inet 172.6.244.1/24 brd 172.6.244.255 scope global docker0
valid_lft forever preferred_lft forever
inet6 fe80::42:65ff:fe95:28d8/64 scope link
valid_lft forever preferred_lft forever
run --rm是什么:
在Docker容器退出时,默认容器内部的文件系统仍然被保留,以方便调试并保留用户数据。
但是,对于foreground容器,由于其只是在开发调试过程中短期运行,其用户数据并无保留的必要,因而可以在容器启动时设置–rm选项,这样在容器退出时就能够自动清理容器内部的文件系统。
显然,–rm选项不能与-d同时使用,即只能自动清理foreground容器,不能自动清理detached容器
3)container模式
这个模式指定新创建的容器和已经存在的一个容器共享一个network namespace,而不是和宿主机共享。新创建的容器不会创建自己的网卡,配置自己的IP,而是和一个指定的容器共享IP,端口范围等。同样,两个容器除了网络方面,其他的如文件系统,进程列表等还是隔离的,两个容器的进程可以通过IO网卡设备通信。
$ docker run --net host -d --name mysql -e MYSQL_ROOT_PASSWORD=123456 mysql:5.7
$ docker run -ti --rm --net=container:mysql busybox sh
/
PID USER TIME COMMAND
1 root 0:00 sh
12 root 0:00 ps aux
/
addr:172.17.0.1
/
tcp 0 0 :::3306 :::* LISTEN -
/
Connected to localhost
J
5.7.34Z..bHeO?
Nu/qXS
vl0mysql_native_password
!
在一下特殊的场景中非常有用,例如kubernetes的pod,kubernetes为pod创建一个基础设施容器,同一pod下的其他容器都以container模式共享这个基础设施的网络命名空间,相互之间以localhost访问,构成一个统一的整体。
联合网络
[root@node4 ~]
76f844e6057b6493a4a8933819ade7c29325ef17bc1fddc88bdf4c7ec60c620b
[root@node4 ~]
[root@node4 ~]
76f844e6057b
[root@node4 ~]
root@76f844e6057b:/
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
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>
root@76f844e6057b:/
4)none模式
使用none模式,Docker容器拥有自己的Network Namespace,但是,并不为Docker容器进行任何网络配置。也就是说,这个Docker容器没有网卡、IP、路由等信息。需要我们自己为Docker容器添加网卡、配置IP等。
这种网络模式下容器只有lo回环网络,没有其他网卡。none模式可以在容器创建时通过–network=none来指定。这种类型的网络没有办法联网,封闭的网络能很好的保证容器的安全性。
None模式示意图:
[root@node4 ~]
/
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
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
待整理:k8s
172.7.0.0/16 pod 172.7.21.0/24 172.7.22.0/24
10.4.7.0/34 节点 10.4.7.21 10.4.7.22
192.168.0.0/16 service
核心附件
CNI网络插件 -> flannel/calico
服务发现用插件 -> coredns
服务暴露用插件 -> traefik
GUI管理插件 -> Dashboard
service的三种代理模式
service的四种类型
- ClusterIP
- NodePort
- LoadBalancer
- ExternalName
kube-proxy提供的是集群网络,而不是podIP
常见的K8S安装部署方式:
1. Minikube单节点微型K8S(仅供学习、预览使用)
2. 二进制安装部署(生产首选,新手推荐)
3. 使用Kuberadmin进行部署,K8S的部署工具,跑在K8S里(相对简单,熟手推荐)
|