云原生技术:应用状态监控与网络

11:可观测性、监控和日志

1)需求来源

当把应用迁移到kubernetes之后,如何保障应用的健康和稳定?

  • 1 提高应用的可观测性
  • 2 提高应用的可恢复能力

具体方法:

  • 1 可以实时观测应用的健康状态
  • 2 可以获取应用的资源使用情况
  • 3 可以拿到应用的实时日志,进行问题的诊断与分析

2)应用健康状态-Liveness与Readiness

Liveness(存活指针) Readness(就绪指针)
介绍 用于判断容器是否存活,即Pod状态是否为Running,如果Liveness探针判断容器不健康,则会触发kubelet杀掉容器,并根据配置的策略判断是否重启容器,如果默认不配置Liveness探针,则认为返回值默认为成功 用于判断容器是否启动完成,即Pod的Condition是否为Ready,如果探测结果不成功,则会将Pod从Endpoint中移除,直至下一次判断成功,再将Pod挂回到Endpoint上
检测失败 杀掉Pod 切断上层流量到Pod
适用场景 支持重新拉起的应用 启动后无法立即对外服务的应用
Liveness与Readiness
注意事项 不论是Liveness还是Readness探针,选择合适的探测方式可以防止被误操作:1、调大判断的超时阈值,防止在容器压力较高的情况下出现偶发超时;2、调整判断的次数阈值,3次的默认值在短周期下不一定是最佳实践;3、exec如果执行的是shell脚本判断,在容器中可能调用时间会非常长;4、使用tcpSocket的方式遇到TLS的场景,需要业务层判断是否有影响

3)问题诊断

状态机制

应用故障排查-常见应用异常

  • Pod停留在Pending:Pending表示调度器没有介入,可以通过kubectl describe pod,查看事件排查,通常和资源使用相关
  • Pod停留在waiting:一般表示Pod的镜像没有正常拉取,通常可能和私有镜像拉取,镜像地址不存在,镜像公网拉取相关
  • Pod不断被拉起且可以看到crashing:通常表示Pod已经完成调度并启动,但是启动失败,通常是由于配置、权限造成,需要查看Pod日志
  • Pod处在Running但是没有正常工作:通常是由于部分字段拼写错误造成的,可以通过校验部署来排查,例如:Kubectl apply -validate -f pod.yaml
  • Service无法正常工作:在排除网络插件自身的问题之外,最可能的是label配置有问题,可以通过查看endpoint的方式进行检查

应用问题诊断的三个步骤:

  • 1 通过describe查看状态,通过状态判断排查方向
  • 2 查看对象的event事件,获取更详细的信息
  • 3 查看Pod的日志,确定应用自身的情况

12:可观测性:监控和日志

1)背景

监控和日志是大型分布式系统的重要基础设施,监控可以帮助开发者查看系统的运行状态,日志可以协助问题的排查。
Kubernetes 定义了介入的接口标准和规范,任何符合接口标准的监控和日志组件都可以快速集成。

2)监控

监控类型

  • 1 资源监控:CPU、内存、网络等资源类的指标,常以数值、百分比为单位进行统计,是最常见的资源监控方式
  • 2 性能监控:应用的内部监控,通常通过Hook的机制在虚拟机层、字节码执行层隐式回调,或者在应用层显示注入,获取更深层次的监控指标,常用来应用诊断与调优
  • 3 安全监控:针对安全进行一系列监控策略,例如越权管理、安全漏洞扫描等
  • 4 事件监控:k8s中一种另类的监控方式,紧密贴合k8s的设计理念,补充常规方案的缺欠与弊端

Prometheus-开源社区的监控”标准“

  • 简洁强大的接入标准
  • 多种数据采集、离线方式
  • k8s的兼容
  • 丰富的插件机制与生态
  • Prometheus Operator的助力

3)日志

日志的场景

  • 主机内核的日志:主机内核日志可以协助开发者诊断,例如:网络栈异常、驱动异常、文件系统异常,影响节点(内核)稳定的异常
  • Runtime的日志:最常见的运行是Docker,可以通过Docker的日志排查,例如Pod Hang等问题
  • 核心组件的日志:APIServer日志可以用来审计,Scheduler日志可以诊断调度,etcd日志可以查看存储状态,Ingress日志可以分析接入层流量
  • 部署应用的日志:可以通过应用日志分析查看业务层的状态,诊断异常

13:Kubernetes网络概念及策略控制

1)Kubernetes基本网络模型

基本法:约法三章+四大目标
Kubernetes对于Pod间的网络没有任何限制,只需要满足如下[三个基本条件]:

  • 所有Pod可以与其他Pod直接通信,无需显式使用NAT(Network Address Translation)
  • 所有Pod可以与所有Pod直接通信,无需显式使用NAT
  • Pod可见的IP地址为其他Pod与其通信时所用,无需显式转换

基于以上准入条件,我们在审视一个网络方案的时候,需要考虑如下[四大目标]:

  • 容器与容器间的通信
  • Pod与Pod之间的通信
  • Pod与Service之间的通信
  • 外部世界与Service间的通信

2) Netns探秘

Network namespace是实现网络虚拟化的内核基础,创建了隔离的网络空间

  • 拥有独立的附属网络设备(Io、veth等虚设备/物理网卡)
  • 独立的协议栈,IP地址和路由表
  • iptables规则
  • ipvs等

Pod和Netns的关系
每个Pod拥有独立的Netns空间,Pod内的Container共享该空间,可通过Loopback接口实现通信,或通过共享的Pod-IP对外提供服务。别忘记,宿主机上还有一个Root Netns,可以看做一个特殊的容器空间

3)典型网络容器解决方案

容器网络是K8S邻域最百花齐放的一个领域,依照IaaS层的配置、外部物理网络的设备、性能or灵活优先,可以有不同的实现:

  • Flannel:最为普遍,提供多种网络backend实现,覆盖多种场景
  • Calico:采用BGP提供网络直连,功能丰富,对底层网络有要求
  • Canal:(Flannel for network + Calico for firewalling),嫁接型创新项目
  • Cilium: 基于eBPF和XDP的高性能Overlay网络方案
  • Kube-router:同样采用BGP提供网络直连,集成基于LVS的负载均衡能力
  • Romana: 采用BGP or OSPF提供网络直连能力的方案
  • WeaveNet:采用UDP封装实现L2 Overlay,支持用户态(慢,可加密)/内核态(快,不能加密)两种实现

4)Network Policy基本概念

Network Policy提供了基于策略的网络控制,用于隔离应用并减少攻击面。它使用标签选择器模拟传统的分段网络,并通过策略控制它们之间的流量以及来自外部的流量

5)小结

  • 1 Pod在容器网络中的核心概念是IP,每个Pod必须有内外视角一致的独立IP地址
  • 2 影响容器网络性能的关键是拓扑设计,也就是数据包端到端的路径设计
  • 3 牢记Overlay/Underlay下各种网络方案的设计选择,如果不知道,可以这样选:普适性最强Flannel-VxLan,2层可直连Calico/Flannel-Hostgw
  • 4 Network Policy是个强大的工具,可以实现Ingress的流量精确控制,关键是选择好Pod Selector

14:Kubernetes Services

1)需求来源

Kubernetes应用应如何相互调用?

  • Pod生命周期短暂,IP地址随时变化
  • Deployment等的Pod组需要统一访问入口和做负载均衡
  • 应用间在不同环境部署时保持同样的部署拓扑和访问方式

Services :Kubernetes中的服务发现与负载均衡

Kubernetes服务发现架构

15:深入剖析Linux容器

以Docker为例的容器:cgroup+namespace+docker image

怎么保证这个进程所用到的资源是被隔离和被限制住的,在 Linux 内核上面是由 cgroup 和 namespace 这两个技术来保证的.

1)资源隔离和限制

隔离方式 用途
mount 保证容器看到的文件系统的视图,是容器镜像提供的一个文件系统,也就是说它看不见宿主机上的其他文件,除了通过 -v 参数 bound 的那种模式,是可以把宿主机上面的一些目录和文件,让它在容器里面可见的
uts 隔离了 hostname 和 domain
pid 保证了容器的 init 进程是以 1 号进程来启动的
network 网络 namespace,除了容器用 host 网络这种模式之外,其他所有的网络模式都有一个自己的 network namespace 的文件
user 控制用户 UID 和 GID 在容器内部和宿主机上的一个映射,不过这个 namespace 用的比较少
ipc 控制了进程兼通信的一些东西,比方说信号量
cgroup 用 cgroup namespace 带来的一个好处是容器中看到的 cgroup 视图是以根的形式来呈现的,这样的话就和宿主机上面进程看到的 cgroup namespace 的一个视图方式是相同的。另外一个好处是让容器内部使用 cgroup 会变得更安全

两种cgroup驱动

驱动 作用
cytemd cgroup driver 限制内存是多少,要用 CPU share 为多少,其实直接把 pid 写入对应的一个 cgroup 文件,然后把对应需要限制的资源也写入相应的 memory cgroup 文件和 CPU 的 cgroup 文件就可以了
cgroupfs cgroup driver systemd 本身可以提供一个 cgroup 管理方式。所以如果用 systemd 做 cgroup 驱动的话,所有的写 cgroup 操作都必须通过 systemd 的接口来完成,不能手动更改 cgroup 的文件

容器中常用的cgroup

cgroup 作用
cpu cpuset cpuacct CPU 一般会去设置 cpu share 和 cupset,控制 CPU 的使用率
memory 控制进程内存的使用量
device device 控制了你可以在容器中看到的 device 设备
freezer、device 当你停止容器的时候,freezer 会把当前的进程全部都写入 cgroup,然后把所有的进程都冻结掉,这样做的目的是,防止你在停止的时候,有进程会去做 fork。这样的话就相当于防止进程逃逸到宿主机上面去,是为安全考虑
blkio 限制容器用到的磁盘的一些 IOPS 还有 bps 的速率限制
pid pid cgroup 限制的是容器里面可以用到的最大进程数量

2)容器镜像

以docker images为例:

  • 基于联合文件系统
  • 不同的层可以被其他镜像复用
  • 容器的可写层可以做成镜像新的一层

以overlay文件系统为例:

组件 介绍
merged 整合了ower层和upper读写层显示出来的视图
upper 容器读写层
workdir 类似中间层,对upper层的写入,先写入workdir,再移入upper层
lower 镜像层,只读层

文件操作:

  • 读:如果upper层没有副本,数据都从lower读上来
  • 写:容器创建出来时,upper层是空的,只有对文件进行写操作时,才会从lower层拷贝文件上来,对副本进行操作
  • 删:删除操作不影响lower层,删除操作通过对文件进行标记,使文件无法显示

3)容器引擎

上图如果把它分成左右两边的话,可以认为 containerd 提供了两大功能。
第一个是对于 runtime,也就是对于容器生命周期的管理,左边 storage 的部分其实是对一个镜像存储的管理。containerd 会负责镜像的拉取、镜像的存储
按照水平层次来看的话:
第一层是 GRPC,containerd 对于上层来说是通过 GRPC serve 的形式来对上层提供服务的。Metrics 这个部分主要是提供 cgroup Metrics 的一些内容。
下面这层的左边是容器镜像的一个存储,中线 images、containers 下面是 Metadata,这部分 Matadata 是通过 bootfs 存储在磁盘上面的。右边的 Tasks 是管理容器的容器结构,Events 是对容器的一些操作都会有一个 Event 向上层发出,然后上层可以去订阅这个 Event,由此知道容器状态发生什么变化。
最下层是 Runtimes 层,这个 Runtimes 可以从类型区分,比如说 runC 或者是安全容器之类的。

16:深入理解etcd-基本原理解析

1)基本介绍

etcd诞生于CoreOS公司,最初用于解决集群管理系统中的OS升级的分布式并发控制以及配置文件的存储与分发等问题。基于此,etcd被设计为提供高可用、强一致的小型KeyValue数据存储服务。项目当前隶属于CNCF基金会,被包括AWS、Google、Microsoft、Alibaba等大型互联网公司广泛使用。

2)架构及内部机制解析

一个 etcd 集群,通常会由 3 个或者 5 个节点组成,多个节点之间,通过一个叫做 Raft 一致性算法的方式完成分布式一致性协同,算法会选举出一个主节点作为 leader,由 leader 负责数据的同步与数据的分发,当 leader 出现故障后,系统会自动地选取另一个节点成为 leader,并重新完成数据的同步与分发。客户端在众多的 leader 中,仅需要选择其中的一个就可以完成数据的读写。

这里面有一个关键点,它基于一个前提:任意两个 quorum 的成员之间一定会有一个交集,也就是说只要有任意一个 quorum 存活,其中一定存在某一个节点,它包含着集群中最新的数据。正是基于这个假设,这个一致性算法就可以在一个 quorum 之间采用这份最新的数据去完成数据的同步,从而保证整个集群向前衍进的过程中其数据保持一致。

etcd API接口

接口 功能
Put(key, value)/Delete(key) put 与 delete 的操作都非常简单,只需要提供一个 key 和一个 value,就可以向集群中写入数据了,那么在删除数据的时候,只需要提供 key 就可以了
Get(key)/Get(keyFrom,keyEnd) 查询操作。查询操作 etcd 支持两种类型的查询:第一种是指定单个 key 的查询,第二种是指定的一个 key 的范围
Watch(key/keyPrefix) etcd 启动了 Watch 的机制,也就是我们前面提到的用于实现增量的数据更新,watch 也是有两种使用方法,第一种是指定单个 key 的 Watch,另一种是指定一个 key 的前缀。在实际应用场景的使用过程中,经常采用第二种
Transactions(if/then/else ops).Commit() API 是 etcd 提供的一个事务操作,可以通过指定某些条件,当条件成立的时候执行一组操作。当条件不成立的时候执行另外一组操作
Leases:Grant/Revoke/KeepAlive Leases 接口是分布式系统中常用的一种设计模式

3)典型的应用场景

场景 功能
元数据存储-Kubernetes 元数据高可用,无单点故障;系统无状态,故障修复方案简单;系统可水平扩展,提高性能及容量;简化架构实现,降低系统工程的复杂度
Service Discovery(Nameing Service-名字服务) 资源注册;存活性检测;API gateway无状态,可水平扩展;支持上万个进程的规模
Distributed Coordination: leader election 将其中的一个 Master 选主成 Leader,负责控制整个集群中所有 Slave 的状态。被选主的 Leader 可以将自己的 IP 注册到 etcd 中,使得 Slave 节点能够及时获取到当前组件的地址,从而使得系统按照之前单个 Master 节点的方式继续工作。当 Leader 节点发生异常之后,通过 etcd 能够选取出一个新的节点成为主节点,并且注册新的 IP 之后,Slave 又能够拉取新的主节点的 IP,从而会继续恢复服务
Distributed Coordination-分布式系统并发控制 分布式信号量;自动踢出故障节点;存储进程的执行状态

17:深入理解etcd:etcd性能优化实践

  • Raft 层,Raft 需要通过网络同步数据,网络 IO 节点之间的 RTT 和 / 带宽会影响 etcd 的性能。除此之外,WAL 也受到磁盘 IO 写入速度影响.
  • 再来看 Storage 层,磁盘 IO fdatasync 延迟会影响 etcd 性能,索引层锁的 block 也会影响 etcd 的性能。除此之外,boltdb Tx 的锁以及 boltdb 本身的性能也将大大影响 etcd 的性能。
  • 从其他方面来看,etcd 所在宿主机的内核参数和 grpc api 层的延迟,也将影响 etcd 的性能。

18:Kubernetes调度过程

1) Kubenetes基础调度能力

资源调度-满足Pod资源要求

  • Resources:CPU/Memory/Storage/GPU/FGPA
  • QoS:Guaranteed(敏感型、需要保障业务)/Burstable(次敏感型、需要弹性业务)/BestEffort(可容忍型业务)
  • Resource Quota(为每个NameSpace配置ResourceQuota来防止过量使用,保障他人的资源可用)

关系调度-满足Pod/Node的特殊关系、条件要求

  • PodAffinity(Pod亲和调度)/PodAntiAffinity(Pod反亲和调度):Pod和Pod之间的关系
  • NodeSelector/NodeAffinity:由Pod决定适合自己的Node
  • Taint/Tolerations:限制调度到某些Node,给Pods配置容忍标记

Kubernetes高级调度能力-如何做到集群资源合理利用?

  • 创建自定义的一些优先级类别(PriprityClass)
  • 给不同类型Pods配置不同的优先级(PriorityClassName)
  • 通过组合不同类型Pods运行和优先级抢占让集群资源和调度弹性起来

19:调度器的调度流程和算法介绍

调度器架构
  • preFilter:对Pod的请求做预处理
  • Filter:自定义Filter逻辑
  • PostFilter:可以用于logs/metircs,或者对Score之前做数据预处理
  • Score:自定义的Score逻辑
  • Reserve:有状态的plugin可以对资源做内存记账
  • Permit:wait, deny, approve,可以作为gang的插入点
  • PreBind:在真正bind node之前,执行一些操作,例如:云盘挂载到Node上
  • Bind:一个Pod只会被一个BindPlugin处理
  • PostBind:bind成功之后执行的逻辑
  • Unreserve:在permit到Bind这几个阶段只要报错就回退

20:GPU管理和Device Plugin工作机制

为什么要用Kubernetes管理以GPU为代表的异构资源?

  • 加速部署:通过容器构建避免重复部署机器学习复杂环境
  • 提升集群资源使用率:统一调度和分配集群资源
  • 保障资源独享:利用容器隔离异构设备,避免相互影响
资源的上报和监控
  • 第一步是 Device Plugin 的注册,需要 Kubernetes 知道要跟哪个 Device Plugin 进行交互。这是因为一个节点上可能有多个设备,需要 Device Plugin 以客户端的身份向 Kubelet 汇报三件事情。
  • 第二步是服务启动,Device Plugin 会启动一个 GRPC 的 server。在此之后 Device Plugin 一直以这个服务器的身份提供服务让 kubelet 来访问,而监听地址和提供 API 的版本就已经在第一步完成了;
  • 第三步,当该 GRPC server 启动之后,kubelet 会建立一个到 Device Plugin 的 ListAndWatch 的长连接, 用来发现设备 ID 以及设备的健康状态。当 Device Plugin 检测到某个设备不健康的时候,就会主动通知 kubelet。而此时如果这个设备处于空闲状态,kubelet 会将其移除可分配的列表。但是当这个设备已经被某个 Pod 所使用的时候,kubelet 就不会做任何事情,如果此时杀掉这个 Pod 是一个很危险的操作。
  • 第四步,kubelet 会将这些设备暴露到 Node 节点的状态中,把设备数量发送到 Kubernetes 的 api-server 中。后续调度器可以根据这些信息进行调度。

你可能感兴趣的:(云原生技术:应用状态监控与网络)