Kubernetes-网络原理(0) - 网络知识预备
Docker 是“新瓶装旧酒”的产物,依赖于 Linux 内核技术 chroot 、namespace 和 cgroup。本篇先来看 namespace 技术。
Docker 和虚拟机技术一样,从操作系统级上实现了资源的隔离,它本质上是宿主机上的进程(容器进程),所以资源隔离主要就是指进程资源的隔离。实现资源隔离的核心技术就是 Linux namespace。这技术和很多语言的命名空间的设计思想是一致的(如 C++ 的 namespace)。
第零篇的话,我们就来看看最基础的 namespace
,和我们后续需要使用的 Tcpdump
这个抓包工具。
NAMESPACE
我们都知道 Docker
的基础是 NAMESPACE
,通过NAMESPACE
我们做到不同的隔离,因为我们这次只聊网络,那我们来看看NAMESPACE
的网络隔离。
创建一个
Network Namespace
1
ip netns add <new namespace name>
假如我们创建一个
test
的namespace
1
ip netns add test
namespace
操作1
ip netns exec <you namespace name> <operator>
我们打开一个 bash 在
test
的namespace
中1
2
3ip netns exec test bash
# 查询下网络信息
ip a我们获得一个有趣的结果
1
2
3root@debian:~# ip a
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN group default qlen 1
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00我们默认获得一个回环地址的网卡,并没有启动,那我们让其启动
1
2
3
4
5
6
7
8
9
10ip netns exec test ip link set dev lo up
# 再次查看IP
ip netns exec test ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default 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我们就获得一个 IP 地址,这样的话,我们系统内部通讯就有了一个
IP
地址。在
Network Namespace
相互通讯
我们首先在Namespace
打开一个Shell
1
ip netns exec test zsh
然后在里面启动一个
HTTP
服务1
echo "Hello world" > index.html ; python -m SimpleHTTPServer 8080
我们再开启一个新的的
Shell
1
2
3
4ip netns exec test zsh
# 尝试访问 8080,得到 hello word 的结果
~ curl localhost:8080
Hello world
网络抓包
我们已经创建了一个虚拟的网络,内部的通讯就是通过这个 localhost
进行通讯。
我们使用 tcpdump
进行网络抓包
监听 lo 的回环网卡
tcpdump -i lo
分析数据包
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21listening on lo, link-type EN10MB (Ethernet)
## TCP 链接建立
# TCP 第一次握手 Client -> Server,Seq = N
15:03:42.394751 IP localhost.42514 > localhost.http-alt: Flags [S], seq 435521204, win 43690, options [mss 65495,sackOK,TS val 3638139 ecr 0,nop,wscale 7], length 0
# TCP 第二次握手 Server -> Client,ACK = N+1, SEQ = J
15:03:42.394774 IP localhost.http-alt > localhost.42514: Flags [S.], seq 1254554874, ack 435521205, win 43690, options [mss 65495,sackOK,TS val 3638139 ecr 3638139,nop,wscale 7], length 0
# TCP 第三次握手 Client -> Server,Seq = J + 1,这里的ACK = 1 是相对报文的开始
15:03:42.394792 IP localhost.42514 > localhost.http-alt: Flags [.], ack 1, win 342, options [nop,nop,TS val 3638139 ecr 3638139], length 0
## TCP 数据发送
# 发送HTTP报文 1 - 79 部分
15:03:42.396258 IP localhost.42514 > localhost.http-alt: Flags [P.], seq 1:79, ack 1, win 342, options [nop,nop,TS val 3638139 ecr 3638139], length 78: HTTP: GET / HTTP/1.1
# 服务端应答收到
15:03:42.396372 IP localhost.http-alt > localhost.42514: Flags [.], ack 79, win 342, options [nop,nop,TS val 3638139 ecr 3638139], length 0
# 客户端发送额外的 18 部分
15:03:42.396999 IP localhost.http-alt > localhost.42514: Flags [P.], seq 1:18, ack 79, win 342, options [nop,nop,TS val 3638139 ecr 3638139], length 17: HTTP: HTTP/1.0 200 OK
# 服务端应答收到
15:03:42.397002 IP localhost.42514 > localhost.http-alt: Flags [.], ack 18, win 342, options [nop,nop,TS val 3638139 ecr 3638139], length 0
# 客户端发送 Fin + Ack
15:03:42.398629 IP localhost.42514 > localhost.http-alt: Flags [F.], seq 79, ack 199, win 342, options [nop,nop,TS val 3638140 ecr 3638139], length 0
# 服务端响应结束
15:03:42.398639 IP localhost.http-alt > localhost.42514: Flags [.], ack 80, win 342, options [nop,nop,TS val 3638140 ecr 3638140], length 0
镜像准备
因为为了方便我们在容器内调试网络,我使用ubuntu
构建一个工具箱的镜像
1 | docker pull yannxia/ubuntu-with-tcpdump |
里面包含了本次实验所需要的所有的网络工具。
How Network Namespace Work
至于 Network namespace
怎么工作的?我们知道对于不同的 Namespace
是相互隔离的,我们需要打通的话,我们需要建立一个 Veth
设备对。我们将 Veth0
放置于某个 Namespace
而将 Veth1
放置于另外一个 Namespace
。
对于 Docker
来说,我们的 Veth
默认还会挂载到 Bridge
上
对于 IPTABLES 工作在 IPV4 和 IPV6 收到包,而收到包是在网卡接收到之后,所以在配置 Iptables
的时候,我们基于 interface
进行配置。
参考
- introducing-linux-network-namespaces
- Tcpdump Commands
- yannxia/ubuntu-with-tcpdump
- A deep dive into Linux namespaces
TCP 标志位
序号 | TCP 标志位 | 解释 |
---|---|---|
1 | SYN | 建立连接 |
2 | FIN | 关闭连接 |
3 | ACK | 响应 |
4 | PSH | 数据传输 |
5 | RST | 链接重置 |