监控套件、CICD

This commit is contained in:
huanqing.shao
2019-11-24 22:52:09 +08:00
parent bcb610ffca
commit a296ea4821
24 changed files with 317 additions and 13 deletions

View File

@ -14,7 +14,7 @@ meta:
<div class="row">
<div class="col-md-4 col-sm-6">
<a href="#kubernetes免费教程">
<FancyImage src="/images/courses/free.png" title="免费教程" description="kubernetes.io权威资料kuboard翻译,网友校对" alt="K8S培训_免费教程" type="SlideLeft2Right"/>
<FancyImage src="/images/courses/free.png" title="免费教程" description="kubernetes.io 权威资料kuboard翻译" alt="K8S培训_免费教程" type="SlideLeft2Right"/>
</a>
</div>
<div class="col-md-4 col-sm-6">

Binary file not shown.

After

Width:  |  Height:  |  Size: 416 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 202 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 173 KiB

View File

@ -1,6 +1,7 @@
---
# vssueId: 158
vssueId: 167
layout: LearningLayout
sharingTitle: 深度长文 - 深入理解 Kubernetes 的网络模型
description: Kubernetes中_网络策略定义了一组Pod是否允许相互通信_或者与网络中的其他端点endpoint通信_本文描述了K8S集群中默认的网络策略
meta:
- name: keywords
@ -153,3 +154,94 @@ Pod1 发送一个数据包到其自己的默认以太网设备 `eth0`。
Kubernetes 的网络模型规定,在跨节点的情况下 Pod 也必须可以通过 IP 地址访问。也就是说Pod 的 IP 地址必须始终对集群中其他 Pod 可见;且从 Pod 内部和从 Pod 外部来看Pod 的IP地址都是相同的。接下来我们讨论跨节点情况下网络数据包如何传递。
### 数据包的传递Pod-to-Pod跨节点
在了解了如何在同节点上 Pod 之间传递数据包之后,我们接下来看看如何在跨节点的 Pod 之间传递数据包。Kubernetes 网络模型要求 Pod 的 IP 在整个网络中都可访问,但是并不指定如何实现这一点。实际上,这是所使用网络插件相关的,但是,仍然有一些模式已经被确立了。
通常,集群中每个节点都被分配了一个 CIDR 网段,指定了该节点上的 Pod 可用的 IP 地址段。一旦发送到该 CIDR 网段的流量到达节点,就由节点负责将流量继续转发给对应的 Pod。下图展示了两个节点之间的数据报文传递过程。
<p style="max-width: 600px">
<img src="./network.assets/pod-to-pod-different-nodes.gif" alt="K8S教程_Kubernetes网络模型_跨节点上Pod之间发送数据包"/>
</p>
图中,目标 Pod以绿色高亮与源 Pod以蓝色高亮在不同的节点上数据包传递过程如下
1. 数据包从 Pod1 的网络设备 `eth0`,该设备通过 `veth0` 连接到 root namespace
2. 数据包到达 root namespace 中的网桥 `cbr0`
3. 网桥上执行 ARP 将会失败,因为与网桥连接的所有设备中,没有与该数据包匹配的 MAC 地址。一旦 ARP 失败网桥会将数据包发送到默认路由root namespace 中的 `eth0` 设备)。此时,数据包离开节点进入网络
4. 假设网络可以根据各节点的CIDR网段将数据包路由到正确的节点
5. 数据包进入目标节点的 root namespaceVM2 上的 `eth0`)后,通过网桥路由到正确的虚拟网络设备(`veth1`
6. 最终,数据包通过 `veth1` 发送到对应 Pod 的 `eth0`,完成了数据包传递的过程
通常来说,每个节点知道如何将数据包分发到运行在该节点上的 Pod。一旦一个数据包到达目标节点数据包的传递方式与同节点上不同Pod之间数据包传递的方式就是一样的了。
此处我们直接跳过了如何配置网络以使得数据包可以从一个节点路由到匹配的节点。这些是与具体的网络插件实现相关的如果感兴趣可以深入查看某一个网络插件的具体实现。例如AWS上亚马逊提供了一个 [Container Network Interface(CNI) plugin](https://github.com/aws/amazon-vpc-cni-k8s) 使得 Kubernetes 可以在 Amazon VPC 上执行节点到节点的网络通信。
Container Network Interface(CNI) plugin 提供了一组通用 API 用来连接容器与外部网络。具体到容器化应用开发者来说,只需要了解在整个集群中,可以通过 Pod 的 IP 地址直接访问 Pod网络插件是如何做到跨节点的数据包传递这件事情对容器化应用来说是透明的。AWS 的 CNI 插件通过利用 AWS 已有的 VPC、IAM、Security Group 等功能提供了一个满足 Kubernetes 网络模型要求的,且安全可管理的网络环境。
> 在 EC2AWS 的虚拟机服务) 中,每一个实例都绑定到一个 elastic network interface ENI并且 VPC 中所有的 ENI 都是可连通的。默认情况下,每一个 EC2 实例都有一个唯一的 ENI但是可以随时为 EC2 实例创建多个 ENI。AWS 的 kubernetes CNI plugin 利用了这个特点,并为节点上的每一个 Pod 都创建了一个新的 ENI。由于在 AWS 的基础设施中, VPC 当中的 ENI 已经相互连接了,这就使得每一个 Pod 的 IP 地址天然就可在 VPC 内直接访问。当 CNI 插件安装到集群上是每一个节点EC2实例创建多个 elastic network interface 并且为其申请到 IP 地址,在节点上形成一个 CIDR 网段。当 Pod 被部署时kubernetes 集群上以 DaemonSet 形式部署的一段程序将接收到该节点上 kubelet 发出的添加 Pod 到 网络的请求。这段程序将从节点的可用 ENI 池中找出一个可用的 IP 地址,并将 ENI 及 IP 地址分配给 Pod具体做法是按照 [数据包的传递Pod-to-Pod同节点](#数据包的传递pod-to-pod同节点) 中描述的方式在 Linux 内核中连接虚拟网络设备和网桥。此时Pod 可以被集群内任意节点访问了。
## Pod-to-Service的网络
我们已经了解了如何在 Pod 的 IP 地址之间传递数据包。然而Pod 的 IP 地址并非是固定不变的,随着 Pod 的重新调度例如水平伸缩、应用程序崩溃、节点重启等Pod 的 IP 地址将会出现又消失。此时Pod 的客户端无法得知该访问哪一个 IP 地址。Kubernetes 中Service 的概念用于解决此问题。
一个 Kubernetes Service 管理了一组 Pod 的状态,可以追踪一组 Pod 的 IP 地址的动态变化过程。一个 Service 拥有一个 IP 地址,并且充当了一组 Pod 的 IP 地址的“虚拟 IP 地址”。任何发送到 Service 的 IP 地址的数据包将被负载均衡到该 Service 对应的 Pod 上。在此情况下Service 关联的 Pod 可以随时间动态变化,客户端只需要知道 Service 的 IP 地址即可(该地址不会发生变化)。
从效果上来说Kubernetes 自动为 Service 创建和维护了集群内部的分布式负载均衡,可以将发送到 Service IP 地址的数据包分发到 Service 对应的健康的 Pod 上。接下来我们讨论一下这是怎么做到的。
### netfilter and iptables
Kubernetes 利用 Linux 内建的网络框架 - `netfilter` 来实现负载均衡。Netfilter 是由 Linux 提供的一个框架,可以通过自定义 handler 的方式来实现多种网络相关的操作。Netfilter 提供了许多用于数据包过滤、网络地址转换、端口转换的功能,通过这些功能,自定义的 handler 可以在网络上转发数据包、禁止数据包发送到敏感的地址,等。
`iptables` 是一个 user-space 应用程序,可以提供基于决策表的规则系统,以使用 netfilter 操作或转换数据包。在 Kubernetes 中kube-proxy 控制器监听 apiserver 中的变化,并配置 iptables 规则。当 Service 或 Pod 发生变化时(例如 Service 被分配了 IP 地址,或者新的 Pod 被关联到 Servicekube-proxy 控制器将更新 iptables 规则,以便将发送到 Service 的数据包正确地路由到其后端 Pod 上。iptables 规则将监听所有发向 Service 的虚拟 IP 的数据包并将这些数据包转发到该Service 对应的一个随机的可用 Pod 的 IP 地址,同时 iptables 规则将修改数据包的目标 IP 地址(从 Service 的 IP 地址修改为选中的 Pod 的 IP 地址)。当 Pod 被创建或者被终止时iptables 的规则也被对应的修改。换句话说iptables 承担了从 Service IP 地址到实际 Pod IP 地址的负载均衡的工作。
在返回数据包的路径上,数据包从目标 Pod 发出此时iptables 规则又将数据包的 IP 头从 Pod 的 IP 地址替换为 Service 的 IP 地址。从请求的发起方来看,就好像始终只是在和 Service 的 IP 地址通信一样。
### IPVS
Kubernetes v1.11 开始,提供了另一个选择用来实现集群内部的负载均衡:[IPVS](/learning/k8s-intermediate/service/service-details.html#ipvs-代理模式)。 IPVSIP Virtual Server也是基于 netfilter 构建的,在 Linux 内核中实现了传输层的负载均衡。IPVS 被合并到 LVSLinux Virtual Server当中充当一组服务器的负载均衡器。IPVS 可以转发 TCP / UDP 请求到实际的服务器上,使得一组实际的服务器看起来像是只通过一个单一 IP 地址访问的服务一样。IPVS 的这个特点天然适合与用在 Kubernetes Service 的这个场景下。
当声明一个 Kubernetes Service 时,你可以指定是使用 iptables 还是 IPVS 来提供集群内的负载均衡工鞥呢。IPVS 是转为负载均衡设计的并且使用更加有效率的数据结构hash tables相较于 iptables可以支持更大数量的网络规模。当创建使用 IPVS 形式的 Service 时Kubernetes 执行了如下三个操作:
* 在节点上创建一个 dummy IPVS interface
* 将 Service 的 IP 地址绑定到该 dummy IPVS interface
* 为每一个 Service IP 地址创建 IPVS 服务器
将来IPVS 有可能成为 kubernetes 中默认的集群内负载均衡方式。这个改变将只影响到集群内的负载均衡,本文后续讨论将以 iptables 为例子,所有讨论对 IPVS 是同样适用的。
### 数据包的传递Pod-to-Service
<p style="max-width: 600px">
<img src="./network.assets/pod-to-service.gif" alt="K8S教程_Kubernetes网络模型_数据包的传递_Pod-to-Service"/>
</p>
在 Pod 和 Service 之间路由数据包时,数据包的发起和以前一样:
1. 数据包首先通过 Pod 的 `eth0` 网卡发出
2. 数据包经过虚拟网卡 `veth0` 到达网桥 `cbr0`
3. 网桥上的 APR 协议查找不到该 Service所以数据包被发送到 root namespace 中的默认路由 - `eth0`
4. 此时,在数据包被 `eth0` 接受之前,数据包将通过 iptables 过滤。iptables 使用其规则(由 kube-proxy 根据 Service、Pod 的变化在节点上创建的 iptables 规则)重写数据包的目标地址(从 Service 的 IP 地址修改为某一个具体 Pod 的 IP 地址)
5. 数据包现在的目标地址是 Pod 4而不是 Service 的虚拟 IP 地址。iptables 使用 Linux 内核的 `conntrack` 工具包来记录具体选择了哪一个 Pod以便可以将未来的数据包路由到同一个 Pod。简而言之iptables 直接在节点上完成了集群内负载均衡的功能。数据包后续如何发送到 Pod 上,其路由方式与 [Pod-to-Pod的网络](#Pod-to-Pod的网络) 中的描述相同。
### 数据包的传递Service-to-Pod
<p style="max-width: 600px">
<img src="./network.assets/service-to-pod.gif" alt="K8S教程_Kubernetes网络模型_数据包的传递_service-to-pod"/>
</p>
1. 接收到此请求的 Pod 将会发送返回数据包,其中标记源 IP 为接收请求 Pod 自己的 IP目标 IP 为最初发送对应请求的 Pod 的 IP
2. 当数据包进入节点后,数据包将经过 iptables 的过滤,此时记录在 `conntrack` 中的信息将被用来修改数据包的源地址(从接收请求的 Pod 的 IP 地址修改为 Service 的 IP 地址)
3. 然后,数据包将通过网桥、以及虚拟网卡 `veth0`
4. 最终到达 Pod 的网卡 `eth0`
### 使用DNS
Kubernetes 也可以使用 DNS以避免将 Service 的 cluster IP 地址硬编码到应用程序当中。Kubernetes DNS 是 Kubernetes 上运行的一个普通的 Service。每一个节点上的 `kubelet` 都使用该 DNS Service 来执行 DNS 名称的解析。集群中每一个 Service包括 DNS Service 自己)都被分配了一个 DNS 名称。DNS 记录将 DNS 名称解析到 Service 的 ClusterIP 或者 Pod 的 IP 地址。[SRV 记录](/learning/k8s-intermediate/service/dns.html#srv-记录) 用来指定 Service 的已命名端口。
DNS Pod 由三个不同的容器组成:
* `kubedns`:观察 Kubernetes master 上 Service 和 Endpoints 的变化,并维护内存中的 DNS 查找表
* `dnsmasq`:添加 DNS 缓存,以提高性能
* `sidecar`:提供一个健康检查端点,可以检查 `dnsmasq` 和 `kubedns` 的健康状态
DNS Pod 被暴露为 Kubernetes 中的一个 Service该 Service 及其 ClusterIP 在每一个容器启动时都被传递到容器中(环境变量及 /etc/resolves因此每一个容器都可以正确的解析 DNS。DNS 条目最终由 `kubedns` 解析,`kubedns` 将 DNS 的所有信息都维护在内存中。`etcd` 中存储了集群的所有状态,`kubedns` 在必要的时候将 `etcd` 中的 key-value 信息转化为 DNS 条目信息,以重建内存中的 DNS 查找表。
CoreDNS 的工作方式与 `kubedns` 类似,但是通过插件化的架构构建,因而灵活性更强。自 Kubernetes v1.11 开始CoreDNS 是 Kubernetes 中默认的 DNS 实现。
## Internet-to-Service的网络