网络模型

This commit is contained in:
huanqing.shao
2019-11-19 11:56:43 +08:00
parent 840843c2c2
commit c51564b6b1
8 changed files with 95 additions and 0 deletions

View File

@ -207,6 +207,7 @@ module.exports = {
'k8s-intermediate/workload/wl-job/pattern',
'k8s-intermediate/workload/wl-job/usage',
'k8s-intermediate/workload/wl-job/when',
'k8s-intermediate/workload/wl-job/task_expansion',
]
},
{

View File

@ -0,0 +1,18 @@
apiVersion: batch/v1
kind: Job
metadata:
name: process-item-$ITEM
labels:
jobgroup: jobexample
spec:
template:
metadata:
name: jobexample
labels:
jobgroup: jobexample
spec:
containers:
- name: c
image: busybox
command: ["sh", "-c", "echo Processing item $ITEM && sleep 5"]
restartPolicy: Never

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

View File

@ -57,3 +57,79 @@ Pod 是 Kubernetes 中的最小可部署单元。一个 Pod 代表了集群中
### 节点Node
节点是Kubernetes集群中的一台机器可以是物理机也可以是虚拟机。
## Kubernetes网络模型
关于 Pod 如何接入网络这件事情Kubernetes 做出了明确的选择。具体来说Kubernetes 要求所有的网络插件实现必须满足如下要求:
* 所有的 Pod 可以与任何其他 Pod 直接通信,无需使用 NAT 映射network address translation
* 所有节点可以与所有 Pod 直接通信,无需使用 NAT 映射
* Pod 内部获取到的 IP 地址与其他 Pod 或节点与其通信时的 IP 地址是同一个
在这些限制条件下,需要解决如下四种完全不同的网络使用场景的问题:
1. Container-to-Container 的网络
2. Pod-to-Pod 的网络
3. Pod-to-Service 的网络
4. Internet-to-Service 的网络
## Container-to-Container的网络
通常,我们认为虚拟机中的网络通信是直接使用以太网设备进行的,如下图所示:
<p style="max-width: 480px">
<img src="./network.assets/eth0.png" alt="K8S教程_Kubernetes网络模型_虚拟机的以太网设备"/>
</p>
实际情况比这个示意图更加复杂一些。Linux系统中每一个进程都在一个 [network namespace](http://man7.org/linux/man-pages/man8/ip-netns.8.html) 中进行通信network namespace 提供了一个逻辑上的网络堆栈包含自己的路由、防火墙规则、网络设备。换句话说network namespace 为其中的所有进程提供了一个全新的网络堆栈。
Linux 用户可以使用 `ip` 命令创建 network namespace。例如下面的命令创建了一个新的 network namespace 名称为 `ns1`
```sh
$ ip netns add ns1
```
当创建 network namespace 时,同时将在 `/var/run/netns` 下创建一个挂载点mount point用于存储该 namespace 的信息。
执行 `ls /var/run/netns` 命令,或执行 `ip` 命令,可以查看所有的 network namespace
``` sh
$ ls /var/run/netns
ns1
$ ip netns
ns1
```
默认情况下Linux 将所有的进程都分配到 root network namespace以使得进程可以访问外部网络如下图所示
<p style="max-width: 480px">
<img src="./network.assets/root-namespace.png" alt="K8S教程_Kubernetes网络模型_root_network_namespace"/>
</p>
在 Kubernetes 中Pod 是一组 docker 容器的集合,这一组 docker 容器将共享一个 network namespace。Pod 中所有的容器都:
* 使用该 network namespace 提供的同一个 IP 地址以及同一个端口空间
* 可以通过 localhost 直接与同一个 Pod 中的另一个容器通信
Kubernetes 为每一个 Pod 都创建了一个 network namespace。具体做法是把一个 Docker 容器当做 “Pod Container” 用来获取 network namespace在创建 Pod 中新的容器时,都使用 docker run 的 `--network:container` 功能来加入该 network namespace参考 [docker run reference](https://docs.docker.com/engine/reference/run/#network-settings)。如下图所示,每一个 Pod 都包含了多个 docker 容器(`ctr*`),这些容器都在同一个共享的 network namespace 中:
<p style="max-width: 480px">
<img src="./network.assets/pod-namespace.png" alt="K8S教程_Kubernetes网络模型_pod_network_namespace"/>
</p>
此外Pod 中可以定义数据卷Pod 中的容器都可以共享这些数据卷,并通过挂载点挂载到容器内部不同的路径,具体请参考 [存储卷](/learning/k8s-intermediate/persistent/pv.html)
## Pod-to-Pod的网络
在 Kubernetes 中,每一个 Pod 都有一个真实的 IP 地址,并且每一个 Pod 都可以使用此 IP 地址与 其他 Pod 通信。本章节可以帮助我们理解 Kubernetes 是如何在 Pod-to-Pod 通信中使用真实 IP 的,不管两个 Pod 是在同一个节点上,还是集群中的不同节点上。我们将首先讨论通信中的两个 Pod 在同一个节点上的情况,以避免引入跨节点网络的复杂性。
从 Pod 的视角来看Pod 是在其自身所在的 network namespace 与同节点上另外一个 network namespace 进程通信。在Linux上不同的 network namespace 可以通过 [Virtual Ethernet Device](http://man7.org/linux/man-pages/man4/veth.4.html) 或 ***veth pair*** (两块跨多个名称空间的虚拟网卡)进行通信。为连接 pod 的 network namespace可以将 ***veth pair*** 的一段指定到 root network namespace另一端指定到 Pod 的 network namespace。每一组 ***veth pair*** 类似于一条网线,连接两端,并可以使流量通过。节点上有多少个 Pod就会设置多少组 ***veth pair***。下图展示了 veth pair 连接 Pod 到 root namespace 的情况:
<p style="max-width: 480px">
<img src="./network.assets/pod-veth-pairs.png" alt="K8S教程_Kubernetes网络模型_veth_pair_per_pod"/>
</p>
此时,我们的 Pod 都有了自己的 network namespace从 Pod 的角度来看,他们都有自己的以太网卡以及 IP 地址,并且都连接到了节点的 root network namespace。为了让 Pod 可以互相通过 root network namespace 通信,我们将使用 network bridge网桥
Linux Ethernet bridge 是一个虚拟的 Layer 2 网络设备可用来连接两个或多个网段network segment。网桥的工作原理是在源于目标之间维护一个转发表forwarding table通过检查通过网桥的数据包的目标地址destination和该转发表来决定是否将数据包转发到与网桥相连的另一个网段。桥接代码通过网络中具备唯一性的网卡MAC地址来判断是否桥接或丢弃数据。
网桥实现了 [ARP](https://en.wikipedia.org/wiki/Address_Resolution_Protocol) 协议,以发现链路层与 IP 地址绑定的 MAC 地址。当网桥收到数据帧时网桥将该数据帧广播到所有连接的设备上除了发送者以外对该数据帧做出相应的设备被记录到一个查找表中lookup table。后续网桥再收到发向同一个 IP 地址的流量时将使用查找表lookup table来找到对应的 MAC 地址,并转发数据包。
<p style="max-width: 480px">
<img src="./network.assets/pods-connected-by-bridge.png" alt="K8S教程_Kubernetes网络模型_network_bridge_网桥_虚拟网卡"/>
</p>