k8s基础介绍

一、容器云发展及主要内容.

1.1 云计算,交付标准( iaas-----openstack)

国内:阿里云一华为云(振兴杯)百度云 (私有云)
国外: AWS

1.2 平台即服务(PAAS)
  1. 例如:新浪云( 号称免运维)
    用户下单一>下单到sina运维, 进行环境构建,平台级的运维

  2. 迭代:产生出来很多运维工具,例如ansible,这些运维工具可以帮我自动化创建–些环境,但是,不同环境的要求不一样,需要考虑、解决各种环境匹配、兼容问题。

  3. docker统一 了 运行环境、发布方式、
    同时,docker- -》自动构建运行环境封装体一-》 docker 成为这一代PAAS的运 行环境标准

  4. 问题:若将容器集群化,要如何管理?
    一 》 资源管理器/资源管理框架(管理工具) :
    早期是mesos (Apache基金会)早期只作为资源管理平台,开源、分布式的管理框架,后来被推特看上,做为基础平台,大规模盛行
    2019年推特宣布不用mesos、 而全部使用kubernetes
    ①mesos 官方公布,可以在我的平台,上管理k8s
    但是k8s与底层虚拟化相性很简单,未必需要多一步使用mesos
    ②docker swarm : docker 父公司的产品,他也是一-种docker 集群化管理的解决方案。

  5. 优势:轻量
    ①但是相对于K8s而言,实现的功能还是比较少,例如k8s 的
    滚动更新、回滚,可以实现,但是很复杂,除此之外大规模集群的使用和管理还是很强大的。
    ②kubernetes稳定、适合生产、全面,成为了主要的解决方案一》谷歌
    kubernetes的名字来自希腊语,意思是“舵手”或“ 领航员" , K8s是将8个字t母"ubernete"替换为“8"的缩写。

1.3 软件及服务(SAAS )

直接使用成品(直接访问服务端)

1.4 小结
1.4.1 K8s的由来

KubernetesGoogle10年容器化基础架构一-》borg架构(内部资源管理器)
随着docker流行,Borg 派出几个内部工程师,使用go语言以Borg系统设计思路
设计了一款新的资源管理系统一》kubernetes,并且开源贡献给了容器基金会一-》当前的标准

1.4.2 K8s的特性
  1. 轻量级:- -些解释性语言:例如Python/JavaScript / Perl /Shell, 效率较低,占用内存资源较多
    使用go语言一》编译型语言,语言级别支持进程管理,不需要人为控制,所以以go开发的资源消耗占用资源小

  2. 开源

  3. 自我修复(控制器控制pod,保证pod可以维持我们所期望的副本数量3)
    在节点故障时重新启动失败的容器,替换和重新部署,保证预期的副本数量:杀死健康检查失败的容器,并且在未准备好之前不会处理客户端请求,确保线上服务不中断。对异常状态的容器进行重启或重建(先删除、再创建),目的是保证业务线不中断

  4. 弹性伸缩
    Yml --> 阈值cpu使用率> 808 - -》 触发扩容pod (CPU使用.上限,docker-cgroup k8s —> 1、limit 2、configmap-配置文件 ),使用命令、UI或者基于CPu使用情况自动快速扩容和缩容应用程序实例,保证应用业务高峰并发时的高可用性:业务低峰时回收资源,以最小成本运行服务。
    伸缩一-》扩容和缩容(节点应用类型nginx)
    弹性一》人为只要指定规则,满足条件时,就会自动触发扩容或缩容的操作

  5. 自动部署和回滚
    K8S采用滚动更新策略更新应用,一次更新一个Pod,而不是同时删除所有Pod,如果更新过程中出现问题,将回滚更改,确保升级不受影响业务

  6. 服务发现和负载均衡
    K8s为多个pod(容器)提供–个统–访问入口(内部IP地址和一-个DNS名称),并且负载均衡关联的所有容器,使得用户无需考虑容器IP问题,使用IPVS (章文嵩)框架–>替代”iptables

  7. 机密和配置管理(secret–》安全/认证加密性的数据)
    管理机密数据和应用程序配置,而不需要把敏感数据暴露在镜像里,提高敏感数据安全性。并可以将一些常用的配置存储在K8S中,方便应用程序使用。

  8. 存储编排(静态、动态)
    挂载外部存储系统,无论是来自本地存储,公有云(如Aws),还是网络存储(如NFS、GlusterFs、 Ceph)都作为集群资源的一部分使用, 极大提高存储使用灵活性。

  9. 批处理.
    提供一次性任务(job),定时任务(crontab):满足批量数据处理和分析的场景
    目的:K8S目标是为了让部署容器化应用、管理容器集群资源更加简单高效

1.5 k8s特性总结
  1. 轻量级::重点在于开发的语言(解释性语言go,系统资源消耗较少)
  2. 开源
  3. 自我修复–》控制器
  4. 弹性伸缩一-》 yml定义的阈值( cgroups控制的1imit资源上限)和伸缩方式(水平)
  5. 自动部署、回滚一》yml定义的(部署方式list-watch机制, rollback回滚)
  6. 服务发现、负载均衡一-》 services +kube-proxy
  7. 机密和配置管理一》RBAC + configmap (配置中心)
  8. 存储编排-》静态+动态:NFS gfs等网络存储+本地存储+云存储(以上是静态),pv+pvc动态
  9. 批处理–》一-次性任务和周期性任务。

二 基本组件

2.1 Pod(最小的资源单位)

一-个pod会封装多个容器组成一一个子节点的运行环境(最小单元,容器的数量2+)
最小部署单元

一- 组容器的集合( 基础容器+主应用容器+挂斗/副容器)
–个Pod中的容器共享网络命名空间(基础容器提供的pause)
Pod是短暂的(叙述的是其生命周期)

2.2 Pod控制器(维护Pod状态,期望值)

什么是控制器–》对不同的对象及其特性使用不同的方式控制管理一-》
控制器说明:

类型描述
ReplicaSet确保预期的Pod副本数量
Depl oyment无状态应用控制器(部署)
State fulSet有状态应用部署
DaemonSet确保所有Node运行同一种Pod I
Job ,一次性任务
Cronjob定时任务

服务分类

2.2.1 ①无状态服务: LVS,

服务不依赖自身的状态,实例的状态数据可以维护在内存中。任何一-个请求都可以被任意-一个实例处理。
不存储状态数据,实例可以水平拓展,通过负载均衡将请求分发到各个节点王
在一个封闭的系统中,只存在一-个数据闭环。
通常存在于单体架构的集群中。

2.2.2②有状态服务:例如数据库(需要持久化)

服务本身依赖或者存在局部的状态数据,这些数据需要自身持久化或者可以通过其他节点恢复。
一一个请求只能被某个节点(或者同等状态下的节点)处理。
存储状态数据,实例的拓展需要整个系统参与状态的迁移。
在一个封闭的系统中,存在多个数据闭环,需要考虑这些闭环的数据一致性问题。
通常存在于分布式架构中。

  1. 简化:1

无状态服务:就是没有特殊状态的服务,各个请求对于服务器来说统一无差别处理,请求自身携带了所有服务端所需要的所有参数(服务端自身不存储跟请求相关的任何数据,不包括数据库存储信息
有状态服务:与之相反,有状态服务在服务端保留之前请求的信息,用以处理当前请求,比如session等

  1. 简化2

有状态:需要持久化,多次请求之间需要共享- -些信息
无状态:一次性,不需要持久化,每次请求都是一条新的数据
对于docker来说,更适合应用无状态服务,而kubernetes, 提供了一种解决方案一-》 多种存储类型

–>例如:
configmap (配置管理中心),主要存储配置文件
Secret:用户密码、需要加密的文件
volume:基本数据(网页文件)
**PV, pVC:动态创建过程

四.kubernetes简介

4.1 k8s是什么
k8s是一个全新的基于容器技术的分布式架构解决方案,并且是一个一站式的完备的分布式系统开发和支撑平台。 
4.2 k8s不是什么
1、Kubernetes不限制支持应用的类型,不限制应用框架。不限制受支持的语言runtimes (例如, Java, Python, Ruby),满足12-factor applications 。不区分 “apps” 或者“services”。Kubernetes支持不同负载应用,包括有状态、无状态、数据处理类型的应用。只要这个应用可以在容器里运行,那么就能很好的运行在Kubernetes上。
2、Kubernetes不提供中间件(如message buses)、数据处理框架(如Spark)、数据库(如Mysql)或者集群存储系统(如Ceph)作为内置服务。但这些应用都可以运行在Kubernetes上面。
3、Kubernetes不部署源码不编译应用。持续集成的 (CI)工作流方面,不同的用户有不同的需求和偏好的区域,因此,我们提供分层的 CI工作流,但并不定义它应该如何工作。
4、Kubernetes允许用户选择自己的日志、监控和报警系统。
5、Kubernetes不提供或授权一个全面的应用程序配置 语言/系统(例如,jsonnet)。
6、Kubernetes不提供任何机器配置、维护、管理或者自修复系统。 
4.3 k8s能做什么
1、多个进程(作为容器运行)协同工作。(Pod)
2、存储系统挂载
3、Distributing secrets
4、应用健康检测
5、应用实例的复制
6、Pod自动伸缩/扩展
7、Naming and discovering
8、负载均衡
9、滚动更新
10、资源监控
11、日志访问
12、调试应用程序
13、提供认证和授权
4.4 k8s组成

Kubernetes 主要由以下几个核心组件组成:

etcd 保存了整个集群的状态;
kube-apiserver 提供了资源操作的唯一入口,并提供认证、授权、访问控制、API 注册和发现等机制;
kube-controller-manager 负责维护集群的状态,比如故障检测、自动扩展、滚动更新等;
kube-scheduler 负责资源的调度,按照预定的调度策略将 Pod 调度到相应的机器上;
kubelet 负责维持容器的生命周期,同时也负责 Volume(CVI)和网络(CNI)的管理;
Container runtime 负责镜像管理以及 Pod 和容器的真正运行(CRI),默认的容器运行时为 Docker;
kube-proxy 负责为 Service 提供 cluster 内部的服务发现和负载均衡;
4.5集群架构图
一个简单架构图,不含dashboard,只有一个master和两个node

在这里插入图片描述
官网配图:
在这里插入图片描述
除了核心组件,还有一些推荐的 Add-ons:

kube-dns 负责为整个集群提供 DNS 服务
Ingress Controller 为服务提供外网入口
Heapster 提供资源监控
Dashboard 提供 GUI
Federation 提供跨可用区的集群
Fluentd-elasticsearch 提供集群日志采集、存储与查询

五 组件简介

5.1 master组件
5.1.1 kube-apiserver
功能
1)提供了集群管理的REST API接口(包括认证授权、数据校验以及集群状态变更)2)提供其他模块之间的数据交互和通信的枢纽(其他模块通过API Server查询或修改数据,只有API Server才直接操作etcd);
3)是资源配额控制的入口

工作原理
在这里插入图片描述
如何访问apiserver

k8s通过kube-apiserver这个进程提供服务,该进程运行在单个k8s-master节点上。默认有两个端口。

  • 2)安全端口

1)该端口默认值为6443,可通过启动参数“–secure-port”的值来修改默认值;
2)默认IP地址为非本地(Non-Localhost)网络端口,通过启动参数“–bind-address”设置该值;
3)该端口用于接收HTTPS请求;
4)用于基于Tocken文件或客户端证书及HTTP Base的认证;
5)用于基于策略的授权;
6)默认不启动HTTPS安全访问控制。

访问apiserver的方式

  • 1)curl

    curl localhost:8080/api
    curl localhost:8080/api/v1/pods
    curl localhost:8080/api/v1/services
    curl localhost:8080/api/v1/replicationcontrollers

  • 2)kube-controller-manager与apiserver交互

kube-controller-manager中的Node Controller模块通过API Server提供的Watch接口,实时监控Node的信息,并做相应处理。

  • 3)kube-scheduler与apiserver交互

Scheduler通过API Server的Watch接口监听到新建Pod副本的信息后,它会检索所有符合该Pod要求的Node列表,开始执行Pod调度逻辑。调度成功后将Pod绑定到目标节点上。

apiserver参数介绍

API Server 主要是和 etcd 打交道,并且对外提供 HTTP 服务,以及进行安全控制,因此它的命令行提供的参数也主要和这几个方面有关。下面是一些比较重要的参数以及说明(不同版本参数可能会有不同):

在这里插入图片描述

5.1.2 kube-scheduler

kube-scheduler 负责分配调度 Pod 到集群内的节点上,它监听 kube-apiserver,查询还未分配 Node 的 Pod,然后根据调度策略为这些 Pod 分配节点(更新 Pod 的 NodeName 字段)。
https://feisky.gitbooks.io/kubernetes/components/scheduler.html

  • 调度器需要充分考虑诸多的因素:
    • 公平调度
    • 资源高效利用
    • Qos
    • affinity和anti-affinity
    • 数据本地化(data locality)
    • 内部负载干扰(inter-workload interference)
    • deadlines
  • 指定node节点调度

有三种方式可以指定 Pod 只运行在指定的 Node 节点上
1)nodeSelector:只调度到匹配指定 label 的 Node 上
2)nodeAffinity:功能更丰富的 Node 选择器,比如支持集合操作
3)podAffinity:调度到满足条件的 Pod 所在的 Node 上

  • taints和tolerations

Taints 和 tolerations 用于保证 Pod 不被调度到不合适的 Node 上,其中 Taint 应用于 Node 上,而 toleration 则应用于 Pod 上。
目前支持的 taint 类型:
1)NoSchedule:新的 Pod 不调度到该 Node 上,不影响正在运行的 Pod
2)PreferNoSchedule:soft 版的 NoSchedule,尽量不调度到该 Node 上
3)NoExecute:新的 Pod 不调度到该 Node 上,并且删除(evict)已在运行的 Pod。Pod 可以增加一个时间(tolerationSeconds)

  • 优先级调度

从 v1.8 开始,kube-scheduler 支持定义 Pod 的优先级,从而保证高优先级的 Pod 优先调度。并从 v1.11 开始默认开启

  • 多调度器

如果默认的调度器不满足要求,还可以部署自定义的调度器。并且,在整个集群中还可以同时运行多个调度器实例,通过 podSpec.schedulerName 来选择使用哪一个调度器(默认使用内置的调度器)。

  • 调度器扩展
    kube-scheduler 还支持使用 --policy-config-file 指定一个调度策略文件来自定义调度策略

  • 其他影响调度的因素

    • 如果Node Condition处于MemoryPressure,则所有BestEffort的新Pod (未指定resources limits和
      requests)不会调度到该Node.上
    • 如果Node Condition处于DiskPressure, 则所有新Pod都不会调度到该Node. 上
    • 为了保证Critical Pods的正常运行,当它们处于异常状态时会自动重新调度。Critical Pods是指
      。annotation 包括s cheduler. alpha. kubernetes. io/critical-pod=’ ’
      。tolerations 包括[{“key” :“Critica LAddonsOnly”, “operator”:“Exists”}]
      。priorityClass 为system-cluster-critical 或者system-node-critical
  • scheduler工作原理

kube-scheduler 调度分为两个阶段,predicate 和 priority
1)predicate:过滤不符合条件的节点
2)priority:优先级排序,选择优先级最高的节点

5.1.3 kube-controller-manager

Controller Manager 由 kube-controller-manager 和 cloud-controller-manager 组成,是 Kubernetes 的大脑,它通过 apiserver 监控整个集群的状态,并确保集群处于预期的工作状态。
在这里插入图片描述

1)必须启动的控制器:18个
EndpointController
ReplicationController
PodGCController
ResourceQuotaController
NamespaceController
ServiceAccountController
GarbageCollectorController
DaemonSetController
JobController
DeploymentController
ReplicaSetController
HPAController
DisruptionController
StatefulSetController
CronJobController
CSRSigningController
CSRApprovingController
TTLController

2)默认启动可选的控制器,可以通过选项设置是否开启
TokenController
NodeController
ServiceController
RouteController
PVBinderController
AttachDetachController

3)默认禁止的可选控制器,可通过选项设置是否开启
BootstrapSignerController
TokenCleanerController

cloud-controller-manager 在 Kubernetes 启用 Cloud Provider 的时候才需要,用来配合云服务提供商的控制,也包括一系列的控制器,如

Node Controller
Route Controller
Service Controller

Metrics

Controller manager metrics 提供了控制器内部逻辑的性能度量,如 Go 语言运行时度量、etcd 请求延时、云服务商 API 请求延时、云存储请求延时等。
Controller manager metrics 默认监听在 kube-controller-manager 的 10252 端口,提供 Prometheus 格式的性能度量数据,可以通过 http://localhost:10252/metrics 来访问。

高可用和高性能

在启动时设置 --leader-elect=true 后,controller manager 会使用多节点选主的方式选择主节点。只有主节点才会调用 StartControllers() 启动所有控制器,而其他从节点则仅执行选主算法。

从 Kubernetes 1.7 开始,所有需要监控资源变化情况的调用均推荐使用 Informer。Informer 提供了基于事件通知的只读缓存机制,可以注册资源变化的回调函数,并可以极大减少 API 的调用。

node驱逐

Node 控制器在节点异常后,会按照默认的速率(–node-eviction-rate=0.1,即每10秒一个节点的速率)进行 Node 的驱逐。Node 控制器按照 Zone 将节点划分为不同的组,再跟进 Zone 的状态进行速率调整:
1)Normal:所有节点都 Ready,默认速率驱逐。
2)PartialDisruption:即超过33% 的节点 NotReady 的状态。当异常节点比例大于 --unhealthy-zone-threshold=0.55 时开始减慢速率:
小集群(即节点数量小于 --large-cluster-size-threshold=50):停止驱逐
大集群,减慢速率为 --secondary-node-eviction-rate=0.01
3)FullDisruption:所有节点都 NotReady,返回使用默认速率驱逐。但当所有 Zone 都处在 FullDisruption 时,停止驱逐。

5.1.4 etcd

Etcd 是 CoreOS 基于 Raft 开发的分布式 key-value 存储,可用于服务发现、共享配置以及一致性保障(如数据库选主、分布式锁等)。etcd作为一个受到ZooKeeper与doozer启发而催生的项目,除了拥有与之类似的功能外,更专注于以下四点。
1)简单:基于HTTP+JSON的API让你用curl就可以轻松使用。
2)安全:可选SSL客户认证机制。
3)快速:每个实例每秒支持一千次写操作。
4)可信:使用Raft算法充分实现了分布式。

etcd主要功能

1)基本的 key-value 存储
2)监听机制
3)key 的过期及续约机制,用于监控和服务发现
4)原子性操作(CAS 和 CAD),用于分布式锁和 leader 选举
tips:
CAS的原理:CAS操作需要输入两个数值,一个旧值(期望操作之前的值)和一个新值,在操作期间先比较旧值有没有变化,如果没有发生变化,才交换新值,发生了变化则不交换

etcd的RAFT(replication and fault-tolerance)一致性算法

RAFT算法把一致性问题分解成了几个子问题:选举方法,日志复制,安全性和失效处理

  • 1)选举算法

初始启动时,节点处于 follower 状态并被设定一个 election timeout,如果在这一时间周期内没有收到来自 leader 的 heartbeat,节点将发起选举:将自己切换为 candidate 之后,向集群中其它 follower 节点发送请求,询问其是否选举自己成为 leader。
当收到来自集群中过半数节点的接受投票后,节点即成为 leader,开始接收保存 client 的数据并向其它的 follower 节点同步日志。如果没有达成一致,则 candidate 随机选择一个等待间隔(150ms ~ 300ms)再次发起投票,得到集群中半数以上 follower 接受的 candidate 将成为 leader
leader 节点依靠定时向 follower 发送 heartbeat 来保持其地位。
任何时候如果其它 follower 在 election timeout 期间都没有收到来自 leader 的 heartbeat,同样会将自己的状态切换为 candidate 并发起选举。每成功选举一次,新 leader 的任期(Term)都会比之前 leader 的任期大 1。

  • 2)日志复制

当前 Leader 收到客户端的日志(事务请求)后先把该日志追加到本地的 Log 中,然后通过 heartbeat 把该 Entry 同步给其他 Follower,Follower 接收到日志后记录日志然后向 Leader 发送 ACK,当 Leader 收到大多数(n/2+1)Follower 的 ACK 信息后将该日志设置为已提交并追加到本地磁盘中,通知客户端并在下个 heartbeat 中 Leader 将通知所有的 Follower 将该日志存储在自己的本地磁盘中。

  • 3)安全性

安全性是用于保证每个节点都执行相同序列的安全机制,如当某个 Follower 在当前 Leader commit Log 时变得不可用了,稍后可能该 Follower 又会被选举为 Leader,这时新 Leader 可能会用新的 Log 覆盖先前已 committed 的 Log,这就是导致节点执行不同序列;Safety 就是用于保证选举出来的 Leader 一定包含先前 committed Log 的机制;

 1.选举安全性(Election Safety):每个任期(Term)只能选举出一个 Leader
2.Leader 完整性(Leader Completeness):指 Leader 日志的完整性,当 Log 在任期 Term1  Commit 后,那么
以后任期 Term2、Term3… 等的 Leader 必须包含该 Log;Raft 在选举阶段就使用 Term 的判断用于保证完整性:当请求
投票的该 Candidate  Term 较大或 Term 相同 Index 更大则投票,否则拒绝该请求。
  • 4)失效处理
  1. Leader 失效:其他没有收到 heartbeat 的节点会发起新的选举,而当 Leader 恢复后由于步进数小会自动成为2. follower(日志也会被新 leader 的日志覆盖)
  2. follower 节点不可用:follower 节点不可用的情况相对容易解决。因为集群中的日志内容始终是从 leader 节点同步的,只要这一节点再次加入集群时重新从 leader 节点处复制日志即可。
  3. 多个 candidate:冲突后 candidate 将随机选择一个等待间隔(150ms ~ 300ms)再次发起投票,得到集群中半数以上 follower 接受的 candidate 将成为 leader

etcd v2与v3

Etcd v2 和 v3 本质上是共享同一套 raft 协议代码的两个独立的应用,接口不一样,存储不一样,数据互相隔离。也就是说如果从 Etcd v2 升级到 Etcd v3,原来 v2 的数据还是只能用 v2 的接口访问,v3 的接口创建的数据也只能访问通过 v3 的接口访问。所以我们按照 v2 和 v3 分别分析。
推荐在 Kubernetes 集群中使用 Etcd v3,v2 版本已在 Kubernetes v1.11 中弃用。

  • Etcd v2 存储,Watch 以及过期机制
    在这里插入图片描述
 Etcd v2 是个纯内存的实现,并未实时将数据写入到磁盘,持久化机制很简单,就是将 store 整合序列化成 json 写入文件。数据在内存中是一个简单的树结构。比如以下数据存储到 Etcd 中的结构就如图所示。
这里有几个影响使用的细节问题:
1.EventHistroy 是有长度限制的,最长 1000。也就是说,如果你的客户端停了许久,然后重新 watch 的时候,可能和该 waitIndex 相关的 event 已经被淘汰了,这种情况下会丢失变更。
2.如果通知 watcher 的时候,出现了阻塞(每个 watcher 的 channel 有 100 个缓冲空间),Etcd 会直接把 watcher 删除,也就是会导致 wait 请求的连接中断,客户端需要重新连接。
3.Etcd store 的每个 node 中都保存了过期时间,通过定时机制进行清理。

从而可以看出,Etcd v2 的一些限制:

1.过期时间只能设置到每个 key 上,如果多个 key 要保证生命周期一致则比较困难。
2.watcher 只能 watch 某一个 key 以及其子节点(通过参数 recursive),不能进行多个 watch。
3.很难通过 watch 机制来实现完整的数据同步(有丢失变更的风险),所以当前的大多数使用方式是通过 watch 得知变更,然后通过 get 重新获取数据,并不完全依赖于 watch 的变更 event。
  • Etcd v3 存储,Watch以及过期机制
    在这里插入图片描述
    Etcd v3 将 watch 和 store 拆开实现:

Etcd v3 store 分为两部分,一部分是内存中的索引,kvindex,是基于 google 开源的一个 golang 的 btree 实现的,另外一部分是后端存储。按照它的设计,backend 可以对接多种存储,当前使用的 boltdb。boltdb 是一个单机的支持事务的 kv 存储,Etcd 的事务是基于 boltdb 的事务实现的。Etcd 在 boltdb 中存储的 key 是 revision,value 是 Etcd 自己的 key-value 组合,也就是说 Etcd 会在 boltdb 中把每个版本都保存下,从而实现了多版本机制。

revision 主要由两部分组成,第一部分 main rev,每次事务进行加一,第二部分 sub rev,同一个事务中的每次操作加一。如上示例,第一次操作的 main rev 是 3,第二次是 4。当然这种机制大家想到的第一个问题就是空间问题,所以 Etcd 提供了命令和设置选项来控制 compact,同时支持 put 操作的参数来精确控制某个 key 的历史版本数。

了解了 Etcd 的磁盘存储,可以看出如果要从 boltdb 中查询数据,必须通过 revision,但客户端都是通过 key 来查询 value,所以 Etcd 的内存 kvindex 保存的就是 key 和 revision 之前的映射关系,用来加速查询。

然后我们再分析下 watch 机制的实现。Etcd v3 的 watch 机制支持 watch 某个固定的 key,也支持 watch 一个范围(可以用于模拟目录的结构的 watch),所以 watchGroup 包含两种 watcher,一种是 key watchers,数据结构是每个 key 对应一组 watcher,另外一种是 range watchers, 数据结构是一个 IntervalTree(不熟悉的参看文文末链接),方便通过区间查找到对应的 watcher。

同时,每个 WatchableStore 包含两种 watcherGroup,一种是 synced,一种是 unsynced,前者表示该 group 的 watcher 数据都已经同步完毕,在等待新的变更,后者表示该 group 的 watcher 数据同步落后于当前最新变更,还在追赶。

当 Etcd 收到客户端的 watch 请求,如果请求携带了 revision 参数,则比较请求的 revision 和 store 当前的 revision,如果大于当前 revision,则放入 synced 组中,否则放入 unsynced 组。同时 Etcd 会启动一个后台的 goroutine 持续同步 unsynced 的 watcher,然后将其迁移到 synced 组。也就是这种机制下,Etcd v3 支持从任意版本开始 watch,没有 v2 的 1000 条历史 event 表限制的问题(当然这是指没有 compact 的情况下)。

另外我们前面提到的,Etcd v2 在通知客户端时,如果网络不好或者客户端读取比较慢,发生了阻塞,则会直接关闭当前连接,客户端需要重新发起请求。Etcd v3 为了解决这个问题,专门维护了一个推送时阻塞的 watcher 队列,在另外的 goroutine 里进行重试。

Etcd v3 对过期机制也做了改进,过期时间设置在 lease 上,然后 key 和 lease 关联。这样可以实现多个 key 关联同一个 lease id,方便设置统一的过期时间,以及实现批量续约。

  • 相比 Etcd v2, Etcd v3 的一些主要变化
1.接口通过 grpc 提供 rpc 接口,放弃了 v2 的 http 接口。优势是长连接效率提升明显,缺点是使用不如以前方便,尤其对不方便维护长连接的场景。
2.废弃了原来的目录结构,变成了纯粹的 kv,用户可以通过前缀匹配模式模拟目录。
3.内存中不再保存 value,同样的内存可以支持存储更多的 key。
4.watch 机制更稳定,基本上可以通过 watch 机制实现数据的完全同步。
5.提供了批量操作以及事务机制,用户可以通过批量事务请求来实现 Etcd v2 的 CAS 机制(批量事务支持 if 条件判断)。

Etcd,Zookeeper,Consul 比较

Etcd 和 Zookeeper 提供的能力非常相似,都是通用的一致性元信息存储,都提供 watch 机制用于变更通知和分发,也都被分布式系统用来作为共享信息存储,在软件生态中所处的位置也几乎是一样的,可以互相替代的。二者除了实现细节,语言,一致性协议上的区别,最大的区别在周边生态圈。Zookeeper 是 apache 下的,用 java 写的,提供 rpc 接口,最早从 hadoop 项目中孵化出来,在分布式系统中得到广泛使用(hadoop, solr, kafka, mesos 等)。Etcd 是 coreos 公司旗下的开源产品,比较新,以其简单好用的 rest 接口以及活跃的社区俘获了一批用户,在新的一些集群中得到使用(比如 kubernetes)。虽然 v3 为了性能也改成二进制 rpc 接口了,但其易用性上比 Zookeeper 还是好一些。

而 Consul 的目标则更为具体一些,Etcd 和 Zookeeper 提供的是分布式一致性存储能力,具体的业务场景需要用户自己实现,比如服务发现,比如配置变更。而 Consul 则以服务发现和配置变更为主要目标,同时附带了 kv 存储。

Etcd 的周边工具

  • Confd

本在分布式系统中,理想情况下是应用程序直接和 Etcd 这样的服务发现 / 配置中心交互,通过监听 Etcd 进行服务发现以及配置变更。但我们还有许多历史遗留的程序,服务发现以及配置大多都是通过变更配置文件进行的。Etcd 自己的定位是通用的 kv 存储,所以并没有像 Consul 那样提供实现配置变更的机制和工具,而 Confd 就是用来实现这个目标的工具。

Confd 通过 watch 机制监听 Etcd 的变更,然后将数据同步到自己的一个本地存储。用户可以通过配置定义自己关注哪些 key 的变更,同时提供一个配置文件模板。Confd 一旦发现数据变更就使用最新数据渲染模板生成配置文件,如果新旧配置文件有变化,则进行替换,同时触发用户提供的 reload 脚本,让应用程序重新加载配置。

Confd 相当于实现了部分 Consul 的 agent 以及 consul-template 的功能,作者是 kubernetes 的 Kelsey Hightower,但大神貌似很忙,没太多时间关注这个项目了,很久没有发布版本,我们着急用,所以 fork 了一份自己更新维护,主要增加了一些新的模板函数以及对 metad 后端的支持。confd

  • Metad

服务注册的实现模式一般分为两种,一种是调度系统代为注册,一种是应用程序自己注册。调度系统代为注册的情况下,应用程序启动后需要有一种机制让应用程序知道『我是谁』,然后发现自己所在的集群以及自己的配置。Metad 提供这样一种机制,客户端请求 Metad 的一个固定的接口 /self,由 Metad 告知应用程序其所属的元信息,简化了客户端的服务发现和配置变更逻辑。

Metad 通过保存一个 ip 到元信息路径的映射关系来做到这一点,当前后端支持 Etcd v3,提供简单好用的 http rest 接口。 它会把 Etcd 的数据通过 watch 机制同步到本地内存中,相当于 Etcd 的一个代理。所以也可以把它当做 Etcd 的代理来使用,适用于不方便使用 Etcd v3 的 rpc 接口或者想降低 Etcd 压力的场景。

Etcd 使用注意事项

  • 1)Etcd cluster 初始化的问题

如果集群第一次初始化启动的时候,有一台节点未启动,通过 v3 的接口访问的时候,会报告 Error: Etcdserver: not capable 错误。这是为兼容性考虑,集群启动时默认的 API 版本是 2.3,只有当集群中的所有节点都加入了,确认所有节点都支持 v3 接口时,才提升集群版本到 v3。这个只有第一次初始化集群的时候会遇到,如果集群已经初始化完毕,再挂掉节点,或者集群关闭重启(关闭重启的时候会从持久化数据中加载集群 API 版本),都不会有影响

  • 2)Etcd 读请求的机制

本v2 quorum=true 的时候,读取是通过 raft 进行的,通过 cli 请求,该参数默认为 true。
v3 --consistency=“l” 的时候(默认)通过 raft 读取,否则读取本地数据。sdk 代码里则是通过是否打开:WithSerializable option 来控制。
一致性读取的情况下,每次读取也需要走一次 raft 协议,能保证一致性,但性能有损失,如果出现网络分区,集群的少数节点是不能提供一致性读取的。但如果不设置该参数,则是直接从本地的 store 里读取,这样就损失了一致性。使用的时候需要注意根据应用场景设置这个参数,在一致性和可用性之间进行取舍。

  • 3)Etcd 的 compact 机制

Etcd 默认不会自动 compact,需要设置启动参数,或者通过命令进行 compact,如果变更频繁建议设置,否则会导致空间和内存的浪费以及错误。Etcd v3 的默认的 backend quota 2GB,如果不 compact,boltdb 文件大小超过这个限制后,就会报错:”Error: etcdserver: mvcc: database space exceeded”,导致数据无法写入。

5.2 node组件
5.2.1 kubelet

每个节点上都运行一个 kubelet 服务进程,默认监听 10250 端口,接收并执行 master 发来的指令,管理 Pod 及 Pod 中的容器。每个 kubelet 进程会在 API Server 上注册节点自身信息,定期向 master 节点汇报节点的资源使用情况,并通过 cAdvisor 监控节点和容器的资源。

节点管理

引用文本节点管理主要是节点自注册和节点状态更新:
Kubelet 可以通过设置启动参数 --register-node 来确定是否向 API Server 注册自己;
如果 Kubelet 没有选择自注册模式,则需要用户自己配置 Node 资源信息,同时需要告知 Kubelet 集群上的 API Server 的位置;
Kubelet 在启动时通过 API Server 注册节点信息,并定时向 API Server 发送节点新消息,API Server 在接收到新消息后,将信息写入 etcd

pod管理

  • 获取pod清单

Kubelet 以 PodSpec 的方式工作。PodSpec 是描述一个 Pod 的 YAML 或 JSON 对象。 kubelet 采用一组通过各种机制提供的 PodSpecs(主要通过 apiserver),并确保这些 PodSpecs 中描述的 Pod 正常健康运行。

向 Kubelet 提供节点上需要运行的 Pod 清单的方法:

  1. 文件:启动参数 --config 指定的配置目录下的文件 (默认 / etc/kubernetes/manifests/)。该文件每 20 秒重新检查一次(可配置)。

2.HTTP endpoint (URL):启动参数 --manifest-url 设置。每 20 秒检查一次这个端点(可配置)。
3.API Server:通过 API Server 监听 etcd 目录,同步 Pod 清单。
4.HTTP server:kubelet 侦听 HTTP 请求,并响应简单的 API 以提交新的 Pod 清单。

  • 2)通过apiserver获取pod清单及创建pod的过程

Kubelet 通过 API Server Client(Kubelet 启动时创建)使用 Watch 加 List 的方式监听 “/registry/nodes/$ 当前节点名” 和 “/registry/pods” 目录,将获取的信息同步到本地缓存中。

Kubelet 监听 etcd,所有针对 Pod 的操作都将会被 Kubelet 监听到。如果发现有新的绑定到本节点的 Pod,则按照 Pod 清单的要求创建该 Pod。

如果发现本地的 Pod 被修改,则 Kubelet 会做出相应的修改,比如删除 Pod 中某个容器时,则通过 Docker Client 删除该容器。 如果发现删除本节点的 Pod,则删除相应的 Pod,并通过 Docker Client 删除 Pod 中的容器。

Kubelet 读取监听到的信息,如果是创建和修改 Pod 任务,则执行如下处理:

1.该 Pod 创建一个数据目录;
2.从 API Server 读取该 Pod 清单;
3.为该 Pod 挂载外部卷;
4.下载 Pod 用到的 Secret;
5.检查已经在节点上运行的 Pod,如果该 Pod 没有容器或 Pause 容器没有启动,则先停止 Pod 里所有容器的进程。如果在 Pod 中有需要删除的容器,则删除这些容器;
6.用 “kubernetes/pause” 镜像为每个 Pod 创建一个容器。Pause 容器用于接管 Pod 中所有其他容器的网络。每创建一个新的 Pod,Kubelet 都会先创建一个 Pause 容器,然后创建其他容器。
为 Pod 中的每个容器做如下处理:
7.为容器计算一个 hash 值,然后用容器的名字去 Docker 查询对应容器的 hash 值。若查找到容器,且两者 hash 值不同,则停止 Docker 中容器的进程,并停止与之关联的 Pause 容器的进程;若两者相同,则不做任何处理;
如果容器被终止了,且容器没有指定的 restartPolicy,则不做任何处理;
调用 Docker Client 下载容器镜像,调用 Docker Client 运行容器。
  • 3)static pod

所有以非 API Server 方式创建的 Pod 都叫 Static Pod。Kubelet 将 Static Pod 的状态汇报给 API Server,API Server 为该 Static Pod 创建一个 Mirror Pod 和其相匹配。Mirror Pod 的状态将真实反映 Static Pod 的状态。当 Static Pod 被删除时,与之相对应的 Mirror Pod 也会被删除。

容器健康检查

  • Pod 通过两类探针检查容器的健康状态

LivenessProbe 探针:用于判断容器是否健康,告诉 Kubelet 一个容器什么时候处于不健康的状态。如果 LivenessProbe 探针探测到容器不健康,则 Kubelet 将删除该容器,并根据容器的重启策略做相应的处理。如果一个容器不包含 LivenessProbe 探针,那么 Kubelet 认为该容器的 LivenessProbe 探针返回的值永远是 “Success”;
ReadinessProbe:用于判断容器是否启动完成且准备接收请求。如果 ReadinessProbe 探针探测到失败,则 Pod 的状态将被修改。Endpoint Controller 将从 Service 的 Endpoint 中删除包含该容器所在 Pod 的 IP 地址的 Endpoint 条目。
Kubelet 定期调用容器中的 LivenessProbe 探针来诊断容器的健康状况。LivenessProbe 包含如下三种实现方式:

ExecAction:在容器内部执行一个命令,如果该命令的退出状态码为 0,则表明容器健康;
TCPSocketAction:通过容器的 IP 地址和端口号执行 TCP 检查,如果端口能被访问,则表明容器健康;
HTTPGetAction:通过容器的 IP 地址和端口号及路径调用 HTTP GET 方法,如果响应的状态码大于等于 200 且小于 400,则认为容器状态健康。

本LivenessProbe 探针包含在 Pod 定义的 spec.containers.{某个容器} 中。

cAdvisor资源监控

Kubernetes 集群中,应用程序的执行情况可以在不同的级别上监测到,这些级别包括:容器、Pod、Service 和整个集群。Heapster 项目为 Kubernetes 提供了一个基本的监控平台,它是集群级别的监控和事件数据集成器 (Aggregator)。Heapster 以 Pod 的方式运行在集群中,Heapster 通过 Kubelet 发现所有运行在集群中的节点,并查看来自这些节点的资源使用情况。Kubelet 通过 cAdvisor 获取其所在节点及容器的数据。Heapster 通过带着关联标签的 Pod 分组这些信息,这些数据将被推到一个可配置的后端,用于存储和可视化展示。支持的后端包括 InfluxDB(使用 Grafana 实现可视化) 和 Google Cloud Monitoring。

cAdvisor 是一个开源的分析容器资源使用率和性能特性的代理工具,已集成到 Kubernetes 代码中。
cAdvisor 自动查找所有在其所在节点上的容器,自动采集 CPU、内存、文件系统和网络使用的统计信息。
cAdvisor 通过它所在节点机的 Root 容器,采集并分析该节点机的全面使用情况。
cAdvisor 通过其所在节点机的 4194 端口暴露一个简单的 UI。

kubelet 驱逐

Kubelet 会监控资源的使用情况,并使用驱逐机制防止计算和存储资源耗尽。在驱逐时,Kubelet 将 Pod 的所有容器停止,并将 PodPhase 设置为 Failed。
Kubelet 定期(housekeeping-interval)检查系统的资源是否达到了预先配置的驱逐阈值,包括:
在这里插入图片描述

这些驱逐阈值可以使用百分比,也可以使用绝对值,如

--eviction-hard=memory.available<500Mi,nodefs.available<1Gi,imagefs.available<100Gi
--eviction-minimum-reclaim="memory.available=0Mi,nodefs.available=500Mi,imagefs.available=2Gi"`
--system-reserved=memory=1.5Gi

引用文本 这些驱逐信号可以分为软驱逐和硬驱逐:

1 .软驱逐(Soft Eviction):配合驱逐宽限期(eviction-soft-grace-period和eviction-max-pod-grace-period)一起使用。系统资源达到软驱逐阈值并在超过宽限期之后才会执行驱逐动作。
2.硬驱逐(Hard Eviction ):系统资源达到硬驱逐阈值时立即执行驱逐动作。

驱逐动作包括回收节点资源和驱逐用户 Pod 两种:

●回收节点资源
   。配置了imagefs阈值时
     ■达到nodefs阈值:删除已停止的Pod
     ■达到imagefs阈值:删除未使用的镜像
。未配置imagefs阈值时
     ■达到nodefs阈值时,按照删除已停止的Pod和删除未使用镜像的顺序清理资源
     ●驱逐用户Pod
。驱逐顺序为: BestEffort、Burstable、 Guaranteed
。配置了imagefs阈值时
    ■达到nodefs阈值,基于nodefs用量驱逐(local volume + logs)
    ■达到imagefs阈值,基于imagefs用量驱逐(容器可写层)
。未配置imagefs阈值时
    ■达到nodefs阈值时,按照总磁盘使用驱逐(local volume + logs +容器可写层)

Container Runtime

容器运行时(Container Runtime)是 Kubernetes 最重要的组件之一,负责真正管理镜像和容器的生命周期。Kubelet 通过 Container Runtime Interface (CRI) 与容器运行时交互,以管理镜像和容器。

kubelet工作原理

 Kubelet 由许多内部组件构成

1.Kubelet API,包括 10250 端口的认证 API、4194 端口的 cAdvisor API、10255 端口的只读 API 以及 10248 端口的健康检查 API
2.syncLoop:从 API 或者 manifest 目录接收 Pod 更新,发送到 podWorkers 处理,大量使用 channel 处理来处理异步请求
3.辅助的 manager,如 cAdvisor、PLEG、Volume Manager 等,处理 syncLoop 以外的其他工作
4.CRI:容器执行引擎接口,负责与 container runtime shim 通信
5.容器执行引擎,如 dockershim、rkt 等(注:rkt 暂未完成 CRI 的迁移)
6.网络插件,目前支持 CNI 和 kubenet

在这里插入图片描述
pod启动流程
在这里插入图片描述
查询node汇总指标

通过 Kubelet 的 10255 端口可以查询 Node 的汇总指标。有两种访问方式

在集群内部可以直接访问 kubelet 的 10255 端口,比如 http://:10255/stats/summary
在集群外部可以借助 kubectl proxy 来访问,比如
kubectl proxy&
curl http://localhost:8001/api/v1/proxy/nodes/:10255/stats/summary
5.2.2 kube-proxy

引用文本每台机器上都运行一个 kube-proxy 服务,它监听 API server 中 service 和 endpoint 的变化情况,并通过 iptables 等来为服务配置负载均衡(仅支持 TCP 和 UDP)。
kube-proxy 可以直接运行在物理机上,也可以以 static pod 或者 daemonset 的方式运行。

  kube-proxy 当前支持以下几种实现:

userspace:最早的负载均衡方案,它在用户空间监听一个端口,所有服务通过 iptables 转发到这个端口,然后在其                          内部负载均衡到实际的 Pod。该方式最主要的问题是效率低,有明显的性能瓶颈。
iptables:目前推荐的方案,完全以 iptables 规则的方式来实现 service 负载均衡。该方式最主要的问题是在服务多的时候产生太多的 iptables 规则,非增量式更新会引入一定的时延,大规模情况下有明显的性能问题
ipvs:为解决 iptables 模式的性能问题,v1.11 新增了 ipvs 模式(v1.8 开始支持测试版,并在 v1.11 GA),采用增量式更新,并可以保证 service 更新期间连接保持不断开
winuserspace:同 userspace,但仅工作在 windows 节点上
注意:使用 ipvs 模式时,需要预先在每台 Node 上加载内核模块 nf_conntrack_ipv4,ip_vs,ip_vs_rr,ip_vs_wrr, ip_vs_sh 等。

kube-proxy工作原理
kube-proxy 监听 API server 中 service 和 endpoint 的变化情况,并通过 userspace、iptables、ipvs 或 winuserspace 等 proxier 来为服务配置负载均衡(仅支持 TCP 和 UDP)。
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值